Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .config/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,29 @@ export default [
}),
],
},
{
input: 'src/plugins/multiline-text/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 [email protected]\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',
},
}),
],
},
];
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ es6/*.js
es6/*.js.map
types/generated/

.augment/
53 changes: 46 additions & 7 deletions example/demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>jsMind</title>
<link type="text/css" rel="stylesheet" href="../style/jsmind.css" />
<!-- Multiline text plugin CSS will be automatically injected by the plugin -->
<style type="text/css">
#jsmind_container {
width: 800px;
Expand All @@ -19,9 +20,12 @@
<input type="file" onchange="load_file(this);" />
<button onclick="save_nodetree();">nodetree</button>
<button onclick="replay();">replay</button>
<button onclick="add_multiline_node();">Add Multiline Node</button>
<button onclick="add_long_text_node();">Add Long Text Node</button>
<div id="jsmind_container"></div>
<script type="text/javascript" src="../es6/jsmind.js"></script>
<script type="text/javascript" src="../es6/jsmind.draggable-node.js"></script>
<script type="text/javascript" src="../es6/jsmind.multiline-text.js"></script>
<script type="text/javascript" src="../features/jsmind.shell.js"></script>
<script type="text/javascript">
var _jm = null;
Expand All @@ -34,18 +38,26 @@
},
format: 'node_array',
data: [
{ id: 'root', isroot: true, topic: 'jsMind' },
{ id: 'root', isroot: true, topic: 'jsMind\nMultiline Support Test' },

{ id: 'sub1', parentid: 'root', topic: 'sub1' },
{ id: 'sub1', parentid: 'root', topic: 'sub1\nThis is a\nmultiline node' },
{ id: 'sub11', parentid: 'sub1', topic: 'sub11' },
{ id: 'sub12', parentid: 'sub1', topic: 'sub12' },
{ id: 'sub13', parentid: 'sub1', topic: 'sub13' },
{ id: 'sub12', parentid: 'sub1', topic: 'sub12\nSupport line breaks' },
{
id: 'sub13',
parentid: 'sub1',
topic: 'Long text test: This is a very long text used to test whether the automatic line wrapping function works properly, including mixed content test',
},

{ id: 'sub2', parentid: 'root', topic: 'sub2' },
{ id: 'sub21', parentid: 'sub2', topic: 'sub21' },
{ id: 'sub2', parentid: 'root', topic: 'sub2\nFunction Test' },
{
id: 'sub21',
parentid: 'sub2',
topic: 'sub21\nEdit Test\nMultiline Editing',
},
{ id: 'sub22', parentid: 'sub2', topic: 'sub22' },

{ id: 'sub3', parentid: 'root', topic: 'sub3' },
{ id: 'sub3', parentid: 'root', topic: 'sub3\nSize Adaptive Test' },
],
};
var options = {
Expand All @@ -68,6 +80,21 @@
},
};
_jm = new jsMind(options);

// Load multiline text plugin
// The plugin is automatically registered when the script is loaded
// We just need to initialize it manually
if (typeof jsMindMultilineText !== 'undefined') {
var multilinePlugin = new jsMindMultilineText.MultilineText(_jm, {
enable_multiline: true,
textAutoWrapWidth: 500,
support_html: true
});
multilinePlugin.init();
} else {
console.error('Multiline text plugin not loaded');
}

_jm.show(mind);
// jm.set_readonly(true);
// var mind_data = jm.get_data();
Expand Down Expand Up @@ -101,6 +128,18 @@
}
}

function add_multiline_node() {
var nodeId = 'node_' + Date.now();
var topic = 'New Multiline Node\nSecond line\nThird line\nFourth line with more content';
_jm.add_node('root', nodeId, topic);
}

function add_long_text_node() {
var nodeId = 'node_' + Date.now();
var topic = 'This is a very long text node that demonstrates the automatic text wrapping feature of the multiline text plugin. It should wrap nicely within the specified width and show how the plugin handles long content automatically.';
_jm.add_node('root', nodeId, topic);
}

load_jsmind();
</script>
</body>
Expand Down
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@
"require": "./es6/jsmind.screenshot.js",
"types": "./types/generated/plugins/jsmind.screenshot.d.ts"
},
"./style/jsmind.css": "./style/jsmind.css"
"./multiline-text": {
"import": "./es6/jsmind.multiline-text.js",
"require": "./es6/jsmind.multiline-text.js",
"types": "./types/generated/plugins/jsmind.multiline-text.d.ts"
},
"./style/jsmind.css": "./style/jsmind.css",
"./style/jsmind.multiline-text.css": "./src/plugins/multiline-text/jsmind.multiline-text.css"
},
"directories": {
"doc": "docs",
Expand Down
10 changes: 10 additions & 0 deletions src/jsmind.util.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,5 +107,15 @@ export const util = {
}
return s.replace(/\s*/, '').length == 0;
},

