@umbraci/jsmind 0.10.12 → 0.10.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/LICENSE +24 -24
  2. package/README.md +116 -116
  3. package/dist/jsmind.draggable-node.js +1 -1
  4. package/dist/jsmind.draggable-node.js.map +1 -1
  5. package/dist/jsmind.history.js +1 -1
  6. package/dist/jsmind.history.js.map +1 -1
  7. package/dist/jsmind.js +1 -1
  8. package/dist/jsmind.js.map +1 -1
  9. package/dist/jsmind.multiline-text.js +1 -1
  10. package/dist/jsmind.multiline-text.js.map +1 -1
  11. package/dist/jsmind.screenshot.js +1 -1
  12. package/dist/jsmind.screenshot.js.map +1 -1
  13. package/es/jsmind.draggable-node.js +1 -1
  14. package/es/jsmind.draggable-node.js.map +1 -1
  15. package/es/jsmind.history.js +1 -1
  16. package/es/jsmind.history.js.map +1 -1
  17. package/es/jsmind.js +1 -1
  18. package/es/jsmind.js.map +1 -1
  19. package/es/jsmind.multiline-text.js +1 -1
  20. package/es/jsmind.multiline-text.js.map +1 -1
  21. package/es/jsmind.screenshot.js +1 -1
  22. package/es/jsmind.screenshot.js.map +1 -1
  23. package/lib/jsmind.draggable-node.js +1 -1
  24. package/lib/jsmind.draggable-node.js.map +1 -1
  25. package/lib/jsmind.history.js +1 -1
  26. package/lib/jsmind.history.js.map +1 -1
  27. package/lib/jsmind.js +1 -1
  28. package/lib/jsmind.js.map +1 -1
  29. package/lib/jsmind.multiline-text.js +1 -1
  30. package/lib/jsmind.multiline-text.js.map +1 -1
  31. package/lib/jsmind.screenshot.js +1 -1
  32. package/lib/jsmind.screenshot.js.map +1 -1
  33. package/package.json +111 -111
  34. package/style/jsmind.css +408 -408
  35. package/types/generated/jsmind.option.d.ts +1 -0
  36. package/types/tsconfig.declaration.json +19 -19
  37. package/dist/jsmind.copy-paste.js +0 -9
  38. package/dist/jsmind.copy-paste.js.map +0 -1
  39. package/es/jsmind.copy-paste.js +0 -9
  40. package/es/jsmind.copy-paste.js.map +0 -1
  41. package/lib/jsmind.copy-paste.js +0 -9
  42. package/lib/jsmind.copy-paste.js.map +0 -1
@@ -5,5 +5,5 @@
5
5
  * Project Home:
6
6
  * https://github.com/hizzgdev/jsmind/
7
7
  */
