Skip to content

Commit 6b0f2ed

Browse files
committed
feat: add multiline text plugin with auto-expand editor
Features: - Multiline text display with word wrapping - Contenteditable-based editor for multiline editing - Auto-expand editor height based on content - Keyboard shortcuts (Shift+Enter for newline, Enter to save, Esc to cancel) - Text normalization (trim whitespace, normalize line endings) Implementation: - Created src/plugins/jsmind.multiline-text.js plugin - Added createMultilineRender() function for custom node rendering - Overrode edit_node_begin/end for contenteditable editor - Editor matches node dimensions with no border - Auto-expands height on input without scrollbar Configuration: - text_width: Maximum width for multiline text nodes (default: 200) - line_height: Line height for text (default: '1.5') Documentation: - Added English documentation (docs/en/plugin-multiline-text.md) - Added Chinese documentation (docs/zh/plugin-multiline-text.md) - Integrated plugin into example/demo.html Build: - Added plugin to rollup.config.js - Fixed external dependency to prevent bundling jsMind core - Generated UMD build (es6/jsmind.multiline-text.js) Breaking Changes: - Removed standalone multiline-text-demo.html (integrated into demo.html) - Removed .d.ts file (using JSDoc instead)
1 parent 5bf5202 commit 6b0f2ed

File tree

5 files changed

+971
-4
lines changed

5 files changed

+971
-4
lines changed

.config/rollup.config.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,29 @@ export default [
7373
}),
7474
],
7575
},
76+
{
77+
input: 'src/plugins/jsmind.multiline-text.js',
78+
output: {
79+
name: 'jsMindMultilineText',
80+
file: 'es6/jsmind.multiline-text.js',
81+
format: 'umd',
82+
banner: '/**\n* @license BSD-3-Clause\n* @copyright 2014-2025 [email protected]\n*\n* Project Home:\n* https://github.com/hizzgdev/jsmind/\n*/',
83+
sourcemap: true,
84+
globals: {
85+
jsmind: 'jsMind',
86+
},
87+
exports: 'named',
88+
},
89+
external: ['jsmind'],
90+
plugins: [
91+
cleanup({
92+
comments: 'none',
93+
}),
94+
terser({
95+
output: {
96+
comments: 'all',
97+
},
98+
}),
99+
],
100+
},
76101
];

