diff --git a/.config/rollup.config.js b/.config/rollup.config.js index fa1d3471..d0a65ec1 100644 --- a/.config/rollup.config.js +++ b/.config/rollup.config.js @@ -73,4 +73,29 @@ export default [ }), ], }, + { + input: 'src/plugins/jsmind.multiline-text.js', + output: { + name: 'jsMindMultilineText', + file: 'es6/jsmind.multiline-text.js', + format: 'umd', + banner: '/**\n* @license BSD-3-Clause\n* @copyright 2014-2025 hizzgdev@163.com\n*\n* Project Home:\n* https://github.com/hizzgdev/jsmind/\n*/', + sourcemap: true, + globals: { + jsmind: 'jsMind', + }, + exports: 'named', + }, + external: ['jsmind'], + plugins: [ + cleanup({ + comments: 'none', + }), + terser({ + output: { + comments: 'all', + }, + }), + ], + }, ]; diff --git a/docs/en/plugin-multiline-text.md b/docs/en/plugin-multiline-text.md new file mode 100644 index 00000000..985ed798 --- /dev/null +++ b/docs/en/plugin-multiline-text.md @@ -0,0 +1,315 @@ +# Multiline Text Plugin + +The Multiline Text Plugin provides complete multiline text support for jsMind, including display and editing capabilities. + +## Features + +- ✅ **Multiline Text Display**: Display multiline text in nodes +- ✅ **Multiline Text Editing**: Rich text editor using `contentEditable` +- ✅ **Auto Word Wrap**: Automatic line wrapping when text exceeds maximum width +- ✅ **Auto Height Expansion**: Editor height automatically adjusts to content +- ✅ **Keyboard Shortcuts**: + - `Shift + Enter`: Insert line break + - `Enter`: Save changes + - `Esc`: Cancel editing + - `Tab`: Save changes +- ✅ **Text Normalization**: Automatically trim whitespace, normalize line endings, limit consecutive blank lines + +## Installation + +### Method 1: UMD (Browser) + +```html + + +``` + +### Method 2: ES6 Module + +```javascript +import jsMind from './es6/jsmind.js'; +import { createMultilineRender } from './es6/jsmind.multiline-text.js'; +``` + +## Usage + +### Basic Usage + +```javascript +// UMD (Browser) +const options = { + container: 'jsmind_container', + editable: true, + view: { + // Use the custom render function provided by the plugin + custom_node_render: jsMindMultilineText.createMultilineRender({ + text_width: 200, + line_height: '1.5', + }) + }, + plugin: { + multiline_text: { + text_width: 200, + line_height: '1.5', + } + } +}; + +const jm = new jsMind(options); +jm.show(mind_data); +``` + +### ES6 Module Usage + +```javascript +import jsMind from './es6/jsmind.js'; +import { createMultilineRender } from './es6/jsmind.multiline-text.js'; + +const options = { + container: 'jsmind_container', + editable: true, + view: { + custom_node_render: createMultilineRender({ + text_width: 200, + line_height: '1.5', + }) + }, + plugin: { + multiline_text: { + text_width: 200, + line_height: '1.5', + } + } +}; + +const jm = new jsMind(options); +jm.show(mind_data); +``` + +## Configuration Options + +### `createMultilineRender(options)` + +Create a custom node render function for multiline text. + +**Parameters:** + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `text_width` | `number` | `200` | Maximum width for multiline text nodes (px) | +| `line_height` | `string` | `'1.5'` | Line height for text | + +**Returns:** `function(jsMind, HTMLElement, Node): boolean` + +**Example:** + +```javascript +const customRender = createMultilineRender({ + text_width: 250, + line_height: '1.6', +}); +``` + +### Plugin Options + +Configure the plugin behavior in `options.plugin.multiline_text`: + +```javascript +{ + plugin: { + multiline_text: { + text_width: 200, // Maximum width for multiline text + line_height: '1.5', // Line height + } + } +} +``` + +## How It Works + +### 1. Node Rendering + +The plugin provides a custom render function that: + +1. Detects if node topic contains newline characters (`\n`) +2. If yes, applies multiline styles: + - `white-space: pre-wrap` - Preserve line breaks and spaces + - `word-break: break-word` - Break long words + - `max-width: {text_width}px` - Limit maximum width +3. If no, uses default rendering + +### 2. Node Editing + +When editing a node, the plugin: + +1. Creates a `
` editor +2. Sets editor styles to match the node element: + - Width = node width + - Min-height = node height + - Auto-expands height based on content +3. Handles keyboard events: + - `Shift + Enter`: Insert line break + - `Enter`: Save changes + - `Esc`: Cancel editing + - `Tab`: Save changes +4. Auto-expands height on input +5. Saves changes on blur (with 100ms delay) + +### 3. Text Normalization + +When saving, the plugin normalizes the text: + +```javascript +const topic = (editor.textContent || '') + .trim() // Remove leading/trailing whitespace + .replace(/\r\n/g, '\n') // Normalize Windows line endings + .replace(/\r/g, '\n') // Normalize Mac line endings + .replace(/\n{3,}/g, '\n\n'); // Limit consecutive blank lines to 2 +``` + +## Examples + +### Example 1: Basic Multiline Text + +```javascript +const mind = { + meta: { name: 'Demo', author: 'jsMind', version: '1.0' }, + format: 'node_tree', + data: { + id: 'root', + topic: 'Multiline Text\nMind Map', + children: [ + { + id: 'node1', + topic: 'Line 1\nLine 2\nLine 3', + }, + ], + }, +}; + +jm.show(mind); +``` + +### Example 2: Programmatically Add Multiline Node + +```javascript +// Add a multiline child node +jm.add_node( + 'parent_node_id', + 'new_node_id', + 'First line\nSecond line\nThird line' +); +``` + +### Example 3: Update Node to Multiline + +```javascript +// Update existing node to multiline text +jm.update_node('node_id', 'New line 1\nNew line 2'); +``` + +## Editor Behavior + +### Auto Height Expansion + +The editor automatically expands its height based on content: + +```javascript +const autoExpand = () => { + editor.style.height = 'auto'; + editor.style.height = editor.scrollHeight + 'px'; +}; +$.on(editor, 'input', autoExpand); +setTimeout(autoExpand, 0); // Initial expand +``` + +**Behavior:** +- Initial height = node height +- Expands when content exceeds initial height +- Shrinks when content is deleted (but not below initial height) +- No scrollbar (overflow: hidden) + +### Editor Styles + +```css +.jsmind-multiline-editor { + width: {node.clientWidth}px; + min-height: {node.clientHeight}px; + line-height: {opts.line_height}; + border: none; + outline: none; + white-space: pre-wrap; + word-break: break-word; + box-sizing: border-box; + overflow: hidden; +} +``` + +## API Reference + +### `createMultilineRender(options)` + +Create a custom node render function. + +**Type:** +```typescript +function createMultilineRender(options?: { + text_width?: number; + line_height?: string; +}): (jm: jsMind, element: HTMLElement, node: Node) => boolean +``` + +**Example:** +```javascript +const render = createMultilineRender({ + text_width: 250, + line_height: '1.6', +}); +``` + +## Browser Compatibility + +- ✅ Chrome 60+ +- ✅ Firefox 55+ +- ✅ Safari 11+ +- ✅ Edge 79+ + +**Note:** Requires `contenteditable="plaintext-only"` support. + +## Troubleshooting + +### Issue: Plugin not working + +**Solution:** +1. Make sure the plugin script is loaded after jsMind core +2. Check that `custom_node_render` is set in options +3. Check that `plugin.multiline_text` is configured +4. Open browser console and look for `[Multiline Plugin] Initializing...` + +### Issue: Editor not showing + +**Solution:** +1. Check that the node is editable (`options.editable = true`) +2. Check browser console for errors +3. Verify that `contenteditable` is supported in your browser + +### Issue: Height not expanding + +**Solution:** +1. Check that `overflow: hidden` is set on the editor +2. Verify that the `input` event is firing +3. Check browser console for JavaScript errors + +## License + +BSD-3-Clause + +## Author + +UmbraCi + +## Links + +- [GitHub Repository](https://github.com/hizzgdev/jsmind/) +- [Documentation](https://hizzgdev.github.io/jsmind/) + diff --git a/docs/zh/plugin-multiline-text.md b/docs/zh/plugin-multiline-text.md new file mode 100644 index 00000000..1730fa04 --- /dev/null +++ b/docs/zh/plugin-multiline-text.md @@ -0,0 +1,315 @@ +# 多行文本插件 + +多行文本插件为 jsMind 提供了完整的多行文本支持,包括显示和编辑功能。 + +## 功能特性 + +- ✅ **多行文本显示**:在节点中显示多行文本 +- ✅ **多行文本编辑**:使用 `contentEditable` 实现的富文本编辑器 +- ✅ **自动换行**:文本超过最大宽度时自动换行 +- ✅ **自动扩展高度**:编辑器高度随内容自动调整 +- ✅ **键盘快捷键**: + - `Shift + Enter`:插入换行符 + - `Enter`:保存更改 + - `Esc`:取消编辑 + - `Tab`:保存更改 +- ✅ **文本规范化**:自动去除首尾空白、统一换行符、限制连续空行 + +## 安装 + +### 方式 1:UMD(浏览器) + +```html + + +``` + +### 方式 2:ES6 模块 + +```javascript +import jsMind from './es6/jsmind.js'; +import { createMultilineRender } from './es6/jsmind.multiline-text.js'; +``` + +## 使用方法 + +### 基本用法 + +```javascript +// UMD(浏览器) +const options = { + container: 'jsmind_container', + editable: true, + view: { + // 使用插件提供的自定义渲染函数 + custom_node_render: jsMindMultilineText.createMultilineRender({ + text_width: 200, + line_height: '1.5', + }) + }, + plugin: { + multiline_text: { + text_width: 200, + line_height: '1.5', + } + } +}; + +const jm = new jsMind(options); +jm.show(mind_data); +``` + +### ES6 模块用法 + +```javascript +import jsMind from './es6/jsmind.js'; +import { createMultilineRender } from './es6/jsmind.multiline-text.js'; + +const options = { + container: 'jsmind_container', + editable: true, + view: { + custom_node_render: createMultilineRender({ + text_width: 200, + line_height: '1.5', + }) + }, + plugin: { + multiline_text: { + text_width: 200, + line_height: '1.5', + } + } +}; + +const jm = new jsMind(options); +jm.show(mind_data); +``` + +## 配置选项 + +### `createMultilineRender(options)` + +创建多行文本的自定义节点渲染函数。 + +**参数:** + +| 选项 | 类型 | 默认值 | 描述 | +|------|------|--------|------| +| `text_width` | `number` | `200` | 多行文本节点的最大宽度(像素) | +| `line_height` | `string` | `'1.5'` | 文本行高 | + +**返回值:** `function(jsMind, HTMLElement, Node): boolean` + +**示例:** + +```javascript +const customRender = createMultilineRender({ + text_width: 250, + line_height: '1.6', +}); +``` + +### 插件选项 + +在 `options.plugin.multiline_text` 中配置插件行为: + +```javascript +{ + plugin: { + multiline_text: { + text_width: 200, // 多行文本最大宽度 + line_height: '1.5', // 行高 + } + } +} +``` + +## 工作原理 + +### 1. 节点渲染 + +插件提供的自定义渲染函数: + +1. 检测节点主题是否包含换行符(`\n`) +2. 如果包含,应用多行样式: + - `white-space: pre-wrap` - 保留换行和空格 + - `word-break: break-word` - 断开长单词 + - `max-width: {text_width}px` - 限制最大宽度 +3. 如果不包含,使用默认渲染 + +### 2. 节点编辑 + +编辑节点时,插件会: + +1. 创建 `
` 编辑器 +2. 设置编辑器样式以匹配节点元素: + - 宽度 = 节点宽度 + - 最小高度 = 节点高度 + - 根据内容自动扩展高度 +3. 处理键盘事件: + - `Shift + Enter`:插入换行符 + - `Enter`:保存更改 + - `Esc`:取消编辑 + - `Tab`:保存更改 +4. 输入时自动扩展高度 +5. 失焦时保存更改(延迟 100ms) + +### 3. 文本规范化 + +保存时,插件会规范化文本: + +```javascript +const topic = (editor.textContent || '') + .trim() // 去除首尾空白 + .replace(/\r\n/g, '\n') // 统一 Windows 换行符 + .replace(/\r/g, '\n') // 统一 Mac 换行符 + .replace(/\n{3,}/g, '\n\n'); // 限制连续空行最多 2 个 +``` + +## 示例 + +### 示例 1:基本多行文本 + +```javascript +const mind = { + meta: { name: 'Demo', author: 'jsMind', version: '1.0' }, + format: 'node_tree', + data: { + id: 'root', + topic: '多行文本\n思维导图', + children: [ + { + id: 'node1', + topic: '第一行\n第二行\n第三行', + }, + ], + }, +}; + +jm.show(mind); +``` + +### 示例 2:编程方式添加多行节点 + +```javascript +// 添加多行子节点 +jm.add_node( + 'parent_node_id', + 'new_node_id', + '第一行\n第二行\n第三行' +); +``` + +### 示例 3:更新节点为多行文本 + +```javascript +// 更新现有节点为多行文本 +jm.update_node('node_id', '新的第一行\n新的第二行'); +``` + +## 编辑器行为 + +### 自动扩展高度 + +编辑器根据内容自动扩展高度: + +```javascript +const autoExpand = () => { + editor.style.height = 'auto'; + editor.style.height = editor.scrollHeight + 'px'; +}; +$.on(editor, 'input', autoExpand); +setTimeout(autoExpand, 0); // 初始扩展 +``` + +**行为:** +- 初始高度 = 节点高度 +- 内容超过初始高度时扩展 +- 删除内容时收缩(但不会小于初始高度) +- 无滚动条(overflow: hidden) + +### 编辑器样式 + +```css +.jsmind-multiline-editor { + width: {node.clientWidth}px; + min-height: {node.clientHeight}px; + line-height: {opts.line_height}; + border: none; + outline: none; + white-space: pre-wrap; + word-break: break-word; + box-sizing: border-box; + overflow: hidden; +} +``` + +## API 参考 + +### `createMultilineRender(options)` + +创建自定义节点渲染函数。 + +**类型:** +```typescript +function createMultilineRender(options?: { + text_width?: number; + line_height?: string; +}): (jm: jsMind, element: HTMLElement, node: Node) => boolean +``` + +**示例:** +```javascript +const render = createMultilineRender({ + text_width: 250, + line_height: '1.6', +}); +``` + +## 浏览器兼容性 + +- ✅ Chrome 60+ +- ✅ Firefox 55+ +- ✅ Safari 11+ +- ✅ Edge 79+ + +**注意:** 需要支持 `contenteditable="plaintext-only"`。 + +## 故障排除 + +### 问题:插件不工作 + +**解决方案:** +1. 确保插件脚本在 jsMind 核心之后加载 +2. 检查 `custom_node_render` 是否在 options 中设置 +3. 检查 `plugin.multiline_text` 是否配置 +4. 打开浏览器控制台查看是否有 `[Multiline Plugin] Initializing...` + +### 问题:编辑器不显示 + +**解决方案:** +1. 检查节点是否可编辑(`options.editable = true`) +2. 检查浏览器控制台是否有错误 +3. 验证浏览器是否支持 `contenteditable` + +### 问题:高度不扩展 + +**解决方案:** +1. 检查编辑器是否设置了 `overflow: hidden` +2. 验证 `input` 事件是否触发 +3. 检查浏览器控制台是否有 JavaScript 错误 + +## 许可证 + +BSD-3-Clause + +## 作者 + +UmbraCi + +## 链接 + +- [GitHub 仓库](https://github.com/hizzgdev/jsmind/) +- [文档](https://hizzgdev.github.io/jsmind/) + diff --git a/example/demo.html b/example/demo.html index 077f3c89..91ddc35b 100644 --- a/example/demo.html +++ b/example/demo.html @@ -22,6 +22,7 @@
+