8
- "use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}Object.defineProperty(exports,"__esModule",{value:!0});var t=e(require("@umbraci/jsmind"));if(!t.default)throw new Error("jsMind is not defined");const n=t.default.$,i={text_width:200,line_height:"1.5"};function o(e={}){const t=Object.assign({},i,e);return function(e,n,i){return!(!i.topic||!i.topic.includes("\n"))&&(n.style.whiteSpace="pre-wrap",n.style.wordBreak="break-word",n.style.maxWidth=t.text_width+"px",n.textContent=i.topic,!0)}}function d(e,o){console.log("[Multiline Plugin] Initializing...",o);const d=Object.assign({},i,o),l=e.view;let r=null,a=null;function s(){if(!r||!a)return;const e=r._data.view.element;a.parentNode&&a.parentNode.removeChild(a),e.style.zIndex="auto",r=null,l.editing_node=null,a=null}l.opts.custom_node_render&&(l.render_node=l._custom_node_render.bind(l),console.log("[Multiline Plugin] Re-bound view.render_node")),e.mind&&e.mind.root&&(!function(e){const t=e.view,n=e.mind;if(!n||!n.root)return;const i=[];for(const e in n.nodes){const t=n.nodes[e];t._data&&t._data.view&&t._data.view.element&&i.push(t)}for(const e of i){const n=e._data.view.element;t.render_node(n,e)}for(const t of i)if(e.layout.is_visible(t)){const e=t._data.view.element;t._data.view.width=e.clientWidth,t._data.view.height=e.clientHeight}e.layout.layout(),e.view.show(!1)}(e),console.log("[Multiline Plugin] Re-rendered all nodes")),l.edit_node_begin=function(e){if(console.log("[Multiline Plugin] edit_node_begin called",e),!e.topic)return;r&&l.edit_node_end(),r=e,l.editing_node=e;const t=n.c("div");t.contentEditable="plaintext-only",t.className="jsmind-multiline-editor",t.textContent=e.topic,a=t;const i=e._data.view.element;Object.assign(t.style,{width:"auto",minHeight:i.clientHeight+"px",lineHeight:d.line_height,border:"none",outline:"none",whiteSpace:"pre-wrap",wordBreak:"break-word",boxSizing:"border-box",overflow:"hidden"});const o=()=>{t.style.height="auto",t.style.height=t.scrollHeight+"px"};n.on(t,"input",o),setTimeout(o,0),n.on(t,"keydown",e=>{"Enter"!==e.key||e.shiftKey?"Escape"===e.key?(e.preventDefault(),e.stopPropagation(),function(){if(!r||!a)return;const e=r;s(),l.render_node(e._data.view.element,e),l.e_panel.focus()}()):"Tab"===e.key&&(e.preventDefault(),e.stopPropagation(),l.edit_node_end()):(e.preventDefault(),e.stopPropagation(),l.edit_node_end())}),n.on(t,"blur",()=>{setTimeout(()=>{r&&l.edit_node_end()},100)}),i.innerHTML="",i.appendChild(t),i.style.zIndex=5,t.focus();const u=n.d.createRange();u.selectNodeContents(t);const c=n.w.getSelection();c.removeAllRanges(),c.addRange(u)},l.edit_node_end=function(){if(!r||!a)return;const n=r,i=(a.textContent||"").trim().replace(/\r\n/g,"\n").replace(/\r/g,"\n").replace(/\n{3,}/g,"\n\n");s(),t.default.util.text.is_empty(i)||n.topic===i?l.render_node(n._data.view.element,n):e.update_node(n.id,i),l.e_panel.focus()}}t.default.register_plugin(new t.default.plugin("multiline_text",d));var l={name:"multiline_text",init:d,createMultilineRender:o};exports.createMultilineRender=o,exports.default=l;
8
+ "use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}Object.defineProperty(exports,"__esModule",{value:!0});var t=e(require("@umbraci/jsmind"));if(!t.default)throw new Error("jsMind is not defined");const n=t.default.$,i={text_width:200,line_height:"1.5"};function o(e={}){const t=Object.assign({},i,e);return function(e,n,i){return!(!i.topic||!i.topic.includes("\n"))&&(n.style.whiteSpace="pre-wrap",n.style.wordBreak="break-word",n.style.maxWidth=t.text_width+"px",n.textContent=i.topic,!0)}}function d(e,o){console.log("[Multiline Plugin] Initializing...",o);const d=Object.assign({},i,o),l=e.view;let r=null,a=null;function s(){if(!r||!a)return;const e=r._data.view.element;a.parentNode&&a.parentNode.removeChild(a),e.style.zIndex="auto",r=null,l.editing_node=null,a=null}l.opts.custom_node_render&&(l.render_node=l._custom_node_render.bind(l),console.log("[Multiline Plugin] Re-bound view.render_node")),e.mind&&e.mind.root&&(!function(e){const t=e.view,n=e.mind;if(!n||!n.root)return;const i=[];for(const e in n.nodes){const t=n.nodes[e];t._data&&t._data.view&&t._data.view.element&&i.push(t)}for(const e of i){const n=e._data.view.element;t.render_node(n,e)}for(const t of i)if(e.layout.is_visible(t)){const e=t._data.view.element;t._data.view.width=e.clientWidth,t._data.view.height=e.clientHeight}e.layout.layout(),e.view.show(!1)}(e),console.log("[Multiline Plugin] Re-rendered all nodes")),l.edit_node_begin=function(e){if(console.log("[Multiline Plugin] edit_node_begin called",e),!e.topic)return;r&&l.edit_node_end(),r=e,l.editing_node=e;const t=n.c("div");t.contentEditable="plaintext-only",t.className="jsmind-multiline-editor",t.textContent=e.topic,a=t;const i=e._data.view.element;Object.assign(t.style,{width:"auto",minHeight:i.clientHeight+"px",lineHeight:d.line_height,border:"none",outline:"none",whiteSpace:"pre-wrap",wordBreak:"break-word",boxSizing:"border-box",overflow:"hidden"});const o=()=>{t.style.height="auto",t.style.height=t.scrollHeight+"px"};n.on(t,"input",o),setTimeout(o,0),n.on(t,"keydown",(e=>{"Enter"!==e.key||e.shiftKey?"Escape"===e.key?(e.preventDefault(),e.stopPropagation(),function(){if(!r||!a)return;const e=r;s(),l.render_node(e._data.view.element,e),l.e_panel.focus()}()):"Tab"===e.key&&(e.preventDefault(),e.stopPropagation(),l.edit_node_end()):(e.preventDefault(),e.stopPropagation(),l.edit_node_end())})),n.on(t,"blur",(()=>{setTimeout((()=>{r&&l.edit_node_end()}),100)})),i.innerHTML="",i.appendChild(t),i.style.zIndex=5,t.focus();const u=n.d.createRange();u.selectNodeContents(t);const c=n.w.getSelection();c.removeAllRanges(),c.addRange(u)},l.edit_node_end=function(){if(!r||!a)return;const n=r,i=(a.textContent||"").trim().replace(/\r\n/g,"\n").replace(/\r/g,"\n").replace(/\n{3,}/g,"\n\n");s(),t.default.util.text.is_empty(i)||n.topic===i?l.render_node(n._data.view.element,n):e.update_node(n.id,i),l.e_panel.focus()}}t.default.register_plugin(new t.default.plugin("multiline_text",d));var l={name:"multiline_text",init:d,createMultilineRender:o};exports.createMultilineRender=o,exports.default=l;
9
9
  //# sourceMappingURL=jsmind.multiline-text.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"jsmind.multiline-text.js","sources":["../src/plugins/jsmind.multiline-text.js"],"sourcesContent":["/**\n * @license BSD\n * @copyright 2014-2025 UmbraCi\n *\n * Project Home:\n * https://github.com/hizzgdev/jsmind/\n */\n\nimport jsMind from '@umbraci/jsmind';\n\nif (!jsMind) {\n throw new Error('jsMind is not defined');\n}\n\nconst $ = jsMind.$;\n\n/**\n * Multiline Text Plugin\n * Provides multiline text support for jsMind nodes\n */\n\n/**\n * Default plugin options\n * @typedef {Object} MultilineTextOptions\n * @property {number} text_width - Maximum width for multiline text nodes (default: 200)\n * @property {string} line_height - Line height for text (default: '1.5')\n */\nconst DEFAULT_OPTIONS = {\n text_width: 200,\n line_height: '1.5',\n};\n\n/**\n * Create a custom node render function for multiline text\n * @param {MultilineTextOptions} [options={}] - Plugin options\n * @param {number} [options.text_width=200] - Maximum width for multiline text nodes\n * @param {string} [options.line_height='1.5'] - Line height for text\n * @returns {function(jsMind, HTMLElement, Node): boolean} Custom render function\n * @example\n * const options = {\n * view: {\n * custom_node_render: createMultilineRender({\n * text_width: 250,\n * line_height: '1.6',\n * })\n * }\n * };\n */\nexport function createMultilineRender(options = {}) {\n const opts = Object.assign({}, DEFAULT_OPTIONS, options);\n\n return function (jm, element, node) {\n if (node.topic && node.topic.includes('\\n')) {\n // Multiline text - apply styles BEFORE setting content\n element.style.whiteSpace = 'pre-wrap';\n element.style.wordBreak = 'break-word';\n element.style.maxWidth = opts.text_width + 'px';\n element.textContent = node.topic;\n return true;\n }\n // Single line text - use default render\n return false;\n };\n}\n\n/**\n * Re-render all nodes to apply multiline styles and recalculate sizes\n * @param {import('../jsmind.js').default} jm - jsMind instance\n * @private\n */\nfunction _rerender_all_nodes(jm) {\n const view = jm.view;\n const mind = jm.mind;\n\n if (!mind || !mind.root) {\n return;\n }\n\n // Collect all nodes to update\n const nodesToUpdate = [];\n for (const nodeId in mind.nodes) {\n const node = mind.nodes[nodeId];\n if (node._data && node._data.view && node._data.view.element) {\n nodesToUpdate.push(node);\n }\n }\n\n // Batch render nodes (only update DOM, no layout trigger)\n for (const node of nodesToUpdate) {\n const element = node._data.view.element;\n view.render_node(element, node);\n }\n\n // Batch update node sizes (read all sizes at once to avoid layout thrashing)\n for (const node of nodesToUpdate) {\n if (jm.layout.is_visible(node)) {\n const element = node._data.view.element;\n node._data.view.width = element.clientWidth;\n node._data.view.height = element.clientHeight;\n }\n }\n\n // Finally recalculate layout and show (only trigger reflow/repaint once)\n jm.layout.layout();\n jm.view.show(false);\n}\n\n/**\n * Plugin initialization function\n * @param {import('../jsmind.js').default} jm - jsMind instance\n * @param {MultilineTextOptions} options - Plugin options\n * @private\n */\nfunction init(jm, options) {\n console.log('[Multiline Plugin] Initializing...', options);\n\n const opts = Object.assign({}, DEFAULT_OPTIONS, options);\n const view = jm.view;\n\n // Plugin state\n let editing_node = null;\n let multiline_editor = null;\n\n // IMPORTANT: Re-set view.render_node to use custom render\n // Because ViewProvider constructor already set it based on options.custom_node_render\n // We need to ensure it uses the custom render function\n if (view.opts.custom_node_render) {\n view.render_node = view._custom_node_render.bind(view);\n console.log('[Multiline Plugin] Re-bound view.render_node');\n }\n\n // Re-render all nodes to apply multiline styles\n if (jm.mind && jm.mind.root) {\n _rerender_all_nodes(jm);\n console.log('[Multiline Plugin] Re-rendered all nodes');\n }\n\n /**\n * Begin editing a node with multiline support\n * @param {import('../jsmind.node.js').Node} node\n */\n view.edit_node_begin = function (node) {\n console.log('[Multiline Plugin] edit_node_begin called', node);\n if (!node.topic) {\n return;\n }\n\n // End editing if another node is being edited\n if (editing_node) {\n view.edit_node_end();\n }\n\n editing_node = node;\n view.editing_node = node;\n\n // Create editor (div with contentEditable)\n const editor = $.c('div');\n editor.contentEditable = 'plaintext-only';\n editor.className = 'jsmind-multiline-editor';\n editor.textContent = node.topic;\n multiline_editor = editor;\n\n // Get element and set editor styles to match\n const element = node._data.view.element;\n\n // Set editor styles to match element width, auto-expand height\n Object.assign(editor.style, {\n width: 'auto',\n minHeight: element.clientHeight + 'px',\n lineHeight: opts.line_height,\n border: 'none',\n outline: 'none',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n boxSizing: 'border-box',\n overflow: 'hidden',\n });\n\n // Auto-expand height on input\n const autoExpand = () => {\n editor.style.height = 'auto';\n editor.style.height = editor.scrollHeight + 'px';\n };\n $.on(editor, 'input', autoExpand);\n // Initial expand\n setTimeout(autoExpand, 0);\n\n // Keyboard events\n $.on(editor, 'keydown', e => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n e.stopPropagation(); // Prevent jsMind shortcut from triggering\n view.edit_node_end();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n cancel_editing();\n } else if (e.key === 'Tab') {\n e.preventDefault();\n e.stopPropagation();\n view.edit_node_end();\n }\n });\n\n // Blur event - save on blur\n $.on(editor, 'blur', () => {\n setTimeout(() => {\n if (editing_node) {\n view.edit_node_end();\n }\n }, 100);\n });\n\n // Replace node content and focus\n element.innerHTML = '';\n element.appendChild(editor);\n element.style.zIndex = 5;\n editor.focus();\n\n // Select all text\n const range = $.d.createRange();\n range.selectNodeContents(editor);\n const selection = $.w.getSelection();\n selection.removeAllRanges();\n selection.addRange(range);\n };\n\n /**\n * End editing and save changes\n */\n view.edit_node_end = function () {\n if (!editing_node || !multiline_editor) {\n return;\n }\n\n const node = editing_node;\n const topic = (multiline_editor.textContent || '')\n .trim()\n .replace(/\\r\\n/g, '\\n')\n .replace(/\\r/g, '\\n')\n .replace(/\\n{3,}/g, '\\n\\n');\n\n // Clean up editor\n cleanup_editor();\n\n // Update node if content changed\n if (!jsMind.util.text.is_empty(topic) && node.topic !== topic) {\n jm.update_node(node.id, topic);\n } else {\n view.render_node(node._data.view.element, node);\n }\n\n // Focus panel\n view.e_panel.focus();\n };\n\n /**\n * Cancel editing without saving changes\n */\n function cancel_editing() {\n if (!editing_node || !multiline_editor) {\n return;\n }\n\n const node = editing_node;\n\n // Clean up editor\n cleanup_editor();\n\n // Re-render node\n view.render_node(node._data.view.element, node);\n\n // Focus panel\n view.e_panel.focus();\n }\n\n /**\n * Clean up editor and reset state\n */\n function cleanup_editor() {\n if (!editing_node || !multiline_editor) {\n return;\n }\n\n const element = editing_node._data.view.element;\n\n // Remove editor\n if (multiline_editor.parentNode) {\n multiline_editor.parentNode.removeChild(multiline_editor);\n }\n\n // Reset styles and state\n element.style.zIndex = 'auto';\n editing_node = null;\n view.editing_node = null;\n multiline_editor = null;\n }\n}\n\n// Register plugin\njsMind.register_plugin(new jsMind.plugin('multiline_text', init));\n\n// Export for ES6 modules\nexport default {\n name: 'multiline_text',\n init,\n createMultilineRender,\n};\n"],"names":["jsMind","Error","$","DEFAULT_OPTIONS","text_width","line_height","createMultilineRender","options","opts","Object","assign","jm","element","node","topic","includes","style","whiteSpace","wordBreak","maxWidth","textContent","init","console","log","view","editing_node","multiline_editor","cleanup_editor","_data","parentNode","removeChild","zIndex","custom_node_render","render_node","_custom_node_render","bind","mind","root","nodesToUpdate","nodeId","nodes","push","layout","is_visible","width","clientWidth","height","clientHeight","show","_rerender_all_nodes","edit_node_begin","edit_node_end","editor","c","contentEditable","className","minHeight","lineHeight","border","outline","boxSizing","overflow","autoExpand","scrollHeight","on","setTimeout","e","key","shiftKey","preventDefault","stopPropagation","e_panel","focus","cancel_editing","innerHTML","appendChild","range","d","createRange","selectNodeContents","selection","w","getSelection","removeAllRanges","addRange","trim","replace","util","text","is_empty","update_node","id","register_plugin","plugin","jsmind_multilineText","name"],"mappings":"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"}