docs/en/plugin-multiline-text.md

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
# Multiline Text Plugin
2+
3+
The Multiline Text Plugin provides complete multiline text support for jsMind, including display and editing capabilities.
4+
5+
## Features
6+
7+
-**Multiline Text Display**: Display multiline text in nodes
8+
-**Multiline Text Editing**: Rich text editor using `contentEditable`
9+
-**Auto Word Wrap**: Automatic line wrapping when text exceeds maximum width
10+
-**Auto Height Expansion**: Editor height automatically adjusts to content
11+
-**Keyboard Shortcuts**:
12+
- `Shift + Enter`: Insert line break
13+
- `Enter`: Save changes
14+
- `Esc`: Cancel editing
15+
- `Tab`: Save changes
16+
-**Text Normalization**: Automatically trim whitespace, normalize line endings, limit consecutive blank lines
17+
18+
## Installation
19+
20+
### Method 1: UMD (Browser)
21+
22+
```html
23+
<script src="es6/jsmind.js"></script>
24+
<script src="es6/jsmind.multiline-text.js"></script>
25+
```
26+
27+
### Method 2: ES6 Module
28+
29+
```javascript
30+
import jsMind from './es6/jsmind.js';
31+
import { createMultilineRender } from './es6/jsmind.multiline-text.js';
32+
```
33+
34+
## Usage
35+
36+
### Basic Usage
37+
38+
```javascript
39+
// UMD (Browser)
40+
const options = {
41+
container: 'jsmind_container',
42+
editable: true,
43+
view: {
44+
// Use the custom render function provided by the plugin
45+
custom_node_render: jsMindMultilineText.createMultilineRender({
46+
text_width: 200,
47+
line_height: '1.5',
48+
})
49+
},
50+
plugin: {
51+
multiline_text: {
52+
text_width: 200,
53+
line_height: '1.5',
54+
}
55+
}
56+
};
57+
58+
const jm = new jsMind(options);
59+
jm.show(mind_data);
60+
```
61+
62+
### ES6 Module Usage
63+
64+
```javascript
65+
import jsMind from './es6/jsmind.js';
66+
import { createMultilineRender } from './es6/jsmind.multiline-text.js';
67+
68+
const options = {
69+
container: 'jsmind_container',
70+
editable: true,
71+
view: {
72+
custom_node_render: createMultilineRender({
73+
text_width: 200,
74+
line_height: '1.5',
75+
})
76+
},
77+
plugin: {
78+
multiline_text: {
79+
text_width: 200,
80+
line_height: '1.5',
81+
}
82+
}
83+
};
84+
85+
const jm = new jsMind(options);
86+
jm.show(mind_data);
87+
```
88+
89+
## Configuration Options
90+
91+
### `createMultilineRender(options)`
92+
93+
Create a custom node render function for multiline text.
94+
95+
**Parameters:**
96+
97+
| Option | Type | Default | Description |
98+
|--------|------|---------|-------------|
99+
| `text_width` | `number` | `200` | Maximum width for multiline text nodes (px) |
100+
| `line_height` | `string` | `'1.5'` | Line height for text |
101+
102+
**Returns:** `function(jsMind, HTMLElement, Node): boolean`
103+
104+
**Example:**
105+
106+
```javascript
107+
const customRender = createMultilineRender({
108+
text_width: 250,
109+
line_height: '1.6',
110+
});
111+
```
112+
113+
### Plugin Options
114+
115+
Configure the plugin behavior in `options.plugin.multiline_text`:
116+
117+
```javascript
118+
{
119+
plugin: {
120+
multiline_text: {
121+
text_width: 200, // Maximum width for multiline text
122+
line_height: '1.5', // Line height
123+
}
124+
}
125+
}
126+
```
127+
128+
## How It Works
129+
130+
### 1. Node Rendering
131+
132+
The plugin provides a custom render function that:
133+
134+
1. Detects if node topic contains newline characters (`\n`)
135+
2. If yes, applies multiline styles:
136+
- `white-space: pre-wrap` - Preserve line breaks and spaces
137+
- `word-break: break-word` - Break long words
138+
- `max-width: {text_width}px` - Limit maximum width
139+
3. If no, uses default rendering
140+
141+
### 2. Node Editing
142+
143+
When editing a node, the plugin:
144+
145+
1. Creates a `<div contenteditable="plaintext-only">` editor
146+
2. Sets editor styles to match the node element:
147+
- Width = node width
148+
- Min-height = node height
149+
- Auto-expands height based on content
150+
3. Handles keyboard events:
151+
- `Shift + Enter`: Insert line break
152+
- `Enter`: Save changes
153+
- `Esc`: Cancel editing
154+
- `Tab`: Save changes
155+
4. Auto-expands height on input
156+
5. Saves changes on blur (with 100ms delay)
157+
158+
### 3. Text Normalization
159+
160+
When saving, the plugin normalizes the text:
161+
162+
```javascript
163+
const topic = (editor.textContent || '')
164+
.trim() // Remove leading/trailing whitespace
165+
.replace(/\r\n/g, '\n') // Normalize Windows line endings
166+
.replace(/\r/g, '\n') // Normalize Mac line endings
167+
.replace(/\n{3,}/g, '\n\n'); // Limit consecutive blank lines to 2
168+
```
169+
170+
## Examples
171+
172+
### Example 1: Basic Multiline Text
173+
174+
```javascript
175+
const mind = {
176+
meta: { name: 'Demo', author: 'jsMind', version: '1.0' },
177+
format: 'node_tree',
178+
data: {
179+
id: 'root',
180+
topic: 'Multiline Text\nMind Map',
181+
children: [
182+
{
183+
id: 'node1',
184+
topic: 'Line 1\nLine 2\nLine 3',
185+
},
186+
],
187+
},
188+
};
189+
190+
jm.show(mind);
191+
```
192+
193+
### Example 2: Programmatically Add Multiline Node
194+
195+
```javascript
196+
// Add a multiline child node
197+
jm.add_node(
198+
'parent_node_id',
199+
'new_node_id',
200+
'First line\nSecond line\nThird line'
201+
);
202+
```
203+
204+
### Example 3: Update Node to Multiline
205+
206+
```javascript
207+
// Update existing node to multiline text
208+
jm.update_node('node_id', 'New line 1\nNew line 2');
209+
```
210+
211+
## Editor Behavior
212+
213+
### Auto Height Expansion
214+
215+
The editor automatically expands its height based on content:
216+
217+
```javascript
218+
const autoExpand = () => {
219+
editor.style.height = 'auto';
220+
editor.style.height = editor.scrollHeight + 'px';
221+
};
222+
$.on(editor, 'input', autoExpand);
223+
setTimeout(autoExpand, 0); // Initial expand
224+
```
225+
226+
**Behavior:**
227+
- Initial height = node height
228+
- Expands when content exceeds initial height
229+
- Shrinks when content is deleted (but not below initial height)
230+
- No scrollbar (overflow: hidden)
231+
232+
### Editor Styles
233+
234+
```css
235+
.jsmind-multiline-editor {
236+
width: {node.clientWidth}px;
237+
min-height: {node.clientHeight}px;
238+
line-height: {opts.line_height};
239+
border: none;
240+
outline: none;
241+
white-space: pre-wrap;
242+
word-break: break-word;
243+
box-sizing: border-box;
244+
overflow: hidden;
245+
}
246+
```
247+
248+
## API Reference
249+
250+
### `createMultilineRender(options)`
251+
252+
Create a custom node render function.
253+
254+
**Type:**
255+
```typescript
256+
function createMultilineRender(options?: {
257+
text_width?: number;
258+
line_height?: string;
259+
}): (jm: jsMind, element: HTMLElement, node: Node) => boolean
260+
```
261+
262+
**Example:**
263+
```javascript
264+
const render = createMultilineRender({
265+
text_width: 250,
266+
line_height: '1.6',
267+
});
268+
```
269+
270+
## Browser Compatibility
271+
272+
- ✅ Chrome 60+
273+
- ✅ Firefox 55+
274+
- ✅ Safari 11+
275+
- ✅ Edge 79+
276+
277+
**Note:** Requires `contenteditable="plaintext-only"` support.
278+
279+
## Troubleshooting
280+
281+
### Issue: Plugin not working
282+
283+
**Solution:**
284+
1. Make sure the plugin script is loaded after jsMind core
285+
2. Check that `custom_node_render` is set in options
286+
3. Check that `plugin.multiline_text` is configured
287+
4. Open browser console and look for `[Multiline Plugin] Initializing...`
288+
289+
### Issue: Editor not showing
290+
291+
**Solution:**
292+
1. Check that the node is editable (`options.editable = true`)
293+
2. Check browser console for errors
294+
3. Verify that `contenteditable` is supported in your browser
295+
296+
### Issue: Height not expanding
297+
298+
**Solution:**
299+
1. Check that `overflow: hidden` is set on the editor
300+
2. Verify that the `input` event is firing
301+
3. Check browser console for JavaScript errors
302+
303+
## License
304+
305+
BSD-3-Clause
306+
307+
## Author
308+
309+
UmbraCi
310+
311+
## Links
312+
313+
- [GitHub Repository](https://github.com/hizzgdev/jsmind/)
314+
- [Documentation](https://hizzgdev.github.io/jsmind/)
315+

0 commit comments

Comments
 (0)