@umbraci/jsmind 0.9.8 → 0.9.9

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 (39) hide show
  1. package/dist/jsmind.draggable-node.js +9 -0
  2. package/dist/jsmind.draggable-node.js.map +1 -0
  3. package/es/jsmind.draggable-node.js +9 -0
  4. package/es/jsmind.draggable-node.js.map +1 -0
  5. package/{es6/jsmind.esm.js → es/jsmind.js} +1 -1
  6. package/es/jsmind.js.map +1 -0
  7. package/{es6/jsmind.multiline-text.esm.js → es/jsmind.multiline-text.js} +1 -1
  8. package/es/jsmind.multiline-text.js.map +1 -0
  9. package/{es6/jsmind.screenshot.esm.js → es/jsmind.screenshot.js} +1 -1
  10. package/es/jsmind.screenshot.js.map +1 -0
  11. package/lib/jsmind.draggable-node.js +9 -0
  12. package/lib/jsmind.draggable-node.js.map +1 -0
  13. package/lib/jsmind.js +9 -0
  14. package/lib/jsmind.js.map +1 -0
  15. package/lib/jsmind.multiline-text.js +9 -0
  16. package/lib/jsmind.multiline-text.js.map +1 -0
  17. package/lib/jsmind.screenshot.js +9 -0
  18. package/lib/jsmind.screenshot.js.map +1 -0
  19. package/package.json +16 -11
  20. package/types/generated/jsmind.common.d.ts +2 -2
  21. package/types/generated/jsmind.d.ts +40 -1
  22. package/types/generated/jsmind.dom.d.ts +2 -2
  23. package/types/generated/jsmind.enhanced-plugin.d.ts +103 -0
  24. package/types/generated/plugins/jsmind.multiline-text-v2.d.ts +58 -0
  25. package/es6/README-en.md +0 -37
  26. package/es6/README.md +0 -34
  27. package/es6/jsmind.draggable-node.esm.js +0 -9
  28. package/es6/jsmind.draggable-node.esm.js.map +0 -1
  29. package/es6/jsmind.draggable-node.js +0 -9
  30. package/es6/jsmind.draggable-node.js.map +0 -1
  31. package/es6/jsmind.esm.js.map +0 -1
  32. package/es6/jsmind.multiline-text.esm.js.map +0 -1
  33. package/es6/jsmind.screenshot.esm.js.map +0 -1
  34. /package/{es6 → dist}/jsmind.js +0 -0
  35. /package/{es6 → dist}/jsmind.js.map +0 -0
  36. /package/{es6 → dist}/jsmind.multiline-text.js +0 -0
  37. /package/{es6 → dist}/jsmind.multiline-text.js.map +0 -0
  38. /package/{es6 → dist}/jsmind.screenshot.js +0 -0
  39. /package/{es6 → dist}/jsmind.screenshot.js.map +0 -0
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @license BSD-3-Clause
3
+ * @copyright 2014-2025 hizzgdev@163.com
4
+ *
5
+ * Project Home:
6
+ * https://github.com/hizzgdev/jsmind/
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;
9
+ //# sourceMappingURL=jsmind.multiline-text.js.map
@@ -0,0 +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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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @license BSD-3-Clause
3
+ * @copyright 2014-2025 hizzgdev@163.com
4
+ *
5
+ * Project Home:
6
+ * https://github.com/hizzgdev/jsmind/
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;
9
+ //# sourceMappingURL=jsmind.screenshot.js.map
@@ -0,0 +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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"}
package/package.json CHANGED
@@ -1,28 +1,31 @@
1
1
  {
2
2
  "name": "@umbraci/jsmind",
3
- "version": "0.9.8",
3
+ "version": "0.9.9",
4
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": "es6/jsmind.js",
5
+ "main": "lib/jsmind.js",
6
+ "module": "es/jsmind.js",
7
+ "unpkg": "dist/jsmind.js",
8
+ "jsdelivr": "dist/jsmind.js",
6
9
  "types": "types/generated/index.d.ts",
7
10
  "exports": {
8
11
  ".": {
9
- "import": "./es6/jsmind.esm.js",
10
- "require": "./es6/jsmind.js",
12
+ "import": "./es/jsmind.js",
13
+ "require": "./lib/jsmind.js",
11
14
  "types": "./types/generated/index.d.ts"
12
15
  },
13
16
  "./draggable-node": {
14
- "import": "./es6/jsmind.draggable-node.esm.js",
15
- "require": "./es6/jsmind.draggable-node.js",
17
+ "import": "./es/jsmind.draggable-node.js",
18
+ "require": "./lib/jsmind.draggable-node.js",
16
19
  "types": "./types/generated/plugins/jsmind.draggable-node.d.ts"
17
20
  },
18
21
  "./screenshot": {
19
- "import": "./es6/jsmind.screenshot.esm.js",
20
- "require": "./es6/jsmind.screenshot.js",
22
+ "import": "./es/jsmind.screenshot.js",
23
+ "require": "./lib/jsmind.screenshot.js",
21
24
  "types": "./types/generated/plugins/jsmind.screenshot.d.ts"
22
25
  },
23
26
  "./multiline-text": {
24
- "import": "./es6/jsmind.multiline-text.esm.js",
25
- "require": "./es6/jsmind.multiline-text.js",
27
+ "import": "./es/jsmind.multiline-text.js",
28
+ "require": "./lib/jsmind.multiline-text.js",
26
29
  "types": "./types/generated/plugins/jsmind.multiline-text.d.ts"
27
30
  },
28
31
  "./style/jsmind.css": "./style/jsmind.css"
@@ -32,7 +35,9 @@
32
35
  "example": "example"
33
36
  },
34
37
  "files": [
35
- "es6",
38
+ "es",
39
+ "lib",
40
+ "dist",
36
41
  "style",
37
42
  "types",
38
43
  "LICENSE",
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * @license BSD
3
- * @copyright 2014-2025 hizzgdev@163.com
3
+ * @copyright 2014-2025 UmbraCi
4
4
  *
5
5
  * Project Home:
6
- * https://github.com/hizzgdev/jsmind/
6
+ * https://github.com/UmbraCi/jsmind/
7
7
  */
8
8
  /**
9
9
  * Library version string.
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * jsMind runtime: orchestrates data/layout/view/shortcut and exposes public API.
7
7
  */
8
- export default class jsMind {
8
+ declare class jsMind {
9
9
  static mind: typeof Mind;
10
10
  static node: typeof Node;
11
11
  static direction: import("./jsmind.common.js").DirectionType;
@@ -44,6 +44,22 @@ export default class jsMind {
44
44
  is_empty: (s?: string) => boolean;
45
45
  };
46
46
  };
47
+ static enhanced_plugin: typeof EnhancedPlugin;
48
+ /** @type {Array<import('./jsmind.enhanced-plugin.js').PluginDescriptor>} */
49
+ static enhancedPluginList: Array<import("./jsmind.enhanced-plugin.js").PluginDescriptor>;
50
+ /**
51
+ * Register an enhanced plugin
52
+ * @param {typeof EnhancedPlugin} PluginClass - Plugin class
53
+ * @param {object} [options={}] - Plugin options
54
+ * @returns {typeof jsMind}
55
+ */
56
+ static usePlugin(PluginClass: typeof EnhancedPlugin, options?: object): typeof jsMind;
57
+ /**
58
+ * Check if an enhanced plugin is registered
59
+ * @param {typeof EnhancedPlugin} PluginClass - Plugin class
60
+ * @returns {boolean}
61
+ */
62
+ static hasEnhancedPlugin(PluginClass: typeof EnhancedPlugin): boolean;
47
63
  /**
48
64
  * Deprecated: static show constructor helper.
49
65
  * @param {import('./jsmind.option.js').JsMindRuntimeOptions} options
@@ -64,6 +80,7 @@ export default class jsMind {
64
80
  event_handles: Array<(type: number, data: EventData) => void>;
65
81
  /** Initialize sub-systems and plugins. */
66
82
  init(): void;
83
+ enhancedPluginManager: EnhancedPluginManager;
67
84
  data: DataProvider;
68
85
  layout: LayoutProvider;
69
86
  view: ViewProvider;
@@ -347,7 +364,26 @@ export default class jsMind {
347
364
  invoke_event_handle(type: number, data: EventData): void;
348
365
  /** @param {number} type @param {EventData} data */
349
366
  _invoke_event_handle(type: number, data: EventData): void;
367
+ /**
368
+ * Remove an enhanced plugin
369
+ * @param {typeof EnhancedPlugin} PluginClass - Plugin class
370
+ */
371
+ removePlugin(PluginClass: typeof EnhancedPlugin): void;
372
+ removePlugin(PluginClass: typeof EnhancedPlugin): void;
373
+ /**
374
+ * Get an enhanced plugin instance
375
+ * @param {string} instanceName - Plugin instance name
376
+ * @returns {EnhancedPlugin | undefined}
377
+ */
378
+ getPlugin(instanceName: string): EnhancedPlugin | undefined;
379
+ getPlugin(instanceName: string): EnhancedPlugin | undefined;
380
+ /**
381
+ * Destroy the jsMind instance and clean up resources
382
+ */
383
+ destroy(): void;
384
+ destroy(): void;
350
385
  }
386
+ export default jsMind;
351
387
  /**
352
388
  * Event callback payload
353
389
  */
@@ -356,11 +392,14 @@ export type EventData = {
356
392
  data?: unknown[];
357
393
  node?: string;
358
394
  };
395
+ export namespace jsMind { }
359
396
  import { Mind } from './jsmind.mind.js';
397
+ import { EnhancedPluginManager } from './jsmind.enhanced-plugin.js';
360
398
  import { DataProvider } from './jsmind.data_provider.js';
361
399
  import { LayoutProvider } from './jsmind.layout_provider.js';
362
400
  import { ViewProvider } from './jsmind.view_provider.js';
363
401
  import { ShortcutProvider } from './jsmind.shortcut_provider.js';
402
+ import { EnhancedPlugin } from './jsmind.enhanced-plugin.js';
364
403
  import { Node } from './jsmind.node.js';
365
404
  import { Plugin } from './jsmind.plugin.js';
366
405
  import { register as _register_plugin } from './jsmind.plugin.js';
@@ -1,10 +1,10 @@
1
1
  export const $: Dom;
2
2
  /**
3
3
  * @license BSD
4
- * @copyright 2014-2025 hizzgdev@163.com
4
+ * @copyright 2014-2025 UmbraCi
5
5
  *
6
6
  * Project Home:
7
- * https://github.com/hizzgdev/jsmind/
7
+ * https://github.com/UmbraCi/jsmind/
8
8
  */
9
9
  /**
10
10
  * Lightweight DOM helpers bound to a window.
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Enhanced Plugin Manager
3
+ * Manages the lifecycle of enhanced plugins with synchronous initialization,
4
+ * preload support, and lifecycle hooks.
5
+ */
6
+ export class EnhancedPluginManager {
7
+ /**
8
+ * @param {import('./jsmind.js').default} jm - jsMind instance
9
+ */
10
+ constructor(jm: import("./jsmind.js").default);
11
+ jm: import("./jsmind.js").default;
12
+ /** @type {Map<string, EnhancedPlugin>} */
13
+ plugins: Map<string, EnhancedPlugin>;
14
+ /**
15
+ * Initialize preload plugins (before core modules)
16
+ */
17
+ initPreloadPlugins(): void;
18
+ /**
19
+ * Initialize normal plugins (after core modules)
20
+ */
21
+ initNormalPlugins(): void;
22
+ /**
23
+ * Internal method: Initialize a single plugin
24
+ * @param {PluginDescriptor} descriptor
25
+ * @private
26
+ */
27
+ private _initPlugin;
28
+ /**
29
+ * Remove a plugin
30
+ * @param {typeof EnhancedPlugin} PluginClass
31
+ */
32
+ removePlugin(PluginClass: typeof EnhancedPlugin): void;
33
+ /**
34
+ * Destroy all plugins
35
+ */
36
+ destroyAllPlugins(): void;
37
+ /**
38
+ * Get plugin instance by name
39
+ * @param {string} instanceName
40
+ * @returns {EnhancedPlugin | undefined}
41
+ */
42
+ getPlugin(instanceName: string): EnhancedPlugin | undefined;
43
+ }
44
+ /**
45
+ * Enhanced Plugin Base Class
46
+ * Provides standard interface for enhanced plugins
47
+ */
48
+ export class EnhancedPlugin {
49
+ /**
50
+ * Plugin instance name (must be defined by subclass)
51
+ * @type {string}
52
+ */
53
+ static instanceName: string;
54
+ /**
55
+ * Whether to initialize before core modules
56
+ * @type {boolean}
57
+ */
58
+ static preload: boolean;
59
+ /**
60
+ * @param {{ jm: import('./jsmind.js').default, pluginOpt: object }} params
61
+ */
62
+ constructor({ jm, pluginOpt }: {
63
+ jm: import("./jsmind.js").default;
64
+ pluginOpt: object;
65
+ });
66
+ jm: import("./jsmind.js").default;
67
+ options: any;
68
+ /**
69
+ * Called before plugin is removed
70
+ * Override this method to clean up resources
71
+ */
72
+ beforePluginRemove(): void;
73
+ /**
74
+ * Called before jsMind instance is destroyed
75
+ * Override this method to clean up resources
76
+ */
77
+ beforePluginDestroy(): void;
78
+ }
79
+ /**
80
+ * Plugin descriptor
81
+ */
82
+ export type PluginDescriptor = {
83
+ /**
84
+ * - Plugin class
85
+ */
86
+ PluginClass: typeof EnhancedPlugin;
87
+ /**
88
+ * - Plugin instance name
89
+ */
90
+ instanceName: string;
91
+ /**
92
+ * - Whether to preload
93
+ */
94
+ preload: boolean;
95
+ /**
96
+ * - Plugin options
97
+ */
98
+ pluginOpt: object;
99
+ /**
100
+ * - Plugin instance (after initialization)
101
+ */
102
+ instance: EnhancedPlugin | null;
103
+ };
@@ -0,0 +1,58 @@
1
+ export default MultilineTextV2;
2
+ /**
3
+ * MultilineTextV2 Plugin
4
+ * Enhanced multiline text plugin using the new plugin system
5
+ */
6
+ declare class MultilineTextV2 extends EnhancedPlugin {
7
+ /**
8
+ * @param {{ jm: import('../jsmind.js').default, pluginOpt: object }} params
9
+ */
10
+ constructor({ jm, pluginOpt }: {
11
+ jm: import("../jsmind.js").default;
12
+ pluginOpt: object;
13
+ });
14
+ options: any;
15
+ editing_node: import("../jsmind.node.js").Node;
16
+ multiline_editor: HTMLElement;
17
+ _original_custom_render: Function | ((jm: import("../jsmind.js").default, ele: HTMLElement, node: import("../jsmind.node.js").Node) => void);
18
+ _original_edit_node_begin: any;
19
+ _original_edit_node_end: any;
20
+ /**
21
+ * Setup custom rendering in options (for preload plugins)
22
+ */
23
+ setupCustomRenderInOptions(): void;
24
+ /**
25
+ * Setup custom rendering for multiline text (for normal plugins)
26
+ */
27
+ setupCustomRender(): void;
28
+ /**
29
+ * Setup edit handlers (common for both preload and normal plugins)
30
+ */
31
+ setupEditHandlers(): void;
32
+ /**
33
+ * Re-render all nodes to apply multiline styles and recalculate sizes.
34
+ * This is necessary because node sizes are calculated before custom styles are applied.
35
+ * @private
36
+ */
37
+ private _rerender_all_nodes;
38
+ /**
39
+ * Begin editing a node
40
+ * @param {import('../jsmind.node.js').Node} node
41
+ */
42
+ edit_node_begin(node: import("../jsmind.node.js").Node): void;
43
+ /**
44
+ * End editing and save changes.
45
+ */
46
+ edit_node_end(): void;
47
+ /**
48
+ * Cancel editing without saving changes.
49
+ */
50
+ cancel_editing(): void;
51
+ /**
52
+ * Clean up editor and reset state.
53
+ * @private
54
+ */
55
+ private _cleanup_editor;
56
+ }
57
+ import { EnhancedPlugin } from '../jsmind.enhanced-plugin.js';
58
+ import jsMind from '../jsmind.js';
package/es6/README-en.md DELETED
@@ -1,37 +0,0 @@
1
- # jsMind ES6 Version
2
-
3
- [[中文](README.md)] | [English]
4
-
5
- jsMind is now written in ES6 code, the source code is in `/src`, and the dist directory is `/es6`.
6
-
7
-
8
- ### Compatibility
9
-
10
- All features in the JS version are fully compatible in the ES6 version.
11
-
12
- ### Migration
13
-
14
- If you use `jsMind` via `NPM`, no migration is required, we just changed the `main` file to `es6/jsmind.js`
15
-
16
- If you reference `jsMind` from CDN, the only thing you need to do is change the url from `js/*.js` to `es6/*.js`.
17
-
18
- E.g.
19
-
20
- ```html
21
- <!-- before -->
22
- <script type="text/javascript" src="//cdn.jsdelivr.net/npm/jsmind/js/jsmind.js"></script>
23
-
24
- <!-- after -->
25
- <script type="text/javascript" src="//cdn.jsdelivr.net/npm/jsmind/es6/jsmind.js"></script>
26
- ```
27
-
28
- ### Deprecation
29
-
30
- The legacy version of jsmind and plugins have been moved to `/js-legacy`. we will no longer update them, and will remove them one day in the future. It's recommended that everyone use the latest version to follow continuous feature updates and bug fixes.
31
-
32
- ### Local build
33
-
34
- You probably notice that there is no `js` files or `es6` files in the directory `/es6`. Yes, we publish the dist file to `NPM` but don't store them in the repo.
35
-
36
- You can download the resources from CDN, or build them locally by running `npm run build` in the root dir of the project. Read [development doc](../docs/en/5.development.md) to get the detail about code building.
37
-
package/es6/README.md DELETED
@@ -1,34 +0,0 @@
1
- # jsMind ES6 Version
2
-
3
- [中文] | [[English](README-en.md)]
4
-
5
- jsMind 使用 ES6 编写,源代码位于 `/src`,构建目录为 `/es6`。
6
-
7
-
8
- ### 兼容性
9
-
10
- 之前 JS 版本里的所有功能,在 ES6 的版本中都是兼容的。
11
-
12
- ### 迁移到新版
13
-
14
- 如果你是通过 `NPM` 引用的 `jsMind`,则无须手动迁移,我们只是在 `project.json` 里将 `main` 修改成了 `es6/jsmind.js` 。
15
-
16
- 如果你是通过 CDN 引用 `jsMind` 的话,你仅仅需要把 url 从 `js/*.js` 改成 `es6/*.js` 。 如:
17
-
18
- ```html
19
- <!-- 修改前 -->
20
- <script type="text/javascript" src="//cdn.jsdelivr.net/npm/jsmind/js/jsmind.js"></script>
21
-
22
- <!-- 修改后 -->
23
- <script type="text/javascript" src="//cdn.jsdelivr.net/npm/jsmind/es6/jsmind.js"></script>
24
- ```
25
-
26
- ### 老版本下线
27
-
28
- 之前的版本被移动到了 `/js-legacy` 目录里,我们将不再升级它,并会在未来的某个时间里删除此版本,建议所有人使用最新版本以获得最新的功能及bug修复。
29
-
30
- ### 本地构建
31
-
32
- 你可能注意到了,在 `es6` 这个目录里没有任何 `js` 或 `es` 文件。是的,构建的文件仅会被包含在 `NPM` 里,但并不会保留在代码库中。
33
-
34
- 你可以从 CDN 上下载这些文件,也可以在你本地构建,只需在项目根目录里运行 `npm run build` 即可。更详细的介绍可参考[贡献代码指南](../docs/zh/5.development.md)里的相关内容。
@@ -1,9 +0,0 @@
1
- /**
2
- * @license BSD-3-Clause
3
- * @copyright 2014-2025 hizzgdev@163.com
4
- *
5
- * Project Home:
6
- * https://github.com/hizzgdev/jsmind/
7
- */
8
- import t from"@umbraci/jsmind";if(!t)throw new Error("jsMind is not defined");const e=t.$,i="getSelection"in e.w?function(){e.w.getSelection().removeAllRanges()}:function(){e.d.selection.empty()},s={line_width:5,line_color:"rgba(0,0,0,0.3)",line_color_invalid:"rgba(255,51,51,0.6)",lookup_delay:200,lookup_interval:100,scrolling_trigger_width:20,scrolling_step_length:10,shadow_node_class_name:"jsmind-draggable-shadow-node"};class o{constructor(e,i){var o={};t.util.json.merge(o,s),t.util.json.merge(o,i),this.version="0.4.0",this.jm=e,this.options=o,this.e_canvas=null,this.canvas_ctx=null,this.shadow=null,this.shadow_p_x=0,this.shadow_p_y=0,this.shadow_w=0,this.shadow_h=0,this.active_node=null,this.target_node=null,this.target_direct=null,this.client_w=0,this.client_h=0,this.offset_x=0,this.offset_y=0,this.hlookup_delay=0,this.hlookup_timer=0,this.capture=!1,this.moved=!1,this.canvas_draggable=e.get_view_draggable(),this.view_panel=e.view.e_panel,this.view_panel_rect=null}init(){this.create_canvas(),this.create_shadow(),this.event_bind()}resize(){this.jm.view.e_nodes.appendChild(this.shadow),this.e_canvas.width=this.jm.view.size.w,this.e_canvas.height=this.jm.view.size.h}create_canvas(){var t=e.c("canvas");this.jm.view.e_panel.appendChild(t);var i=t.getContext("2d");this.e_canvas=t,this.canvas_ctx=i}create_shadow(){var t=e.c("jmnode");t.style.visibility="hidden",t.style.zIndex="3",t.style.cursor="move",t.style.opacity="0.7",t.className=this.options.shadow_node_class_name,this.shadow=t}reset_shadow(t){var e=this.shadow.style;this.shadow.innerHTML=t.innerHTML,e.left=t.style.left,e.top=t.style.top,e.width=t.style.width,e.height=t.style.height,e.backgroundImage=t.style.backgroundImage,e.backgroundSize=t.style.backgroundSize,e.transform=t.style.transform,this.shadow_w=this.shadow.clientWidth,this.shadow_h=this.shadow.clientHeight}show_shadow(){this.moved||(this.shadow.style.visibility="visible")}hide_shadow(){this.shadow.style.visibility="hidden"}magnet_shadow(t,e,i){this.canvas_ctx.lineWidth=this.options.line_width,this.canvas_ctx.strokeStyle=i?this.options.line_color_invalid:this.options.line_color,this.canvas_ctx.lineCap="round",this.clear_lines(),this.canvas_lineto(t.x,t.y,e.x,e.y)}clear_lines(){this.canvas_ctx.clearRect(0,0,this.jm.view.size.w,this.jm.view.size.h)}canvas_lineto(t,e,i,s){this.canvas_ctx.beginPath(),this.canvas_ctx.moveTo(t,e),this.canvas_ctx.lineTo(i,s),this.canvas_ctx.stroke()}event_bind(){var t=this,i=this.jm.view.container;e.on(i,"mousedown",function(e){0===e.button&&t.dragstart.call(t,e)}),e.on(i,"mousemove",function(e){0===e.movementX&&0===e.movementY||t.drag.call(t,e)}),e.on(i,"mouseup",function(e){t.dragend.call(t,e)}),e.on(i,"touchstart",function(e){t.dragstart.call(t,e)}),e.on(i,"touchmove",function(e){t.drag.call(t,e)}),e.on(i,"touchend",function(e){t.dragend.call(t,e)})}dragstart(t){if(this.jm.get_editable()&&!this.capture){var i=this.jm.view;if(!i.is_editing()){this.active_node=null,this.view_draggable=this.jm.get_view_draggable();var s=this.find_node_element(t.target);if(s){this.view_draggable&&this.jm.disable_view_draggable();var o=i.get_binded_nodeid(s);if(o){var n=this.jm.get_node(o);if(!n.isroot){this.reset_shadow(s),this.view_panel_rect=this.view_panel.getBoundingClientRect(),this.active_node=n,this.offset_x=(t.clientX||t.touches[0].clientX)/i.zoom_current-s.offsetLeft,this.offset_y=(t.clientY||t.touches[0].clientY)/i.zoom_current-s.offsetTop,this.client_hw=Math.floor(s.clientWidth/2),this.client_hh=Math.floor(s.clientHeight/2),0!=this.hlookup_delay&&e.w.clearTimeout(this.hlookup_delay),0!=this.hlookup_timer&&e.w.clearInterval(this.hlookup_timer);var h=this;this.hlookup_delay=e.w.setTimeout(function(){h.hlookup_delay=0,h.hlookup_timer=e.w.setInterval(function(){h.lookup_target_node.call(h)},h.options.lookup_interval)},this.options.lookup_delay),h.capture=!0}}}}}}drag(t){if(this.jm.get_editable()&&this.capture){t.preventDefault(),this.show_shadow(),this.moved=!0,i();var e=this.jm.view,s=(t.clientX||t.touches[0].clientX)/e.zoom_current-this.offset_x,o=(t.clientY||t.touches[0].clientY)/e.zoom_current-this.offset_y;t.clientY-this.view_panel_rect.top<this.options.scrolling_trigger_width&&this.view_panel.scrollTop>this.options.scrolling_step_length?(this.view_panel.scrollBy(0,-this.options.scrolling_step_length),this.offset_y+=this.options.scrolling_step_length/e.zoom_current):this.view_panel_rect.bottom-t.clientY<this.options.scrolling_trigger_width&&this.view_panel.scrollTop<this.view_panel.scrollHeight-this.view_panel_rect.height-this.options.scrolling_step_length&&(this.view_panel.scrollBy(0,this.options.scrolling_step_length),this.offset_y-=this.options.scrolling_step_length/e.zoom_current),t.clientX-this.view_panel_rect.left<this.options.scrolling_trigger_width&&this.view_panel.scrollLeft>this.options.scrolling_step_length?(this.view_panel.scrollBy(-this.options.scrolling_step_length,0),this.offset_x+=this.options.scrolling_step_length/e.zoom_current):this.view_panel_rect.right-t.clientX<this.options.scrolling_trigger_width&&this.view_panel.scrollLeft<this.view_panel.scrollWidth-this.view_panel_rect.width-this.options.scrolling_step_length&&(this.view_panel.scrollBy(this.options.scrolling_step_length,0),this.offset_x-=this.options.scrolling_step_length/e.zoom_current),this.shadow.style.left=s+"px",this.shadow.style.top=o+"px",i()}}dragend(t){if(this.jm.get_editable()){if(this.view_draggable&&this.jm.enable_view_draggable(),this.capture){if(0!=this.hlookup_delay&&(e.w.clearTimeout(this.hlookup_delay),this.hlookup_delay=0,this.clear_lines()),0!=this.hlookup_timer&&(e.w.clearInterval(this.hlookup_timer),this.hlookup_timer=0,this.clear_lines()),this.moved){var i=this.active_node,s=this.target_node,o=this.target_direct;this.move_node(i,s,o)}this.hide_shadow()}this.view_panel_rect=null,this.moved=!1,this.capture=!1}}find_node_element(t){return t===this.jm.view.e_nodes||t===this.jm.view.e_panel||t===this.jm.view.container?null:"jmnode"===t.tagName.toLowerCase()?t:this.find_node_element(t.parentNode)}lookup_target_node(){let e=this.shadow.offsetLeft,i=this.shadow.offsetTop;if(e===this.shadow_p_x&&i===this.shadow_p_y)return;this.shadow_p_x=e,this.shadow_p_y=i;let s=this.shadow_p_x+this.shadow_w/2>=this.get_root_x()?t.direction.right:t.direction.left,o=this.lookup_overlapping_node_parent(s)||this.lookup_close_node(s);if(o){let e=this.calc_point_of_node(o,s),i=t.node.inherited(this.active_node,o);this.magnet_shadow(e.sp,e.np,i),this.target_node=o,this.target_direct=s}}get_root_x(){let t=this.jm.get_root(),e=t.get_location(),i=t.get_size();return e.x+i.w/2}lookup_overlapping_node_parent(t){let e=this.shadow.getBoundingClientRect(),i=e.x+e.width*(1-t)/2,s=(this.jm.options.layout.hspace+this.jm.options.layout.pspace)*t,o=e.height,n=[[i,e.y],[i,e.y+o/2],[i,e.y+o],[i+s/2,e.y],[i+s/2,e.y+o/2],[i+s/2,e.y+o],[i+s,e.y],[i+s,e.y+o/2],[i+s,e.y+o]];for(const t of n){let e=this.lookup_node_parent_by_location(t[0],t[1]);if(e)return e}}lookup_node_parent_by_location(t,i){return e.d.elementsFromPoint(t,i).filter(t=>"JMNODE"===t.tagName&&t.className!==this.options.shadow_node_class_name).map(t=>this.jm.view.get_binded_nodeid(t)).map(t=>t&&this.jm.mind.nodes[t]).map(t=>t&&t.parent).find(t=>t)}lookup_close_node(t){return Object.values(this.jm.mind.nodes).filter(e=>e.direction==t||e.isroot).filter(t=>this.jm.layout.is_visible(t)).filter(e=>this.shadow_on_target_side(e,t)).map(e=>({node:e,distance:this.shadow_to_node(e,t)})).reduce((t,e)=>t.distance<e.distance?t:e,{node:this.jm.get_root(),distance:Number.MAX_VALUE}).node}shadow_on_target_side(e,i){return i==t.direction.right&&this.shadow_to_right_of_node(e)>0||i==t.direction.left&&this.shadow_to_left_of_node(e)>0}shadow_to_right_of_node(t){return this.shadow_p_x-t.get_location().x-t.get_size().w}shadow_to_left_of_node(t){return t.get_location().x-this.shadow_p_x-this.shadow_w}shadow_to_base_line_of_node(t){return this.shadow_p_y+this.shadow_h/2-t.get_location().y-t.get_size().h/2}shadow_to_node(e,i){return(i===t.direction.right?Math.abs(this.shadow_to_right_of_node(e)):Math.abs(this.shadow_to_left_of_node(e)))+Math.abs(this.shadow_to_base_line_of_node(e))}calc_point_of_node(t,e){let i=t.get_size(),s=t.get_location(),o=t.isroot?s.x+i.w/2:s.x+i.w*(1+e)/2+this.options.line_width*e,n=s.y+i.h/2;return{sp:{x:this.shadow_p_x+this.shadow_w*(1-e)/2-this.options.line_width*e,y:this.shadow_p_y+this.shadow_h/2},np:{x:o,y:n}}}move_node(e,i,s){var o=this.shadow.offsetTop;if(i&&e&&!t.node.inherited(e,i)){for(var n=i.children,h=n.length,_=null,l=Number.MAX_VALUE,a=null,r="_last_";h--;)if((_=n[h]).direction==s&&_.id!=e.id){var d=_.get_location().y-o;d>0&&d<l&&(l=d,a=_,r="_first_")}a&&(r=a.id),this.jm.move_node(e.id,r,i.id,s)}this.active_node=null,this.target_node=null,this.target_direct=null}jm_event_handle(e,i){e===t.event_type.resize&&this.resize()}}const n=new t.plugin("draggable_node",function(t,e){var i=new o(t,e);i.init(),t.add_event_listener(function(t,e){i.jm_event_handle.call(i,t,e)})});t.register_plugin(n);export{o as DraggableNode,o as default,n as draggable_plugin};
9
- //# sourceMappingURL=jsmind.draggable-node.esm.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"jsmind.draggable-node.esm.js","sources":["../src/plugins/jsmind.draggable-node.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';\n\nif (!jsMind) {\n throw new Error('jsMind is not defined');\n}\n\nconst $ = jsMind.$;\n\nconst clear_selection =\n 'getSelection' in $.w\n ? function () {\n $.w.getSelection().removeAllRanges();\n }\n : function () {\n $.d.selection.empty();\n };\n\n/**\n * Default options for draggable node plugin.\n * @typedef {Object} DraggableNodeOptions\n * @property {number} [line_width]\n * @property {string} [line_color]\n * @property {string} [line_color_invalid]\n * @property {number} [lookup_delay]\n * @property {number} [lookup_interval]\n * @property {number} [scrolling_trigger_width]\n * @property {number} [scrolling_step_length]\n * @property {string} [shadow_node_class_name]\n */\nconst DEFAULT_OPTIONS = {\n line_width: 5,\n line_color: 'rgba(0,0,0,0.3)',\n line_color_invalid: 'rgba(255,51,51,0.6)',\n lookup_delay: 200,\n lookup_interval: 100,\n scrolling_trigger_width: 20,\n scrolling_step_length: 10,\n shadow_node_class_name: 'jsmind-draggable-shadow-node',\n};\n\n/**\n * Draggable node plugin for jsMind.\n */\nexport class DraggableNode {\n /**\n * Create draggable node plugin instance.\n * @param {import('../jsmind.js').default} jm - jsMind instance\n * @param {Partial<DraggableNodeOptions>} 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.4.0';\n /** @type {import('../jsmind.js').default} */\n this.jm = jm;\n /** @type {DraggableNodeOptions} */\n this.options = opts;\n /** @type {HTMLCanvasElement|null} */\n this.e_canvas = null;\n /** @type {CanvasRenderingContext2D|null} */\n this.canvas_ctx = null;\n /** @type {HTMLElement|null} */\n this.shadow = null;\n /** @type {number} */\n this.shadow_p_x = 0;\n /** @type {number} */\n this.shadow_p_y = 0;\n /** @type {number} */\n this.shadow_w = 0;\n /** @type {number} */\n this.shadow_h = 0;\n /** @type {import('../jsmind.node.js').Node|null} */\n this.active_node = null;\n /** @type {import('../jsmind.node.js').Node|null} */\n this.target_node = null;\n /** @type {number|null} */\n this.target_direct = null;\n /** @type {number} */\n this.client_w = 0;\n /** @type {number} */\n this.client_h = 0;\n /** @type {number} */\n this.offset_x = 0;\n /** @type {number} */\n this.offset_y = 0;\n /** @type {number} */\n this.hlookup_delay = 0;\n /** @type {number} */\n this.hlookup_timer = 0;\n /** @type {boolean} */\n this.capture = false;\n /** @type {boolean} */\n this.moved = false;\n /** @type {boolean} */\n this.canvas_draggable = jm.get_view_draggable();\n /** @type {HTMLElement} */\n this.view_panel = jm.view.e_panel;\n /** @type {DOMRect|null} */\n this.view_panel_rect = null;\n }\n /** Initialize the draggable node plugin. */\n init() {\n this.create_canvas();\n this.create_shadow();\n this.event_bind();\n }\n /** Resize canvas and shadow elements. */\n resize() {\n this.jm.view.e_nodes.appendChild(this.shadow);\n this.e_canvas.width = this.jm.view.size.w;\n this.e_canvas.height = this.jm.view.size.h;\n }\n /** Create canvas for drawing drag lines. */\n create_canvas() {\n var c = $.c('canvas');\n this.jm.view.e_panel.appendChild(c);\n var ctx = c.getContext('2d');\n this.e_canvas = c;\n this.canvas_ctx = ctx;\n }\n create_shadow() {\n var s = $.c('jmnode');\n s.style.visibility = 'hidden';\n s.style.zIndex = '3';\n s.style.cursor = 'move';\n s.style.opacity = '0.7';\n s.className = this.options.shadow_node_class_name;\n this.shadow = s;\n }\n /**\n * Reset shadow element style and cache its size.\n * @param {HTMLElement} el - The node element to mirror as shadow\n */\n reset_shadow(el) {\n var s = this.shadow.style;\n this.shadow.innerHTML = el.innerHTML;\n s.left = el.style.left;\n s.top = el.style.top;\n s.width = el.style.width;\n s.height = el.style.height;\n s.backgroundImage = el.style.backgroundImage;\n s.backgroundSize = el.style.backgroundSize;\n s.transform = el.style.transform;\n this.shadow_w = this.shadow.clientWidth;\n this.shadow_h = this.shadow.clientHeight;\n }\n /** Show the shadow element. */\n show_shadow() {\n if (!this.moved) {\n this.shadow.style.visibility = 'visible';\n }\n }\n /** Hide the shadow element. */\n hide_shadow() {\n this.shadow.style.visibility = 'hidden';\n }\n /**\n * Draw a helper line between the shadow and target node.\n * @param {{x:number,y:number}} shadow_p - Shadow anchor point\n * @param {{x:number,y:number}} node_p - Target node anchor point\n * @param {boolean} invalid - Whether current target is invalid\n */\n magnet_shadow(shadow_p, node_p, invalid) {\n this.canvas_ctx.lineWidth = this.options.line_width;\n this.canvas_ctx.strokeStyle = invalid\n ? this.options.line_color_invalid\n : this.options.line_color;\n this.canvas_ctx.lineCap = 'round';\n this.clear_lines();\n this.canvas_lineto(shadow_p.x, shadow_p.y, node_p.x, node_p.y);\n }\n /** Clear helper lines from canvas. */\n clear_lines() {\n this.canvas_ctx.clearRect(0, 0, this.jm.view.size.w, this.jm.view.size.h);\n }\n /**\n * Draw a straight helper line.\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n */\n canvas_lineto(x1, y1, x2, y2) {\n this.canvas_ctx.beginPath();\n this.canvas_ctx.moveTo(x1, y1);\n this.canvas_ctx.lineTo(x2, y2);\n this.canvas_ctx.stroke();\n }\n /** Bind mouse/touch events for dragging. */\n event_bind() {\n var jd = this;\n var container = this.jm.view.container;\n $.on(container, 'mousedown', function (e) {\n if (e.button === 0) {\n jd.dragstart.call(jd, e);\n }\n });\n $.on(container, 'mousemove', function (e) {\n if (e.movementX !== 0 || e.movementY !== 0) {\n jd.drag.call(jd, e);\n }\n });\n $.on(container, 'mouseup', function (e) {\n jd.dragend.call(jd, e);\n });\n $.on(container, 'touchstart', function (e) {\n jd.dragstart.call(jd, e);\n });\n $.on(container, 'touchmove', function (e) {\n jd.drag.call(jd, e);\n });\n $.on(container, 'touchend', function (e) {\n jd.dragend.call(jd, e);\n });\n }\n /**\n * Begin dragging interaction.\n * @param {MouseEvent|TouchEvent} e - Pointer down event\n */\n dragstart(e) {\n if (!this.jm.get_editable()) {\n return;\n }\n if (this.capture) {\n return;\n }\n var jview = this.jm.view;\n if (jview.is_editing()) {\n return;\n }\n this.active_node = null;\n this.view_draggable = this.jm.get_view_draggable();\n\n var el = this.find_node_element(e.target);\n if (!el) {\n return;\n }\n if (this.view_draggable) {\n this.jm.disable_view_draggable();\n }\n var nodeid = jview.get_binded_nodeid(el);\n if (!!nodeid) {\n var node = this.jm.get_node(nodeid);\n if (!node.isroot) {\n this.reset_shadow(el);\n this.view_panel_rect = this.view_panel.getBoundingClientRect();\n this.active_node = node;\n this.offset_x =\n (e.clientX || e.touches[0].clientX) / jview.zoom_current - el.offsetLeft;\n this.offset_y =\n (e.clientY || e.touches[0].clientY) / jview.zoom_current - el.offsetTop;\n this.client_hw = Math.floor(el.clientWidth / 2);\n this.client_hh = Math.floor(el.clientHeight / 2);\n if (this.hlookup_delay != 0) {\n $.w.clearTimeout(this.hlookup_delay);\n }\n if (this.hlookup_timer != 0) {\n $.w.clearInterval(this.hlookup_timer);\n }\n var jd = this;\n this.hlookup_delay = $.w.setTimeout(function () {\n jd.hlookup_delay = 0;\n jd.hlookup_timer = $.w.setInterval(function () {\n jd.lookup_target_node.call(jd);\n }, jd.options.lookup_interval);\n }, this.options.lookup_delay);\n jd.capture = true;\n }\n }\n }\n /**\n * Drag handler to move shadow and auto-scroll container.\n * @param {MouseEvent|TouchEvent} e - Pointer move event\n */\n drag(e) {\n if (!this.jm.get_editable()) {\n return;\n }\n if (this.capture) {\n e.preventDefault();\n this.show_shadow();\n this.moved = true;\n clear_selection();\n var jview = this.jm.view;\n var px = (e.clientX || e.touches[0].clientX) / jview.zoom_current - this.offset_x;\n var py = (e.clientY || e.touches[0].clientY) / jview.zoom_current - this.offset_y;\n // scrolling container axisY if drag nodes exceeding container\n if (\n e.clientY - this.view_panel_rect.top < this.options.scrolling_trigger_width &&\n this.view_panel.scrollTop > this.options.scrolling_step_length\n ) {\n this.view_panel.scrollBy(0, -this.options.scrolling_step_length);\n this.offset_y += this.options.scrolling_step_length / jview.zoom_current;\n } else if (\n this.view_panel_rect.bottom - e.clientY < this.options.scrolling_trigger_width &&\n this.view_panel.scrollTop <\n this.view_panel.scrollHeight -\n this.view_panel_rect.height -\n this.options.scrolling_step_length\n ) {\n this.view_panel.scrollBy(0, this.options.scrolling_step_length);\n this.offset_y -= this.options.scrolling_step_length / jview.zoom_current;\n }\n // scrolling container axisX if drag nodes exceeding container\n if (\n e.clientX - this.view_panel_rect.left < this.options.scrolling_trigger_width &&\n this.view_panel.scrollLeft > this.options.scrolling_step_length\n ) {\n this.view_panel.scrollBy(-this.options.scrolling_step_length, 0);\n this.offset_x += this.options.scrolling_step_length / jview.zoom_current;\n } else if (\n this.view_panel_rect.right - e.clientX < this.options.scrolling_trigger_width &&\n this.view_panel.scrollLeft <\n this.view_panel.scrollWidth -\n this.view_panel_rect.width -\n this.options.scrolling_step_length\n ) {\n this.view_panel.scrollBy(this.options.scrolling_step_length, 0);\n this.offset_x -= this.options.scrolling_step_length / jview.zoom_current;\n }\n this.shadow.style.left = px + 'px';\n this.shadow.style.top = py + 'px';\n clear_selection();\n }\n }\n /**\n * Finish dragging, move the node if applicable.\n * @param {MouseEvent|TouchEvent} e - Pointer up event\n */\n dragend(e) {\n if (!this.jm.get_editable()) {\n return;\n }\n if (this.view_draggable) {\n this.jm.enable_view_draggable();\n }\n if (this.capture) {\n if (this.hlookup_delay != 0) {\n $.w.clearTimeout(this.hlookup_delay);\n this.hlookup_delay = 0;\n this.clear_lines();\n }\n if (this.hlookup_timer != 0) {\n $.w.clearInterval(this.hlookup_timer);\n this.hlookup_timer = 0;\n this.clear_lines();\n }\n if (this.moved) {\n var src_node = this.active_node;\n var target_node = this.target_node;\n var target_direct = this.target_direct;\n this.move_node(src_node, target_node, target_direct);\n }\n this.hide_shadow();\n }\n this.view_panel_rect = null;\n this.moved = false;\n this.capture = false;\n }\n /**\n * Find the closest node element from an event target.\n * @param {HTMLElement} el - Current DOM element\n * @returns {HTMLElement|null} Matched node element or null\n */\n find_node_element(el) {\n if (\n el === this.jm.view.e_nodes ||\n el === this.jm.view.e_panel ||\n el === this.jm.view.container\n ) {\n return null;\n }\n if (el.tagName.toLowerCase() === 'jmnode') {\n return el;\n }\n return this.find_node_element(el.parentNode);\n }\n /** Recompute target node under the shadow and draw helper. */\n lookup_target_node() {\n let sx = this.shadow.offsetLeft;\n let sy = this.shadow.offsetTop;\n if (sx === this.shadow_p_x && sy === this.shadow_p_y) {\n return;\n }\n this.shadow_p_x = sx;\n this.shadow_p_y = sy;\n\n let target_direction =\n this.shadow_p_x + this.shadow_w / 2 >= this.get_root_x()\n ? jsMind.direction.right\n : jsMind.direction.left;\n let overlapping_node = this.lookup_overlapping_node_parent(target_direction);\n let target_node = overlapping_node || this.lookup_close_node(target_direction);\n if (!!target_node) {\n let points = this.calc_point_of_node(target_node, target_direction);\n let invalid = jsMind.node.inherited(this.active_node, target_node);\n this.magnet_shadow(points.sp, points.np, invalid);\n this.target_node = target_node;\n this.target_direct = target_direction;\n }\n }\n /**\n * Get X coordinate of root node center.\n * @returns {number}\n */\n get_root_x() {\n let root = this.jm.get_root();\n let root_location = root.get_location();\n let root_size = root.get_size();\n return root_location.x + root_size.w / 2;\n }\n\n /**\n * Lookup overlapping node's parent near the shadow position.\n * @param {number} direction - Direction constant\n * @returns {import('../jsmind.node.js').Node|null}\n */\n lookup_overlapping_node_parent(direction) {\n let shadowRect = this.shadow.getBoundingClientRect();\n let x = shadowRect.x + (shadowRect.width * (1 - direction)) / 2;\n let deltaX = (this.jm.options.layout.hspace + this.jm.options.layout.pspace) * direction;\n let deltaY = shadowRect.height;\n let points = [\n [x, shadowRect.y],\n [x, shadowRect.y + deltaY / 2],\n [x, shadowRect.y + deltaY],\n [x + deltaX / 2, shadowRect.y],\n [x + deltaX / 2, shadowRect.y + deltaY / 2],\n [x + deltaX / 2, shadowRect.y + deltaY],\n [x + deltaX, shadowRect.y],\n [x + deltaX, shadowRect.y + deltaY / 2],\n [x + deltaX, shadowRect.y + deltaY],\n ];\n for (const p of points) {\n let n = this.lookup_node_parent_by_location(p[0], p[1]);\n if (!!n) {\n return n;\n }\n }\n }\n\n /**\n * Find node's parent by a screen location.\n * @param {number} x - Client X\n * @param {number} y - Client Y\n * @returns {import('../jsmind.node.js').Node|null}\n */\n lookup_node_parent_by_location(x, y) {\n return $.d\n .elementsFromPoint(x, y)\n .filter(\n x => x.tagName === 'JMNODE' && x.className !== this.options.shadow_node_class_name\n )\n .map(el => this.jm.view.get_binded_nodeid(el))\n .map(id => id && this.jm.mind.nodes[id])\n .map(n => n && n.parent)\n .find(n => n);\n }\n\n /**\n * Lookup the closest node along a direction.\n * @param {number} direction\n * @returns {import('../jsmind.node.js').Node}\n */\n lookup_close_node(direction) {\n return Object.values(this.jm.mind.nodes)\n .filter(n => n.direction == direction || n.isroot)\n .filter(n => this.jm.layout.is_visible(n))\n .filter(n => this.shadow_on_target_side(n, direction))\n .map(n => ({ node: n, distance: this.shadow_to_node(n, direction) }))\n .reduce(\n (prev, curr) => {\n return prev.distance < curr.distance ? prev : curr;\n },\n { node: this.jm.get_root(), distance: Number.MAX_VALUE }\n ).node;\n }\n\n /**\n * Check if shadow is on the target side of a node.\n * @param {import('../jsmind.node.js').Node} node\n * @param {number} dir\n * @returns {boolean}\n */\n shadow_on_target_side(node, dir) {\n return (\n (dir == jsMind.direction.right && this.shadow_to_right_of_node(node) > 0) ||\n (dir == jsMind.direction.left && this.shadow_to_left_of_node(node) > 0)\n );\n }\n\n /**\n * Distance from shadow to the right side of a node.\n * @param {import('../jsmind.node.js').Node} node\n * @returns {number}\n */\n shadow_to_right_of_node(node) {\n return this.shadow_p_x - node.get_location().x - node.get_size().w;\n }\n\n /**\n * Distance from shadow to the left side of a node.\n * @param {import('../jsmind.node.js').Node} node\n * @returns {number}\n */\n shadow_to_left_of_node(node) {\n return node.get_location().x - this.shadow_p_x - this.shadow_w;\n }\n\n /**\n * Vertical distance between shadow centerline and node centerline.\n * @param {import('../jsmind.node.js').Node} node\n * @returns {number}\n */\n shadow_to_base_line_of_node(node) {\n return this.shadow_p_y + this.shadow_h / 2 - node.get_location().y - node.get_size().h / 2;\n }\n\n /**\n * Manhattan distance to a node along a direction.\n * @param {import('../jsmind.node.js').Node} node\n * @param {number} dir\n * @returns {number}\n */\n shadow_to_node(node, dir) {\n let distance_x =\n dir === jsMind.direction.right\n ? Math.abs(this.shadow_to_right_of_node(node))\n : Math.abs(this.shadow_to_left_of_node(node));\n let distance_y = Math.abs(this.shadow_to_base_line_of_node(node));\n return distance_x + distance_y;\n }\n\n /**\n * Calculate connection points of a node and the shadow.\n * @param {import('../jsmind.node.js').Node} node\n * @param {number} dir\n * @returns {{sp:{x:number,y:number}, np:{x:number,y:number}}}\n */\n calc_point_of_node(node, dir) {\n let ns = node.get_size();\n let nl = node.get_location();\n let node_x = node.isroot\n ? nl.x + ns.w / 2\n : nl.x + (ns.w * (1 + dir)) / 2 + this.options.line_width * dir;\n let node_y = nl.y + ns.h / 2;\n let shadow_x =\n this.shadow_p_x + (this.shadow_w * (1 - dir)) / 2 - this.options.line_width * dir;\n let shadow_y = this.shadow_p_y + this.shadow_h / 2;\n return {\n sp: { x: shadow_x, y: shadow_y },\n np: { x: node_x, y: node_y },\n };\n }\n\n /**\n * Move a node to a new parent/position.\n * @param {import('../jsmind.node.js').Node} src_node\n * @param {import('../jsmind.node.js').Node|null} target_node\n * @param {number|null} target_direct\n */\n move_node(src_node, target_node, target_direct) {\n var shadow_h = this.shadow.offsetTop;\n if (!!target_node && !!src_node && !jsMind.node.inherited(src_node, target_node)) {\n // lookup before_node\n var sibling_nodes = target_node.children;\n var sc = sibling_nodes.length;\n var node = null;\n var delta_y = Number.MAX_VALUE;\n var node_before = null;\n var beforeid = '_last_';\n while (sc--) {\n node = sibling_nodes[sc];\n if (node.direction == target_direct && node.id != src_node.id) {\n var dy = node.get_location().y - shadow_h;\n if (dy > 0 && dy < delta_y) {\n delta_y = dy;\n node_before = node;\n beforeid = '_first_';\n }\n }\n }\n if (!!node_before) {\n beforeid = node_before.id;\n }\n this.jm.move_node(src_node.id, beforeid, target_node.id, target_direct);\n }\n this.active_node = null;\n this.target_node = null;\n this.target_direct = null;\n }\n /**\n * Handle jsMind events.\n * @param {number|string} type - Event type\n * @param {object} [data] - Event data\n */\n jm_event_handle(type, data) {\n if (type === jsMind.event_type.resize) {\n this.resize();\n }\n }\n}\n\n/**\n * Draggable node plugin registration.\n * @type {import('../jsmind.plugin.js').Plugin<Partial<DraggableNodeOptions>>}\n */\nexport const draggable_plugin = new jsMind.plugin('draggable_node', function (jm, options) {\n var jd = new DraggableNode(jm, options);\n jd.init();\n jm.add_event_listener(function (type, data) {\n jd.jm_event_handle.call(jd, type, data);\n });\n});\n\njsMind.register_plugin(draggable_plugin);\n\nexport default DraggableNode;\n"],"names":["jsMind","Error","$","clear_selection","w","getSelection","removeAllRanges","d","selection","empty","DEFAULT_OPTIONS","line_width","line_color","line_color_invalid","lookup_delay","lookup_interval","scrolling_trigger_width","scrolling_step_length","shadow_node_class_name","DraggableNode","constructor","jm","options","opts","util","json","merge","this","version","e_canvas","canvas_ctx","shadow","shadow_p_x","shadow_p_y","shadow_w","shadow_h","active_node","target_node","target_direct","client_w","client_h","offset_x","offset_y","hlookup_delay","hlookup_timer","capture","moved","canvas_draggable","get_view_draggable","view_panel","view","e_panel","view_panel_rect","init","create_canvas","create_shadow","event_bind","resize","e_nodes","appendChild","width","size","height","h","c","ctx","getContext","s","style","visibility","zIndex","cursor","opacity","className","reset_shadow","el","innerHTML","left","top","backgroundImage","backgroundSize","transform","clientWidth","clientHeight","show_shadow","hide_shadow","magnet_shadow","shadow_p","node_p","invalid","lineWidth","strokeStyle","lineCap","clear_lines","canvas_lineto","x","y","clearRect","x1","y1","x2","y2","beginPath","moveTo","lineTo","stroke","jd","container","on","e","button","dragstart","call","movementX","movementY","drag","dragend","get_editable","jview","is_editing","view_draggable","find_node_element","target","disable_view_draggable","nodeid","get_binded_nodeid","node","get_node","isroot","getBoundingClientRect","clientX","touches","zoom_current","offsetLeft","clientY","offsetTop","client_hw","Math","floor","client_hh","clearTimeout","clearInterval","setTimeout","setInterval","lookup_target_node","preventDefault","px","py","scrollTop","scrollBy","bottom","scrollHeight","scrollLeft","right","scrollWidth","enable_view_draggable","src_node","move_node","tagName","toLowerCase","parentNode","sx","sy","target_direction","get_root_x","direction","lookup_overlapping_node_parent","lookup_close_node","points","calc_point_of_node","inherited","sp","np","root","get_root","root_location","get_location","root_size","get_size","shadowRect","deltaX","layout","hspace","pspace","deltaY","p","n","lookup_node_parent_by_location","elementsFromPoint","filter","map","id","mind","nodes","parent","find","Object","values","is_visible","shadow_on_target_side","distance","shadow_to_node","reduce","prev","curr","Number","MAX_VALUE","dir","shadow_to_right_of_node","shadow_to_left_of_node","shadow_to_base_line_of_node","abs","ns","nl","node_x","node_y","sibling_nodes","children","sc","length","delta_y","node_before","beforeid","dy","jm_event_handle","type","data","event_type","draggable_plugin","plugin","add_event_listener","register_plugin"],"mappings":"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"}