html_escape: function (text) {
if (!text) return '';
return text
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#x27;');
},
},
};
167 changes: 167 additions & 0 deletions src/plugins/multiline-text/jsmind.multiline-text.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/**
* @license BSD
* @copyright 2014-2025 [email protected]
*
* Project Home:
* https://github.com/hizzgdev/jsmind/
*/

/* Multiline text plugin styles */

/* Base editor styles */
.jsmind-editor {
border: 2px solid #4caf50;
border-radius: 4px;
padding: 4px;
margin: 0;
outline: none;
background: #fff;
font-family: inherit;
font-size: inherit;
line-height: inherit;
color: #000 !important; /* Ensure editor text is always black */
}

/* Multiline editor using contenteditable div */
.jsmind-multiline-editor {
min-height: 20px;
word-wrap: break-word;
overflow-wrap: break-word;
white-space: pre-wrap;
max-height: 200px;
overflow-y: auto;
}

/* Input editor for single line text */
.jsmind-input-editor {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-height: 20px;
border: none;
outline: none;
}

/* Rich text editor (legacy support) */
.jsmind-rich-editor {
min-height: 20px;
word-wrap: break-word;
overflow-wrap: break-word;
white-space: normal;
max-height: 200px;
overflow-y: auto;
}

/* Legacy textarea support (deprecated - will be removed in future versions) */
.jsmind-textarea-editor {
resize: vertical;
min-height: 40px;
font-family: inherit;
}

/* Multiline node styles */
jmnode.multiline {
white-space: pre-wrap;
word-wrap: break-word;
overflow-wrap: break-word;
max-width: 300px; /* Default value, will be overridden by plugin */
}

/* Rich text node styles */
jmnode.rich-text {
white-space: normal;
word-wrap: break-word;
overflow-wrap: break-word;
max-width: 300px; /* Default value, will be overridden by plugin */
}

/* Rich text formatting support */
jmnode.rich-text b,
jmnode.rich-text strong {
font-weight: bold;
}

jmnode.rich-text i,
jmnode.rich-text em {
font-style: italic;
}

jmnode.rich-text u {
text-decoration: underline;
}

jmnode.rich-text ul,
jmnode.rich-text ol {
margin: 4px 0;
padding-left: 20px;
}

jmnode.rich-text li {
margin: 2px 0;
}

/* Multiline text specific styles */
jmnode.multiline br {
line-height: inherit;
}

/* Ensure proper line height for multiline content */
jmnode.multiline {
line-height: 1.4;
}

/* Handle overflow for very long lines in multiline mode */
jmnode.multiline {
overflow-wrap: anywhere;
word-break: break-word;
}

/* Responsive behavior for smaller screens */
@media (max-width: 768px) {
jmnode.multiline,
jmnode.rich-text {
max-width: 250px;
}
}

@media (max-width: 480px) {
jmnode.multiline,
jmnode.rich-text {
max-width: 200px;
}
}

/* High contrast mode support */
@media (prefers-contrast: high) {
.jsmind-editor {
border-color: #000;
border-width: 3px;
}
}

/* Reduced motion support */
@media (prefers-reduced-motion: reduce) {
.jsmind-editor {
transition: none;
}
}

/* Focus styles for accessibility */
.jsmind-editor:focus {
border-color: #2196f3;
box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.2);
}

/* Print styles */
@media print {
.jsmind-editor {
border: 1px solid #000;
background: transparent;
}

jmnode.multiline,
jmnode.rich-text {
max-width: none;
page-break-inside: avoid;
}
}
Loading
Loading