1
+ {"version":3,"file":"jsmind.multiline-text.js","sources":["../src/plugins/jsmind.multiline-text.js"],"sourcesContent":["/**\r\n * @license BSD\r\n * @copyright 2014-2025 UmbraCi\r\n *\r\n * Project Home:\r\n * https://github.com/hizzgdev/jsmind/\r\n */\r\n\r\nimport jsMind from '@umbraci/jsmind';\r\n\r\nif (!jsMind) {\r\n throw new Error('jsMind is not defined');\r\n}\r\n\r\nconst $ = jsMind.$;\r\n\r\n/**\r\n * Multiline Text Plugin\r\n * Provides multiline text support for jsMind nodes\r\n */\r\n\r\n/**\r\n * Default plugin options\r\n * @typedef {Object} MultilineTextOptions\r\n * @property {number} text_width - Maximum width for multiline text nodes (default: 200)\r\n * @property {string} line_height - Line height for text (default: '1.5')\r\n */\r\nconst DEFAULT_OPTIONS = {\r\n text_width: 200,\r\n line_height: '1.5',\r\n};\r\n\r\n/**\r\n * Create a custom node render function for multiline text\r\n * @param {MultilineTextOptions} [options={}] - Plugin options\r\n * @param {number} [options.text_width=200] - Maximum width for multiline text nodes\r\n * @param {string} [options.line_height='1.5'] - Line height for text\r\n * @returns {function(jsMind, HTMLElement, Node): boolean} Custom render function\r\n * @example\r\n * const options = {\r\n * view: {\r\n * custom_node_render: createMultilineRender({\r\n * text_width: 250,\r\n * line_height: '1.6',\r\n * })\r\n * }\r\n * };\r\n */\r\nexport function createMultilineRender(options = {}) {\r\n const opts = Object.assign({}, DEFAULT_OPTIONS, options);\r\n\r\n return function (jm, element, node) {\r\n if (node.topic && node.topic.includes('\\n')) {\r\n // Multiline text - apply styles BEFORE setting content\r\n element.style.whiteSpace = 'pre-wrap';\r\n element.style.wordBreak = 'break-word';\r\n element.style.maxWidth = opts.text_width + 'px';\r\n element.textContent = node.topic;\r\n return true;\r\n }\r\n // Single line text - use default render\r\n return false;\r\n };\r\n}\r\n\r\n/**\r\n * Re-render all nodes to apply multiline styles and recalculate sizes\r\n * @param {import('../jsmind.js').default} jm - jsMind instance\r\n * @private\r\n */\r\nfunction _rerender_all_nodes(jm) {\r\n const view = jm.view;\r\n const mind = jm.mind;\r\n\r\n if (!mind || !mind.root) {\r\n return;\r\n }\r\n\r\n // Collect all nodes to update\r\n const nodesToUpdate = [];\r\n for (const nodeId in mind.nodes) {\r\n const node = mind.nodes[nodeId];\r\n if (node._data && node._data.view && node._data.view.element) {\r\n nodesToUpdate.push(node);\r\n }\r\n }\r\n\r\n // Batch render nodes (only update DOM, no layout trigger)\r\n for (const node of nodesToUpdate) {\r\n const element = node._data.view.element;\r\n view.render_node(element, node);\r\n }\r\n\r\n // Batch update node sizes (read all sizes at once to avoid layout thrashing)\r\n for (const node of nodesToUpdate) {\r\n if (jm.layout.is_visible(node)) {\r\n const element = node._data.view.element;\r\n node._data.view.width = element.clientWidth;\r\n node._data.view.height = element.clientHeight;\r\n }\r\n }\r\n\r\n // Finally recalculate layout and show (only trigger reflow/repaint once)\r\n jm.layout.layout();\r\n jm.view.show(false);\r\n}\r\n\r\n/**\r\n * Plugin initialization function\r\n * @param {import('../jsmind.js').default} jm - jsMind instance\r\n * @param {MultilineTextOptions} options - Plugin options\r\n * @private\r\n */\r\nfunction init(jm, options) {\r\n console.log('[Multiline Plugin] Initializing...', options);\r\n\r\n const opts = Object.assign({}, DEFAULT_OPTIONS, options);\r\n const view = jm.view;\r\n\r\n // Plugin state\r\n let editing_node = null;\r\n let multiline_editor = null;\r\n\r\n // IMPORTANT: Re-set view.render_node to use custom render\r\n // Because ViewProvider constructor already set it based on options.custom_node_render\r\n // We need to ensure it uses the custom render function\r\n if (view.opts.custom_node_render) {\r\n view.render_node = view._custom_node_render.bind(view);\r\n console.log('[Multiline Plugin] Re-bound view.render_node');\r\n }\r\n\r\n // Re-render all nodes to apply multiline styles\r\n if (jm.mind && jm.mind.root) {\r\n _rerender_all_nodes(jm);\r\n console.log('[Multiline Plugin] Re-rendered all nodes');\r\n }\r\n\r\n /**\r\n * Begin editing a node with multiline support\r\n * @param {import('../jsmind.node.js').Node} node\r\n */\r\n view.edit_node_begin = function (node) {\r\n console.log('[Multiline Plugin] edit_node_begin called', node);\r\n if (!node.topic) {\r\n return;\r\n }\r\n\r\n // End editing if another node is being edited\r\n if (editing_node) {\r\n view.edit_node_end();\r\n }\r\n\r\n editing_node = node;\r\n view.editing_node = node;\r\n\r\n // Create editor (div with contentEditable)\r\n const editor = $.c('div');\r\n editor.contentEditable = 'plaintext-only';\r\n editor.className = 'jsmind-multiline-editor';\r\n editor.textContent = node.topic;\r\n multiline_editor = editor;\r\n\r\n // Get element and set editor styles to match\r\n const element = node._data.view.element;\r\n\r\n // Set editor styles to match element width, auto-expand height\r\n Object.assign(editor.style, {\r\n width: 'auto',\r\n minHeight: element.clientHeight + 'px',\r\n lineHeight: opts.line_height,\r\n border: 'none',\r\n outline: 'none',\r\n whiteSpace: 'pre-wrap',\r\n wordBreak: 'break-word',\r\n boxSizing: 'border-box',\r\n overflow: 'hidden',\r\n });\r\n\r\n // Auto-expand height on input\r\n const autoExpand = () => {\r\n editor.style.height = 'auto';\r\n editor.style.height = editor.scrollHeight + 'px';\r\n };\r\n $.on(editor, 'input', autoExpand);\r\n // Initial expand\r\n setTimeout(autoExpand, 0);\r\n\r\n // Keyboard events\r\n $.on(editor, 'keydown', e => {\r\n if (e.key === 'Enter' && !e.shiftKey) {\r\n e.preventDefault();\r\n e.stopPropagation(); // Prevent jsMind shortcut from triggering\r\n view.edit_node_end();\r\n } else if (e.key === 'Escape') {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n cancel_editing();\r\n } else if (e.key === 'Tab') {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n view.edit_node_end();\r\n }\r\n });\r\n\r\n // Blur event - save on blur\r\n $.on(editor, 'blur', () => {\r\n setTimeout(() => {\r\n if (editing_node) {\r\n view.edit_node_end();\r\n }\r\n }, 100);\r\n });\r\n\r\n // Replace node content and focus\r\n element.innerHTML = '';\r\n element.appendChild(editor);\r\n element.style.zIndex = 5;\r\n editor.focus();\r\n\r\n // Select all text\r\n const range = $.d.createRange();\r\n range.selectNodeContents(editor);\r\n const selection = $.w.getSelection();\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n };\r\n\r\n /**\r\n * End editing and save changes\r\n */\r\n view.edit_node_end = function () {\r\n if (!editing_node || !multiline_editor) {\r\n return;\r\n }\r\n\r\n const node = editing_node;\r\n const topic = (multiline_editor.textContent || '')\r\n .trim()\r\n .replace(/\\r\\n/g, '\\n')\r\n .replace(/\\r/g, '\\n')\r\n .replace(/\\n{3,}/g, '\\n\\n');\r\n\r\n // Clean up editor\r\n cleanup_editor();\r\n\r\n // Update node if content changed\r\n if (!jsMind.util.text.is_empty(topic) && node.topic !== topic) {\r\n jm.update_node(node.id, topic);\r\n } else {\r\n view.render_node(node._data.view.element, node);\r\n }\r\n\r\n // Focus panel\r\n view.e_panel.focus();\r\n };\r\n\r\n /**\r\n * Cancel editing without saving changes\r\n */\r\n function cancel_editing() {\r\n if (!editing_node || !multiline_editor) {\r\n return;\r\n }\r\n\r\n const node = editing_node;\r\n\r\n // Clean up editor\r\n cleanup_editor();\r\n\r\n // Re-render node\r\n view.render_node(node._data.view.element, node);\r\n\r\n // Focus panel\r\n view.e_panel.focus();\r\n }\r\n\r\n /**\r\n * Clean up editor and reset state\r\n */\r\n function cleanup_editor() {\r\n if (!editing_node || !multiline_editor) {\r\n return;\r\n }\r\n\r\n const element = editing_node._data.view.element;\r\n\r\n // Remove editor\r\n if (multiline_editor.parentNode) {\r\n multiline_editor.parentNode.removeChild(multiline_editor);\r\n }\r\n\r\n // Reset styles and state\r\n element.style.zIndex = 'auto';\r\n editing_node = null;\r\n view.editing_node = null;\r\n multiline_editor = null;\r\n }\r\n}\r\n\r\n// Register plugin\r\njsMind.register_plugin(new jsMind.plugin('multiline_text', init));\r\n\r\n// Export for ES6 modules\r\nexport default {\r\n name: 'multiline_text',\r\n init,\r\n createMultilineRender,\r\n};\r\n"],"names":["jsMind","Error","$","DEFAULT_OPTIONS","text_width","line_height","createMultilineRender","options","opts","Object","assign","jm","element","node","topic","includes","style","whiteSpace","wordBreak","maxWidth","textContent","init","console","log","view","editing_node","multiline_editor","cleanup_editor","_data","parentNode","removeChild","zIndex","custom_node_render","render_node","_custom_node_render","bind","mind","root","nodesToUpdate","nodeId","nodes","push","layout","is_visible","width","clientWidth","height","clientHeight","show","_rerender_all_nodes","edit_node_begin","edit_node_end","editor","c","contentEditable","className","minHeight","lineHeight","border","outline","boxSizing","overflow","autoExpand","scrollHeight","on","setTimeout","e","key","shiftKey","preventDefault","stopPropagation","e_panel","focus","cancel_editing","innerHTML","appendChild","range","d","createRange","selectNodeContents","selection","w","getSelection","removeAllRanges","addRange","trim","replace","util","text","is_empty","update_node","id","register_plugin","plugin","jsmind_multilineText","name"],"mappings":"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"}
@@ -5,5 +5,5 @@
5
5
  * Project Home:
6
6
  * https://github.com/hizzgdev/jsmind/
7
7
  */
8
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@umbraci/jsmind"),t=require("dom-to-image");function i(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var n=i(e),r=i(t);if(!n.default)throw new Error("jsMind is not defined");if(!r.default)throw new Error("dom-to-image is required");const o=n.default.$,s={filename:null,watermark:{left:o.w.location,right:"https://github.com/UmbraCi/jsmind"},background:"transparent"};class a{constructor(e,t){var i={};n.default.util.json.merge(i,s),n.default.util.json.merge(i,t),this.version="0.2.0",this.jm=e,this.options=i,this.dpr=e.view.device_pixel_ratio}shoot(){let e=this.create_canvas(),t=e.getContext("2d");t.scale(this.dpr,this.dpr),Promise.resolve(t).then(()=>this.draw_background(t)).then(()=>this.draw_lines(t)).then(()=>this.draw_nodes(t)).then(()=>this.draw_watermark(e,t)).then(()=>this.download(e)).then(()=>this.clear(e))}create_canvas(){let e=o.c("canvas");const t=this.jm.view.size.w,i=this.jm.view.size.h;return e.width=t*this.dpr,e.height=i*this.dpr,e.style.width=t+"px",e.style.height=i+"px",e.style.visibility="hidden",this.jm.view.e_panel.appendChild(e),e}clear(e){e.parentNode.removeChild(e)}draw_background(e){return new Promise(function(t,i){const n=this.options.background;n&&"transparent"!==n&&(e.fillStyle=this.options.background,e.fillRect(0,0,this.jm.view.size.w,this.jm.view.size.h)),t(e)}.bind(this))}draw_lines(e){return new Promise(function(t,i){this.jm.view.graph.copy_to(e,function(){t(e)})}.bind(this))}draw_nodes(e){return r.default.toSvg(this.jm.view.e_nodes,{style:{zoom:1}}).then(this.load_image).then(function(t){return e.drawImage(t,0,0),e})}draw_watermark(e,t){return t.textBaseline="bottom",t.fillStyle="#000",t.font="11px Verdana,Arial,Helvetica,sans-serif",this.options.watermark.left&&(t.textAlign="left",t.fillText(this.options.watermark.left,5.5,e.height-2.5)),this.options.watermark.right&&(t.textAlign="right",t.fillText(this.options.watermark.right,e.width-5.5,e.height-2.5)),t}load_image(e){return new Promise(function(t,i){let n=new Image;n.onload=function(){t(n)},n.onerror=i,n.src=e})}download(e){var t=(this.options.filename||this.jm.mind.name)+".png";if(navigator.msSaveBlob&&e.msToBlob){var i=e.msToBlob();navigator.msSaveBlob(i,t)}else{var n=e.toDataURL(),r=o.c("a");if("download"in r){r.style.visibility="hidden",r.href=n,r.download=t,o.d.body.appendChild(r);var s=o.d.createEvent("MouseEvents");s.initEvent("click",!0,!0),r.dispatchEvent(s),o.d.body.removeChild(r)}else location.href=n}}}const l=new n.default.plugin("screenshot",function(e,t){var i=new a(e,t);e.screenshot=i,e.shoot=function(){i.shoot()}});n.default.register_plugin(l),exports.JmScreenshot=a,exports.default=a,exports.screenshot_plugin=l;
8
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@umbraci/jsmind"),t=require("dom-to-image");function i(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var n=i(e),r=i(t);if(!n.default)throw new Error("jsMind is not defined");if(!r.default)throw new Error("dom-to-image is required");const o=n.default.$,s={filename:null,watermark:{left:o.w.location,right:"https://github.com/UmbraCi/jsmind"},background:"transparent"};class a{constructor(e,t){var i={};n.default.util.json.merge(i,s),n.default.util.json.merge(i,t),this.version="0.2.0",this.jm=e,this.options=i,this.dpr=e.view.device_pixel_ratio}shoot(){let e=this.create_canvas(),t=e.getContext("2d");t.scale(this.dpr,this.dpr),Promise.resolve(t).then((()=>this.draw_background(t))).then((()=>this.draw_lines(t))).then((()=>this.draw_nodes(t))).then((()=>this.draw_watermark(e,t))).then((()=>this.download(e))).then((()=>this.clear(e)))}create_canvas(){let e=o.c("canvas");const t=this.jm.view.size.w,i=this.jm.view.size.h;return e.width=t*this.dpr,e.height=i*this.dpr,e.style.width=t+"px",e.style.height=i+"px",e.style.visibility="hidden",this.jm.view.e_panel.appendChild(e),e}clear(e){e.parentNode.removeChild(e)}draw_background(e){return new Promise(function(t,i){const n=this.options.background;n&&"transparent"!==n&&(e.fillStyle=this.options.background,e.fillRect(0,0,this.jm.view.size.w,this.jm.view.size.h)),t(e)}.bind(this))}draw_lines(e){return new Promise(function(t,i){this.jm.view.graph.copy_to(e,(function(){t(e)}))}.bind(this))}draw_nodes(e){return r.default.toSvg(this.jm.view.e_nodes,{style:{zoom:1}}).then(this.load_image).then((function(t){return e.drawImage(t,0,0),e}))}draw_watermark(e,t){return t.textBaseline="bottom",t.fillStyle="#000",t.font="11px Verdana,Arial,Helvetica,sans-serif",this.options.watermark.left&&(t.textAlign="left",t.fillText(this.options.watermark.left,5.5,e.height-2.5)),this.options.watermark.right&&(t.textAlign="right",t.fillText(this.options.watermark.right,e.width-5.5,e.height-2.5)),t}load_image(e){return new Promise((function(t,i){let n=new Image;n.onload=function(){t(n)},n.onerror=i,n.src=e}))}download(e){var t=(this.options.filename||this.jm.mind.name)+".png";if(navigator.msSaveBlob&&e.msToBlob){var i=e.msToBlob();navigator.msSaveBlob(i,t)}else{var n=e.toDataURL(),r=o.c("a");if("download"in r){r.style.visibility="hidden",r.href=n,r.download=t,o.d.body.appendChild(r);var s=o.d.createEvent("MouseEvents");s.initEvent("click",!0,!0),r.dispatchEvent(s),o.d.body.removeChild(r)}else location.href=n}}}const l=new n.default.plugin("screenshot",(function(e,t){var i=new a(e,t);e.screenshot=i,e.shoot=function(){i.shoot()}}));n.default.register_plugin(l),exports.JmScreenshot=a,exports.default=a,exports.screenshot_plugin=l;
9
9
  //# sourceMappingURL=jsmind.screenshot.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"jsmind.screenshot.js","sources":["../src/plugins/jsmind.screenshot.js"],"sourcesContent":["/**\n * @license BSD\n * @copyright 2014-2025 UmbraCi\n *\n * Project Home:\n * https://github.com/UmbraCi/jsmind/\n */\n\nimport jsMind from '@umbraci/jsmind';\nimport domtoimage from 'dom-to-image';\n\nif (!jsMind) {\n throw new Error('jsMind is not defined');\n}\n\nif (!domtoimage) {\n throw new Error('dom-to-image is required');\n}\n\nconst $ = jsMind.$;\n\n/**\n * Default options for screenshot plugin.\n * @typedef {Object} ScreenshotOptions\n * @property {string|null} [filename]\n * @property {{left?:string|Location,right?:string}} [watermark]\n * @property {string} [background]\n */\nconst DEFAULT_OPTIONS = {\n filename: null,\n watermark: {\n left: $.w.location,\n right: 'https://github.com/UmbraCi/jsmind',\n },\n background: 'transparent',\n};\n\n/**\n * Screenshot plugin for jsMind.\n */\nexport class JmScreenshot {\n /**\n * Create screenshot plugin instance.\n * @param {import('../jsmind.js').default} jm - jsMind instance\n * @param {Partial<ScreenshotOptions>} options - Plugin options\n */\n constructor(jm, options) {\n var opts = {};\n jsMind.util.json.merge(opts, DEFAULT_OPTIONS);\n jsMind.util.json.merge(opts, options);\n\n this.version = '0.2.0';\n /** @type {import('../jsmind.js').default} */\n this.jm = jm;\n /** @type {ScreenshotOptions} */\n this.options = opts;\n /** @type {number} */\n this.dpr = jm.view.device_pixel_ratio;\n }\n\n /** Take a screenshot of the mind map. */\n shoot() {\n let c = this.create_canvas();\n let ctx = c.getContext('2d');\n ctx.scale(this.dpr, this.dpr);\n Promise.resolve(ctx)\n .then(() => this.draw_background(ctx))\n .then(() => this.draw_lines(ctx))\n .then(() => this.draw_nodes(ctx))\n .then(() => this.draw_watermark(c, ctx))\n .then(() => this.download(c))\n .then(() => this.clear(c));\n }\n\n /**\n * Create canvas for screenshot.\n * @returns {HTMLCanvasElement} Canvas element\n */\n create_canvas() {\n let c = $.c('canvas');\n const w = this.jm.view.size.w;\n const h = this.jm.view.size.h;\n c.width = w * this.dpr;\n c.height = h * this.dpr;\n c.style.width = w + 'px';\n c.style.height = h + 'px';\n\n c.style.visibility = 'hidden';\n this.jm.view.e_panel.appendChild(c);\n return c;\n }\n\n /**\n * Clean up canvas element.\n * @param {HTMLCanvasElement} c - Canvas to remove\n */\n clear(c) {\n c.parentNode.removeChild(c);\n }\n\n /**\n * Draw background on canvas.\n * @param {CanvasRenderingContext2D} ctx - Canvas context\n * @returns {Promise<CanvasRenderingContext2D>} Promise resolving to context\n */\n draw_background(ctx) {\n return new Promise(\n function (resolve, _) {\n const bg = this.options.background;\n if (!!bg && bg !== 'transparent') {\n ctx.fillStyle = this.options.background;\n ctx.fillRect(0, 0, this.jm.view.size.w, this.jm.view.size.h);\n }\n resolve(ctx);\n }.bind(this)\n );\n }\n\n /**\n * Draw connection lines on canvas by copying from view graph.\n * @param {CanvasRenderingContext2D} ctx\n * @returns {Promise<CanvasRenderingContext2D>}\n */\n draw_lines(ctx) {\n return new Promise(\n function (resolve, _) {\n this.jm.view.graph.copy_to(ctx, function () {\n resolve(ctx);\n });\n }.bind(this)\n );\n }\n\n /**\n * Draw node DOM into canvas via SVG snapshot.\n * @param {CanvasRenderingContext2D} ctx\n * @returns {Promise<CanvasRenderingContext2D>}\n */\n draw_nodes(ctx) {\n return domtoimage\n .toSvg(this.jm.view.e_nodes, { style: { zoom: 1 } })\n .then(this.load_image)\n .then(function (img) {\n ctx.drawImage(img, 0, 0);\n return ctx;\n });\n }\n\n /**\n * Draw watermark text on canvas.\n * @param {HTMLCanvasElement} c\n * @param {CanvasRenderingContext2D} ctx\n * @returns {CanvasRenderingContext2D}\n */\n draw_watermark(c, ctx) {\n ctx.textBaseline = 'bottom';\n ctx.fillStyle = '#000';\n ctx.font = '11px Verdana,Arial,Helvetica,sans-serif';\n if (!!this.options.watermark.left) {\n ctx.textAlign = 'left';\n ctx.fillText(this.options.watermark.left, 5.5, c.height - 2.5);\n }\n if (!!this.options.watermark.right) {\n ctx.textAlign = 'right';\n ctx.fillText(this.options.watermark.right, c.width - 5.5, c.height - 2.5);\n }\n return ctx;\n }\n\n /**\n * Load image from URL and resolve img element.\n * @param {string} url\n * @returns {Promise<HTMLImageElement>}\n */\n load_image(url) {\n return new Promise(function (resolve, reject) {\n let img = new Image();\n img.onload = function () {\n resolve(img);\n };\n img.onerror = reject;\n img.src = url;\n });\n }\n\n /**\n * Trigger download of canvas content as PNG.\n * @param {HTMLCanvasElement} c\n */\n download(c) {\n var name = (this.options.filename || this.jm.mind.name) + '.png';\n\n if (navigator.msSaveBlob && !!c.msToBlob) {\n var blob = c.msToBlob();\n navigator.msSaveBlob(blob, name);\n } else {\n var blob_url = c.toDataURL();\n var anchor = $.c('a');\n if ('download' in anchor) {\n anchor.style.visibility = 'hidden';\n anchor.href = blob_url;\n anchor.download = name;\n $.d.body.appendChild(anchor);\n var evt = $.d.createEvent('MouseEvents');\n evt.initEvent('click', true, true);\n anchor.dispatchEvent(evt);\n $.d.body.removeChild(anchor);\n } else {\n location.href = blob_url;\n }\n }\n }\n}\n\n/**\n * Screenshot plugin registration.\n * @type {import('../jsmind.plugin.js').Plugin<Partial<ScreenshotOptions>>}\n */\nexport const screenshot_plugin = new jsMind.plugin('screenshot', function (jm, options) {\n var jmss = new JmScreenshot(jm, options);\n jm.screenshot = jmss;\n jm.shoot = function () {\n jmss.shoot();\n };\n});\n\njsMind.register_plugin(screenshot_plugin);\n\nexport default JmScreenshot;\n"],"names":["jsMind","Error","domtoimage","$","DEFAULT_OPTIONS","filename","watermark","left","w","location","right","background","JmScreenshot","constructor","jm","options","opts","util","json","merge","this","version","dpr","view","device_pixel_ratio","shoot","c","create_canvas","ctx","getContext","scale","Promise","resolve","then","draw_background","draw_lines","draw_nodes","draw_watermark","download","clear","size","h","width","height","style","visibility","e_panel","appendChild","parentNode","removeChild","_","bg","fillStyle","fillRect","bind","graph","copy_to","toSvg","e_nodes","zoom","load_image","img","drawImage","textBaseline","font","textAlign","fillText","url","reject","Image","onload","onerror","src","name","mind","navigator","msSaveBlob","msToBlob","blob","blob_url","toDataURL","anchor","href","d","body","evt","createEvent","initEvent","dispatchEvent","screenshot_plugin","plugin","jmss","screenshot","register_plugin"],"mappings":"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"}
1
+ {"version":3,"file":"jsmind.screenshot.js","sources":["../src/plugins/jsmind.screenshot.js"],"sourcesContent":["/**\r\n * @license BSD\r\n * @copyright 2014-2025 UmbraCi\r\n *\r\n * Project Home:\r\n * https://github.com/UmbraCi/jsmind/\r\n */\r\n\r\nimport jsMind from '@umbraci/jsmind';\r\nimport domtoimage from 'dom-to-image';\r\n\r\nif (!jsMind) {\r\n throw new Error('jsMind is not defined');\r\n}\r\n\r\nif (!domtoimage) {\r\n throw new Error('dom-to-image is required');\r\n}\r\n\r\nconst $ = jsMind.$;\r\n\r\n/**\r\n * Default options for screenshot plugin.\r\n * @typedef {Object} ScreenshotOptions\r\n * @property {string|null} [filename]\r\n * @property {{left?:string|Location,right?:string}} [watermark]\r\n * @property {string} [background]\r\n */\r\nconst DEFAULT_OPTIONS = {\r\n filename: null,\r\n watermark: {\r\n left: $.w.location,\r\n right: 'https://github.com/UmbraCi/jsmind',\r\n },\r\n background: 'transparent',\r\n};\r\n\r\n/**\r\n * Screenshot plugin for jsMind.\r\n */\r\nexport class JmScreenshot {\r\n /**\r\n * Create screenshot plugin instance.\r\n * @param {import('../jsmind.js').default} jm - jsMind instance\r\n * @param {Partial<ScreenshotOptions>} options - Plugin options\r\n */\r\n constructor(jm, options) {\r\n var opts = {};\r\n jsMind.util.json.merge(opts, DEFAULT_OPTIONS);\r\n jsMind.util.json.merge(opts, options);\r\n\r\n this.version = '0.2.0';\r\n /** @type {import('../jsmind.js').default} */\r\n this.jm = jm;\r\n /** @type {ScreenshotOptions} */\r\n this.options = opts;\r\n /** @type {number} */\r\n this.dpr = jm.view.device_pixel_ratio;\r\n }\r\n\r\n /** Take a screenshot of the mind map. */\r\n shoot() {\r\n let c = this.create_canvas();\r\n let ctx = c.getContext('2d');\r\n ctx.scale(this.dpr, this.dpr);\r\n Promise.resolve(ctx)\r\n .then(() => this.draw_background(ctx))\r\n .then(() => this.draw_lines(ctx))\r\n .then(() => this.draw_nodes(ctx))\r\n .then(() => this.draw_watermark(c, ctx))\r\n .then(() => this.download(c))\r\n .then(() => this.clear(c));\r\n }\r\n\r\n /**\r\n * Create canvas for screenshot.\r\n * @returns {HTMLCanvasElement} Canvas element\r\n */\r\n create_canvas() {\r\n let c = $.c('canvas');\r\n const w = this.jm.view.size.w;\r\n const h = this.jm.view.size.h;\r\n c.width = w * this.dpr;\r\n c.height = h * this.dpr;\r\n c.style.width = w + 'px';\r\n c.style.height = h + 'px';\r\n\r\n c.style.visibility = 'hidden';\r\n this.jm.view.e_panel.appendChild(c);\r\n return c;\r\n }\r\n\r\n /**\r\n * Clean up canvas element.\r\n * @param {HTMLCanvasElement} c - Canvas to remove\r\n */\r\n clear(c) {\r\n c.parentNode.removeChild(c);\r\n }\r\n\r\n /**\r\n * Draw background on canvas.\r\n * @param {CanvasRenderingContext2D} ctx - Canvas context\r\n * @returns {Promise<CanvasRenderingContext2D>} Promise resolving to context\r\n */\r\n draw_background(ctx) {\r\n return new Promise(\r\n function (resolve, _) {\r\n const bg = this.options.background;\r\n if (!!bg && bg !== 'transparent') {\r\n ctx.fillStyle = this.options.background;\r\n ctx.fillRect(0, 0, this.jm.view.size.w, this.jm.view.size.h);\r\n }\r\n resolve(ctx);\r\n }.bind(this)\r\n );\r\n }\r\n\r\n /**\r\n * Draw connection lines on canvas by copying from view graph.\r\n * @param {CanvasRenderingContext2D} ctx\r\n * @returns {Promise<CanvasRenderingContext2D>}\r\n */\r\n draw_lines(ctx) {\r\n return new Promise(\r\n function (resolve, _) {\r\n this.jm.view.graph.copy_to(ctx, function () {\r\n resolve(ctx);\r\n });\r\n }.bind(this)\r\n );\r\n }\r\n\r\n /**\r\n * Draw node DOM into canvas via SVG snapshot.\r\n * @param {CanvasRenderingContext2D} ctx\r\n * @returns {Promise<CanvasRenderingContext2D>}\r\n */\r\n draw_nodes(ctx) {\r\n return domtoimage\r\n .toSvg(this.jm.view.e_nodes, { style: { zoom: 1 } })\r\n .then(this.load_image)\r\n .then(function (img) {\r\n ctx.drawImage(img, 0, 0);\r\n return ctx;\r\n });\r\n }\r\n\r\n /**\r\n * Draw watermark text on canvas.\r\n * @param {HTMLCanvasElement} c\r\n * @param {CanvasRenderingContext2D} ctx\r\n * @returns {CanvasRenderingContext2D}\r\n */\r\n draw_watermark(c, ctx) {\r\n ctx.textBaseline = 'bottom';\r\n ctx.fillStyle = '#000';\r\n ctx.font = '11px Verdana,Arial,Helvetica,sans-serif';\r\n if (!!this.options.watermark.left) {\r\n ctx.textAlign = 'left';\r\n ctx.fillText(this.options.watermark.left, 5.5, c.height - 2.5);\r\n }\r\n if (!!this.options.watermark.right) {\r\n ctx.textAlign = 'right';\r\n ctx.fillText(this.options.watermark.right, c.width - 5.5, c.height - 2.5);\r\n }\r\n return ctx;\r\n }\r\n\r\n /**\r\n * Load image from URL and resolve img element.\r\n * @param {string} url\r\n * @returns {Promise<HTMLImageElement>}\r\n */\r\n load_image(url) {\r\n return new Promise(function (resolve, reject) {\r\n let img = new Image();\r\n img.onload = function () {\r\n resolve(img);\r\n };\r\n img.onerror = reject;\r\n img.src = url;\r\n });\r\n }\r\n\r\n /**\r\n * Trigger download of canvas content as PNG.\r\n * @param {HTMLCanvasElement} c\r\n */\r\n download(c) {\r\n var name = (this.options.filename || this.jm.mind.name) + '.png';\r\n\r\n if (navigator.msSaveBlob && !!c.msToBlob) {\r\n var blob = c.msToBlob();\r\n navigator.msSaveBlob(blob, name);\r\n } else {\r\n var blob_url = c.toDataURL();\r\n var anchor = $.c('a');\r\n if ('download' in anchor) {\r\n anchor.style.visibility = 'hidden';\r\n anchor.href = blob_url;\r\n anchor.download = name;\r\n $.d.body.appendChild(anchor);\r\n var evt = $.d.createEvent('MouseEvents');\r\n evt.initEvent('click', true, true);\r\n anchor.dispatchEvent(evt);\r\n $.d.body.removeChild(anchor);\r\n } else {\r\n location.href = blob_url;\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Screenshot plugin registration.\r\n * @type {import('../jsmind.plugin.js').Plugin<Partial<ScreenshotOptions>>}\r\n */\r\nexport const screenshot_plugin = new jsMind.plugin('screenshot', function (jm, options) {\r\n var jmss = new JmScreenshot(jm, options);\r\n jm.screenshot = jmss;\r\n jm.shoot = function () {\r\n jmss.shoot();\r\n };\r\n});\r\n\r\njsMind.register_plugin(screenshot_plugin);\r\n\r\nexport default JmScreenshot;\r\n"],"names":["jsMind","Error","domtoimage","$","DEFAULT_OPTIONS","filename","watermark","left","w","location","right","background","JmScreenshot","constructor","jm","options","opts","util","json","merge","this","version","dpr","view","device_pixel_ratio","shoot","c","create_canvas","ctx","getContext","scale","Promise","resolve","then","draw_background","draw_lines","draw_nodes","draw_watermark","download","clear","size","h","width","height","style","visibility","e_panel","appendChild","parentNode","removeChild","_","bg","fillStyle","fillRect","bind","graph","copy_to","toSvg","e_nodes","zoom","load_image","img","drawImage","textBaseline","font","textAlign","fillText","url","reject","Image","onload","onerror","src","name","mind","navigator","msSaveBlob","msToBlob","blob","blob_url","toDataURL","anchor","href","d","body","evt","createEvent","initEvent","dispatchEvent","screenshot_plugin","plugin","jmss","screenshot","register_plugin"],"mappings":"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"}
package/package.json CHANGED
@@ -1,111 +1,111 @@
1
- {
2
- "name": "@umbraci/jsmind",
3
- "version": "0.10.12",
4
- "description": "jsMind is a pure javascript library for mindmap, it base on html5 canvas. jsMind was released under BSD license, you can embed it in any project, if only you observe the license.",
5
- "main": "lib/jsmind.js",
6
- "module": "es/jsmind.js",
7
- "unpkg": "dist/jsmind.js",
8
- "jsdelivr": "dist/jsmind.js",
9
- "types": "types/generated/index.d.ts",
10
- "exports": {
11
- ".": {
12
- "import": "./es/jsmind.js",
13
- "require": "./lib/jsmind.js",
14
- "types": "./types/generated/index.d.ts"
15
- },
16
- "./draggable-node": {
17
- "import": "./es/jsmind.draggable-node.js",
18
- "require": "./lib/jsmind.draggable-node.js",
19
- "types": "./types/generated/plugins/jsmind.draggable-node.d.ts"
20
- },
21
- "./screenshot": {
22
- "import": "./es/jsmind.screenshot.js",
23
- "require": "./lib/jsmind.screenshot.js",
24
- "types": "./types/generated/plugins/jsmind.screenshot.d.ts"
25
- },
26
- "./multiline-text": {
27
- "import": "./es/jsmind.multiline-text.js",
28
- "require": "./lib/jsmind.multiline-text.js",
29
- "types": "./types/generated/plugins/jsmind.multiline-text.d.ts"
30
- },
31
- "./history": {
32
- "import": "./es/jsmind.history.js",
33
- "require": "./lib/jsmind.history.js",
34
- "types": "./types/generated/plugins/history/jsmind.history.d.ts"
35
- },
36
- "./style/jsmind.css": "./style/jsmind.css"
37
- },
38
- "directories": {
39
- "doc": "docs",
40
- "example": "example"
41
- },
42
- "files": [
43
- "es",
44
- "lib",
45
- "dist",
46
- "style",
47
- "types",
48
- "LICENSE",
49
- "README.md"
50
- ],
51
- "scripts": {
52
- "server": "http-server",
53
- "build": "rollup -c .config/rollup.config.js",
54
- "build-types": "npx -p typescript tsc -p types/tsconfig.declaration.json",
55
- "test": "NODE_OPTIONS=--experimental-vm-modules jest tests/unit",
56
- "test-es6": "NODE_OPTIONS=--experimental-vm-modules jest tests/unit",
57
- "test-types": "NODE_OPTIONS=--experimental-vm-modules jest tests/types",
58
- "build-test-types": "npm run build-types && npm run test-types",
59
- "test-legacy": "jest tests/legacy",
60
- "format": "prettier --config .config/prettierrc.json --ignore-path .config/prettierignore --write .",
61
- "format-check": "prettier --config .config/prettierrc.json --ignore-path .config/prettierignore --check ."
62
- },
63
- "repository": {
64
- "type": "git",
65
- "url": "git+https://github.com/UmbraCi/jsmind.git"
66
- },
67
- "author": {
68
- "name": "UmbraCi"
69
- },
70
- "license": "BSD-3-Clause",
71
- "bugs": {
72
- "url": "https://github.com/UmbraCi/jsmind/issues"
73
- },
74
- "homepage": "https://github.com/UmbraCi/jsmind#readme",
75
- "keywords": [
76
- "jsmind",
77
- "mindmap"
78
- ],
79
- "maintainers": [
80
- {
81
- "name": "UmbraCi"
82
- }
83
- ],
84
- "devDependencies": {
85
- "@rollup/plugin-commonjs": "^28.0.8",
86
- "@rollup/plugin-node-resolve": "^16.0.3",
87
- "@rollup/plugin-terser": "^0.4.4",
88
- "http-server": "^14.1.1",
89
- "jest": "^28.1.0",
90
- "jest-environment-jsdom": "^28.1.0",
91
- "prettier": "2.6.2",
92
- "rollup": "2.79.2",
93
- "rollup-plugin-cleanup": "^3.2.1",
94
- "tsd-jsdoc": "^2.5.0",
95
- "typescript": "^5.9.2"
96
- },
97
- "jest": {
98
- "verbose": true,
99
- "testEnvironment": "jsdom"
100
- },
101
- "sideEffects": [
102
- "./es6/*",
103
- "./es/*.js",
104
- "./lib/*.js",
105
- "./dist/*.js",
106
- "./style/*.css"
107
- ],
108
- "dependencies": {
109
- "fast-equals": "^5.3.2"
110
- }
111
- }
1
+ {
2
+ "name": "@umbraci/jsmind",
3
+ "version": "0.10.13",
4
+ "description": "jsMind is a pure javascript library for mindmap, it base on html5 canvas. jsMind was released under BSD license, you can embed it in any project, if only you observe the license.",
5
+ "main": "lib/jsmind.js",
6
+ "module": "es/jsmind.js",
7
+ "unpkg": "dist/jsmind.js",
8
+ "jsdelivr": "dist/jsmind.js",
9
+ "types": "types/generated/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": "./es/jsmind.js",
13
+ "require": "./lib/jsmind.js",
14
+ "types": "./types/generated/index.d.ts"
15
+ },
16
+ "./draggable-node": {
17
+ "import": "./es/jsmind.draggable-node.js",
18
+ "require": "./lib/jsmind.draggable-node.js",
19
+ "types": "./types/generated/plugins/jsmind.draggable-node.d.ts"
20
+ },
21
+ "./screenshot": {
22
+ "import": "./es/jsmind.screenshot.js",
23
+ "require": "./lib/jsmind.screenshot.js",
24
+ "types": "./types/generated/plugins/jsmind.screenshot.d.ts"
25
+ },
26
+ "./multiline-text": {
27
+ "import": "./es/jsmind.multiline-text.js",
28
+ "require": "./lib/jsmind.multiline-text.js",
29
+ "types": "./types/generated/plugins/jsmind.multiline-text.d.ts"
30
+ },
31
+ "./history": {
32
+ "import": "./es/jsmind.history.js",
33
+ "require": "./lib/jsmind.history.js",
34
+ "types": "./types/generated/plugins/history/jsmind.history.d.ts"
35
+ },
36
+ "./style/jsmind.css": "./style/jsmind.css"
37
+ },
38
+ "directories": {
39
+ "doc": "docs",
40
+ "example": "example"
41
+ },
42
+ "files": [
43
+ "es",
44
+ "lib",
45
+ "dist",
46
+ "style",
47
+ "types",
48
+ "LICENSE",
49
+ "README.md"
50
+ ],
51
+ "scripts": {
52
+ "server": "http-server",
53
+ "build": "rollup -c .config/rollup.config.js",
54
+ "build-types": "npx -p typescript tsc -p types/tsconfig.declaration.json",
55
+ "test": "NODE_OPTIONS=--experimental-vm-modules jest tests/unit",
56
+ "test-es6": "NODE_OPTIONS=--experimental-vm-modules jest tests/unit",
57
+ "test-types": "NODE_OPTIONS=--experimental-vm-modules jest tests/types",
58
+ "build-test-types": "npm run build-types && npm run test-types",
59
+ "test-legacy": "jest tests/legacy",
60
+ "format": "prettier --config .config/prettierrc.json --ignore-path .config/prettierignore --write .",
61
+ "format-check": "prettier --config .config/prettierrc.json --ignore-path .config/prettierignore --check ."
62
+ },
63
+ "repository": {
64
+ "type": "git",
65
+ "url": "git+https://github.com/UmbraCi/jsmind.git"
66
+ },
67
+ "author": {
68
+ "name": "UmbraCi"
69
+ },
70
+ "license": "BSD-3-Clause",
71
+ "bugs": {
72
+ "url": "https://github.com/UmbraCi/jsmind/issues"
73
+ },
74
+ "homepage": "https://github.com/UmbraCi/jsmind#readme",
75
+ "keywords": [
76
+ "jsmind",
77
+ "mindmap"
78
+ ],
79
+ "maintainers": [
80
+ {
81
+ "name": "UmbraCi"
82
+ }
83
+ ],
84
+ "devDependencies": {
85
+ "@rollup/plugin-commonjs": "^28.0.8",
86
+ "@rollup/plugin-node-resolve": "^16.0.3",
87
+ "@rollup/plugin-terser": "^0.4.4",
88
+ "http-server": "^14.1.1",
89
+ "jest": "^28.1.0",
90
+ "jest-environment-jsdom": "^28.1.0",
91
+ "prettier": "2.6.2",
92
+ "rollup": "2.79.2",
93
+ "rollup-plugin-cleanup": "^3.2.1",
94
+ "tsd-jsdoc": "^2.5.0",
95
+ "typescript": "^5.9.2"
96
+ },
97
+ "jest": {
98
+ "verbose": true,
99
+ "testEnvironment": "jsdom"
100
+ },
101
+ "sideEffects": [
102
+ "./es6/*",
103
+ "./es/*.js",
104
+ "./lib/*.js",
105
+ "./dist/*.js",
106
+ "./style/*.css"
107
+ ],
108
+ "dependencies": {
109
+ "fast-equals": "^5.3.2"
110
+ }
111
+ }