@umbraci/jsmind 0.10.17 → 1.0.0-beta

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 (53) hide show
  1. package/README.md +7 -7
  2. package/dist/jsmind.draggable-node.js +1 -1
  3. package/dist/jsmind.draggable-node.js.map +1 -1
  4. package/dist/jsmind.history.js +1 -1
  5. package/dist/jsmind.history.js.map +1 -1
  6. package/dist/jsmind.js +1 -1
  7. package/dist/jsmind.js.map +1 -1
  8. package/dist/jsmind.multi-select.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.multi-select.js.map +1 -1
  20. package/es/jsmind.multiline-text.js +1 -1
  21. package/es/jsmind.multiline-text.js.map +1 -1
  22. package/es/jsmind.screenshot.js +1 -1
  23. package/es/jsmind.screenshot.js.map +1 -1
  24. package/lib/jsmind.copy-paste.js +262 -7
  25. package/lib/jsmind.draggable-node.js +1 -1
  26. package/lib/jsmind.draggable-node.js.map +1 -1
  27. package/lib/jsmind.history.js +1 -1
  28. package/lib/jsmind.history.js.map +1 -1
  29. package/lib/jsmind.js +1 -1
  30. package/lib/jsmind.js.map +1 -1
  31. package/lib/jsmind.multi-select.js.map +1 -1
  32. package/lib/jsmind.multiline-text.js +1 -1
  33. package/lib/jsmind.multiline-text.js.map +1 -1
  34. package/lib/jsmind.screenshot.js +1 -1
  35. package/lib/jsmind.screenshot.js.map +1 -1
  36. package/package.json +26 -25
  37. package/types/generated/jsmind.d.ts +21 -24
  38. package/types/generated/jsmind.mind.d.ts +7 -0
  39. package/types/generated/{jsmind.enhanced-plugin.d.ts → jsmind.plugin-system.d.ts} +10 -10
  40. package/types/generated/jsmind.plugin.d.ts +93 -13
  41. package/types/generated/jsmind.view_provider.d.ts +1 -1
  42. package/types/generated/plugins/history/history-diff.d.ts +10 -0
  43. package/types/generated/plugins/history/jsmind.history.d.ts +2 -2
  44. package/types/generated/plugins/jsmind.draggable-node.d.ts +13 -3
  45. package/types/generated/plugins/jsmind.multi-select.d.ts +3 -3
  46. package/types/generated/plugins/jsmind.multiline-text.d.ts +67 -21
  47. package/types/generated/plugins/jsmind.screenshot.d.ts +12 -3
  48. package/types/tsconfig.declaration.json +6 -1
  49. package/dist/jsmind.copy-paste.js +0 -9
  50. package/dist/jsmind.copy-paste.js.map +0 -1
  51. package/es/jsmind.copy-paste.js +0 -9
  52. package/es/jsmind.copy-paste.js.map +0 -1
  53. package/types/generated/plugins/jsmind.multiline-text-v2.d.ts +0 -58
@@ -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/jsmind.common.js","../src/jsmind.plugin.js","../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\n/**\n * Library version string.\n * @type {string}\n */\nexport const __version__ = '0.9.1';\n/**\n * Library author.\n * @type {string}\n */\nexport const __author__ = 'UmbraCi';\n\nif (typeof String.prototype.startsWith != 'function') {\n String.prototype.startsWith = function (p) {\n return this.slice(0, p.length) === p;\n };\n}\n\n/**\n * Direction constants and parser.\n * @typedef {{left:number,center:number,right:number,of:(dir:(string|number))=>number|undefined}} DirectionType\n */\n/** @type {DirectionType} */\nexport const Direction = {\n left: -1,\n center: 0,\n right: 1,\n of: function (dir) {\n if (!dir || dir === -1 || dir === 0 || dir === 1) {\n return dir;\n }\n if (dir === '-1' || dir === '0' || dir === '1') {\n return parseInt(dir);\n }\n if (dir.toLowerCase() === 'left') {\n return this.left;\n }\n if (dir.toLowerCase() === 'right') {\n return this.right;\n }\n if (dir.toLowerCase() === 'center') {\n return this.center;\n }\n },\n};\n/** @enum {number} */\nexport const EventType = { show: 1, resize: 2, edit: 3, select: 4, reset: 5, history_change: 6 };\n/** @enum {number} */\nexport const Key = { meta: 1 << 13, ctrl: 1 << 12, alt: 1 << 11, shift: 1 << 10 };\n/** @enum {number} */\nexport const LogLevel = { debug: 1, info: 2, warn: 3, error: 4, disable: 9 };\n\n// an noop function define\nvar _noop = function () {};\n/**\n * Logger facade with dynamic level.\n * @type {{level:(lvl:number)=>void,log:Function,debug:Function,info:Function,warn:Function,error:Function}}\n */\nexport let logger =\n typeof console === 'undefined'\n ? {\n level: _noop,\n log: _noop,\n debug: _noop,\n info: _noop,\n warn: _noop,\n error: _noop,\n }\n : {\n level: setup_logger_level,\n log: console.log,\n debug: console.debug,\n info: console.info,\n warn: console.warn,\n error: console.error,\n };\n\n/**\n * Set logger level.\n * @param {number} log_level\n */\nfunction setup_logger_level(log_level) {\n if (log_level > LogLevel.debug) {\n logger.debug = _noop;\n } else {\n logger.debug = console.debug;\n }\n if (log_level > LogLevel.info) {\n logger.info = _noop;\n } else {\n logger.info = console.info;\n }\n if (log_level > LogLevel.warn) {\n logger.warn = _noop;\n } else {\n logger.warn = console.warn;\n }\n if (log_level > LogLevel.error) {\n logger.error = _noop;\n } else {\n logger.error = console.error;\n }\n}\n","/**\n * @license BSD\n * @copyright 2014-2025 UmbraCi\n *\n * Project Home:\n * https://github.com/UmbraCi/jsmind/\n */\n\nimport { logger } from './jsmind.common.js';\n\n/**\n * Plugin Manager\n * Manages plugin lifecycle with synchronous initialization,\n * preload support, and lifecycle hooks.\n */\nexport class PluginManager {\n /**\n * @param {import('./jsmind.js').default} jm - jsMind instance\n */\n constructor(jm) {\n this.jm = jm;\n /** @type {Map<string, Plugin>} */\n this.plugins = new Map();\n }\n\n /**\n * Initialize preload plugins (before core modules)\n */\n initPreloadPlugins() {\n const preloadPlugins = this.jm.constructor.pluginList.filter(d => d.preload);\n logger.info('Initializing ' + preloadPlugins.length + ' preload plugins');\n preloadPlugins.forEach(descriptor => {\n this._initPlugin(descriptor);\n });\n }\n\n /**\n * Initialize normal plugins (after core modules)\n */\n initNormalPlugins() {\n const normalPlugins = this.jm.constructor.pluginList.filter(d => !d.preload);\n logger.info('Initializing ' + normalPlugins.length + ' normal plugins');\n normalPlugins.forEach(descriptor => {\n this._initPlugin(descriptor);\n });\n }\n\n /**\n * Internal method: Initialize a single plugin\n * @param {PluginDescriptor} descriptor\n * @private\n */\n _initPlugin(descriptor) {\n try {\n const { PluginClass, pluginOpt } = descriptor;\n\n if (!PluginClass.instanceName) {\n throw new Error('Plugin ' + PluginClass.name + ' must define static instanceName');\n }\n if (this.plugins.has(PluginClass.instanceName)) {\n logger.warn(\n 'Plugin ' + PluginClass.instanceName + ' already exists, will be replaced'\n );\n }\n\n const instance = new PluginClass({\n jm: this.jm,\n pluginOpt: pluginOpt || {},\n });\n\n this.plugins.set(PluginClass.instanceName, instance);\n this.jm[PluginClass.instanceName] = instance;\n descriptor.instance = instance;\n\n logger.info('Plugin ' + PluginClass.instanceName + ' initialized');\n } catch (error) {\n logger.error('Failed to initialize plugin ' + descriptor.PluginClass.name + ':', error);\n }\n }\n\n /**\n * Remove a plugin\n * @param {typeof Plugin} PluginClass\n */\n removePlugin(PluginClass) {\n const instanceName = PluginClass.instanceName;\n if (!instanceName) {\n return;\n }\n\n const instance = this.plugins.get(instanceName);\n if (!instance) {\n return;\n }\n\n try {\n if (typeof instance.beforePluginRemove === 'function') {\n instance.beforePluginRemove();\n }\n\n this.plugins.delete(instanceName);\n delete this.jm[instanceName];\n\n const list = this.jm.constructor.pluginList;\n const index = list.findIndex(d => d.PluginClass === PluginClass);\n if (index !== -1) {\n list.splice(index, 1);\n }\n\n logger.info('Plugin ' + instanceName + ' removed');\n } catch (error) {\n logger.error('Failed to remove plugin ' + instanceName + ':', error);\n }\n }\n\n /**\n * Destroy all plugins\n */\n destroyAllPlugins() {\n this.plugins.forEach((instance, instanceName) => {\n try {\n if (typeof instance.beforePluginDestroy === 'function') {\n instance.beforePluginDestroy();\n }\n } catch (error) {\n logger.error('Failed to destroy plugin ' + instanceName + ':', error);\n }\n });\n\n this.plugins.clear();\n }\n\n /**\n * Get plugin instance by name\n * @param {string} instanceName\n * @returns {Plugin | undefined}\n */\n getPlugin(instanceName) {\n return this.plugins.get(instanceName);\n }\n}\n\n/**\n * Plugin Base Class\n * Provides standard plugin interface.\n */\nexport class Plugin {\n /**\n * Plugin instance name (must be defined by subclass)\n * @type {string}\n */\n static instanceName = '';\n\n /**\n * Whether to initialize before core modules\n * @type {boolean}\n */\n static preload = false;\n\n /**\n * @param {{ jm: import('./jsmind.js').default, pluginOpt: object }} params\n */\n constructor({ jm, pluginOpt }) {\n this.jm = jm;\n this.options = pluginOpt || {};\n }\n\n /**\n * Called before plugin is removed\n */\n beforePluginRemove() {}\n\n /**\n * Called before jsMind instance is destroyed\n */\n beforePluginDestroy() {\n this.beforePluginRemove();\n }\n}\n\n/**\n * Plugin descriptor\n * @typedef {object} PluginDescriptor\n * @property {typeof Plugin} PluginClass - Plugin class\n * @property {string} instanceName - Plugin instance name\n * @property {boolean} preload - Whether to preload\n * @property {object} pluginOpt - Plugin options\n * @property {Plugin | null} instance - Plugin instance (after initialization)\n */\n","/**\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';\nimport { Plugin } from '../jsmind.plugin.js';\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 for unified plugin system.\n */\nexport class ScreenshotPlugin extends Plugin {\n static instanceName = 'screenshot';\n static preload = false;\n\n /**\n * @param {{ jm: import('../jsmind.js').default, pluginOpt: Partial<ScreenshotOptions> }} params\n */\n constructor({ jm, pluginOpt }) {\n super({ jm, pluginOpt });\n this.screenshot = new JmScreenshot(jm, pluginOpt);\n jm.screenshot = this.screenshot;\n jm.shoot = () => {\n this.screenshot.shoot();\n };\n }\n\n beforePluginRemove() {\n delete this.jm.shoot;\n delete this.jm.screenshot;\n }\n}\n\njsMind.usePlugin(ScreenshotPlugin);\n\nexport default JmScreenshot;\n"],"names":["String","prototype","startsWith","p","this","slice","length","Plugin","static","constructor","jm","pluginOpt","options","beforePluginRemove","beforePluginDestroy","jsMind","Error","domtoimage","$","DEFAULT_OPTIONS","filename","watermark","left","w","location","right","background","JmScreenshot","opts","util","json","merge","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","ScreenshotPlugin","super","screenshot","usePlugin"],"mappings":"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"}
@@ -1,9 +1,264 @@
1
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"));const i=new class{constructor(e){this.w=e,this.d=e.document,this.g=function(e){return this.d.getElementById(e)},this.c=function(e){return this.d.createElement(e)},this.t=function(e,t){e.hasChildNodes()?e.firstChild.nodeValue=t:e.appendChild(this.d.createTextNode(t))},this.h=function(e,t){t instanceof HTMLElement?(e.innerHTML="",e.appendChild(t)):e.innerHTML=t},this.i=function(e){return!!e&&"object"==typeof e&&1===e.nodeType&&"object"==typeof e.style&&"object"==typeof e.ownerDocument},this.on=function(e,t,i){e.addEventListener?e.addEventListener(t,i,!1):e.attachEvent("on"+t,i)}}}(window),n={file:{read:function(e,t){var i=new FileReader;i.onload=function(){"function"==typeof t&&t(this.result,e.name)},i.readAsText(e)},save:function(e,t,n){var o;if("function"==typeof i.w.Blob)o=new Blob([e],{type:t});else{var r=new(i.w.BlobBuilder||i.w.MozBlobBuilder||i.w.WebKitBlobBuilder||i.w.MSBlobBuilder);r.append(e),o=r.getBlob(t)}if(navigator.msSaveBlob)navigator.msSaveBlob(o,n);else{var a=(i.w.URL||i.w.webkitURL).createObjectURL(o),s=i.c("a");if("download"in s){s.style.visibility="hidden",s.href=a,s.download=n,i.d.body.appendChild(s);var d=i.d.createEvent("MouseEvents");d.initEvent("click",!0,!0),s.dispatchEvent(d),i.d.body.removeChild(s)}else location.href=a}}},json:{json2string:function(e){return JSON.stringify(e)},string2json:function(e){return JSON.parse(e)},merge:function(e,t){for(var i in t)i in e?"object"!=typeof e[i]||"[object object]"!=Object.prototype.toString.call(e[i]).toLowerCase()||e[i].length?e[i]=t[i]:n.json.merge(e[i],t[i]):e[i]=t[i];return e}},uuid:{newid:function(){return((new Date).getTime().toString(16)+Math.random().toString(16).substring(2)).substring(2,18)}},text:{is_empty:function(e){return!e||0==e.replace(/\s*/,"").length}}};class o{constructor(e,t={}){this.jsMind=e,this.options={enabled:!0,shortcuts:{copy:"meta+c",paste:"meta+v",cut:"meta+x"},...t},this.clipboardData=null,this.logger={info:e=>console.info("[CopyPaste]",e),warn:e=>console.warn("[CopyPaste]",e),error:e=>console.error("[CopyPaste]",e),debug:e=>console.debug("[CopyPaste]",e)},this.init()}init(){return this.logger.info("CopyPaste plugin initialized"),!0}handleCopy(e){if(!this.options.enabled)return;const t=this.jsMind.get_selected_node();if(t)try{e.preventDefault(),this.clipboardData={id:t.id,topic:t.topic,data:t.data||{},direction:t.direction,expanded:t.expanded,children:this.copyChildren(t)},this.logger.info("Node copied:",t.topic),this.showMessage("节点已复制")}catch(e){this.logger.error("Copy failed:",e),this.showMessage("复制失败","error")}else this.logger.warn("No node selected for copying")}handlePaste(e){if(!this.options.enabled)return;if(!this.clipboardData)return this.logger.warn("No data in clipboard"),void this.showMessage("剪贴板为空,请先复制节点","warning");const t=this.jsMind.get_selected_node();if(!t)return this.logger.warn("No target node selected for pasting"),void this.showMessage("请选择目标节点","warning");try{e.preventDefault();const i=this.prepareBatchData(this.clipboardData),n=this.jsMind.add_nodes(t,[i]);n&&n.length>0&&(this.logger.info("Nodes pasted successfully:",this.clipboardData.topic),this.showMessage("粘贴成功"))}catch(e){this.logger.error("Paste failed:",e),this.showMessage("粘贴失败","error")}}handleCut(e){if(!this.options.enabled)return;const t=this.jsMind.get_selected_node();if(t){if(t.isroot)return this.logger.warn("Cannot cut root node"),void this.showMessage("不能剪切根节点","warning");try{e.preventDefault(),this.clipboardData={id:t.id,topic:t.topic,data:t.data||{},direction:t.direction,expanded:t.expanded,children:this.copyChildren(t)};this.jsMind.remove_node(t)&&(this.logger.info("Node cut:",t.topic),this.showMessage("节点已剪切"))}catch(e){this.logger.error("Cut failed:",e),this.showMessage("剪切失败","error")}}else this.logger.warn("No node selected for cutting")}copyChildren(e){return e.children&&0!==e.children.length?e.children.map(e=>({id:e.id,topic:e.topic,data:e.data||{},direction:e.direction,expanded:e.expanded,children:this.copyChildren(e)})):[]}prepareBatchData(e){return{id:n.uuid.newid(),topic:e.topic,data:e.data||{},children:e.children&&e.children.length>0?e.children.map(e=>this.prepareBatchData(e)):void 0}}pasteChildren(e,t){if(!t||0===t.length)return[];const i=t.map(e=>this.prepareBatchData(e));return this.jsMind.add_nodes(e,i)}showMessage(e,t="info"){console.log(`[CopyPaste ${t.toUpperCase()}]: ${e}`)}clear(){this.clipboardData=null,this.logger.info("Clipboard cleared")}getStatus(){return{hasData:!!this.clipboardData,data:this.clipboardData}}}const r=new t.default.plugin("copy-paste",function(e,t){var i=t||{};i.shortcuts=i.shortcuts||{copy:"meta+c",paste:"meta+v",cut:"meta+x"};var n=new o(e,i);e.view&&e.view.e_panel&&e.view.e_panel.addEventListener("keydown",function(e){!e.metaKey&&!e.ctrlKey||"c"!==e.key||e.shiftKey||e.altKey?!e.metaKey&&!e.ctrlKey||"v"!==e.key||e.shiftKey||e.altKey?!e.metaKey&&!e.ctrlKey||"x"!==e.key||e.shiftKey||e.altKey||n.handleCut(e):n.handlePaste(e):n.handleCopy(e)}),e.copy_paste_handler=n});t.default.register_plugin(r),exports.copy_paste_plugin=r,exports.default=o;
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';
9
+ function e(e) {
10
+ return e && 'object' == typeof e && 'default' in e ? e : { default: e };
11
+ }
12
+ Object.defineProperty(exports, '__esModule', { value: !0 });
13
+ var t = e(require('@umbraci/jsmind'));
14
+ const i = new (class {
15
+ constructor(e) {
16
+ (this.w = e),
17
+ (this.d = e.document),
18
+ (this.g = function (e) {
19
+ return this.d.getElementById(e);
20
+ }),
21
+ (this.c = function (e) {
22
+ return this.d.createElement(e);
23
+ }),
24
+ (this.t = function (e, t) {
25
+ e.hasChildNodes()
26
+ ? (e.firstChild.nodeValue = t)
27
+ : e.appendChild(this.d.createTextNode(t));
28
+ }),
29
+ (this.h = function (e, t) {
30
+ t instanceof HTMLElement
31
+ ? ((e.innerHTML = ''), e.appendChild(t))
32
+ : (e.innerHTML = t);
33
+ }),
34
+ (this.i = function (e) {
35
+ return (
36
+ !!e &&
37
+ 'object' == typeof e &&
38
+ 1 === e.nodeType &&
39
+ 'object' == typeof e.style &&
40
+ 'object' == typeof e.ownerDocument
41
+ );
42
+ }),
43
+ (this.on = function (e, t, i) {
44
+ e.addEventListener ? e.addEventListener(t, i, !1) : e.attachEvent('on' + t, i);
45
+ });
46
+ }
47
+ })(window),
48
+ n = {
49
+ file: {
50
+ read: function (e, t) {
51
+ var i = new FileReader();
52
+ (i.onload = function () {
53
+ 'function' == typeof t && t(this.result, e.name);
54
+ }),
55
+ i.readAsText(e);
56
+ },
57
+ save: function (e, t, n) {
58
+ var o;
59
+ if ('function' == typeof i.w.Blob) o = new Blob([e], { type: t });
60
+ else {
61
+ var r = new (i.w.BlobBuilder ||
62
+ i.w.MozBlobBuilder ||
63
+ i.w.WebKitBlobBuilder ||
64
+ i.w.MSBlobBuilder)();
65
+ r.append(e), (o = r.getBlob(t));
66
+ }
67
+ if (navigator.msSaveBlob) navigator.msSaveBlob(o, n);
68
+ else {
69
+ var a = (i.w.URL || i.w.webkitURL).createObjectURL(o),
70
+ s = i.c('a');
71
+ if ('download' in s) {
72
+ (s.style.visibility = 'hidden'),
73
+ (s.href = a),
74
+ (s.download = n),
75
+ i.d.body.appendChild(s);
76
+ var d = i.d.createEvent('MouseEvents');
77
+ d.initEvent('click', !0, !0), s.dispatchEvent(d), i.d.body.removeChild(s);
78
+ } else location.href = a;
79
+ }
80
+ },
81
+ },
82
+ json: {
83
+ json2string: function (e) {
84
+ return JSON.stringify(e);
85
+ },
86
+ string2json: function (e) {
87
+ return JSON.parse(e);
88
+ },
89
+ merge: function (e, t) {
90
+ for (var i in t)
91
+ i in e
92
+ ? 'object' != typeof e[i] ||
93
+ '[object object]' != Object.prototype.toString.call(e[i]).toLowerCase() ||
94
+ e[i].length
95
+ ? (e[i] = t[i])
96
+ : n.json.merge(e[i], t[i])
97
+ : (e[i] = t[i]);
98
+ return e;
99
+ },
100
+ },
101
+ uuid: {
102
+ newid: function () {
103
+ return (
104
+ new Date().getTime().toString(16) + Math.random().toString(16).substring(2)
105
+ ).substring(2, 18);
106
+ },
107
+ },
108
+ text: {
109
+ is_empty: function (e) {
110
+ return !e || 0 == e.replace(/\s*/, '').length;
111
+ },
112
+ },
113
+ };
114
+ class o {
115
+ constructor(e, t = {}) {
116
+ (this.jsMind = e),
117
+ (this.options = {
118
+ enabled: !0,
119
+ shortcuts: { copy: 'meta+c', paste: 'meta+v', cut: 'meta+x' },
120
+ ...t,
121
+ }),
122
+ (this.clipboardData = null),
123
+ (this.logger = {
124
+ info: e => console.info('[CopyPaste]', e),
125
+ warn: e => console.warn('[CopyPaste]', e),
126
+ error: e => console.error('[CopyPaste]', e),
127
+ debug: e => console.debug('[CopyPaste]', e),
128
+ }),
129
+ this.init();
130
+ }
131
+ init() {
132
+ return this.logger.info('CopyPaste plugin initialized'), !0;
133
+ }
134
+ handleCopy(e) {
135
+ if (!this.options.enabled) return;
136
+ const t = this.jsMind.get_selected_node();
137
+ if (t)
138
+ try {
139
+ e.preventDefault(),
140
+ (this.clipboardData = {
141
+ id: t.id,
142
+ topic: t.topic,
143
+ data: t.data || {},
144
+ direction: t.direction,
145
+ expanded: t.expanded,
146
+ children: this.copyChildren(t),
147
+ }),
148
+ this.logger.info('Node copied:', t.topic),
149
+ this.showMessage('节点已复制');
150
+ } catch (e) {
151
+ this.logger.error('Copy failed:', e), this.showMessage('复制失败', 'error');
152
+ }
153
+ else this.logger.warn('No node selected for copying');
154
+ }
155
+ handlePaste(e) {
156
+ if (!this.options.enabled) return;
157
+ if (!this.clipboardData)
158
+ return (
159
+ this.logger.warn('No data in clipboard'),
160
+ void this.showMessage('剪贴板为空,请先复制节点', 'warning')
161
+ );
162
+ const t = this.jsMind.get_selected_node();
163
+ if (!t)
164
+ return (
165
+ this.logger.warn('No target node selected for pasting'),
166
+ void this.showMessage('请选择目标节点', 'warning')
167
+ );
168
+ try {
169
+ e.preventDefault();
170
+ const i = this.prepareBatchData(this.clipboardData),
171
+ n = this.jsMind.add_nodes(t, [i]);
172
+ n &&
173
+ n.length > 0 &&
174
+ (this.logger.info('Nodes pasted successfully:', this.clipboardData.topic),
175
+ this.showMessage('粘贴成功'));
176
+ } catch (e) {
177
+ this.logger.error('Paste failed:', e), this.showMessage('粘贴失败', 'error');
178
+ }
179
+ }
180
+ handleCut(e) {
181
+ if (!this.options.enabled) return;
182
+ const t = this.jsMind.get_selected_node();
183
+ if (t) {
184
+ if (t.isroot)
185
+ return (
186
+ this.logger.warn('Cannot cut root node'),
187
+ void this.showMessage('不能剪切根节点', 'warning')
188
+ );
189
+ try {
190
+ e.preventDefault(),
191
+ (this.clipboardData = {
192
+ id: t.id,
193
+ topic: t.topic,
194
+ data: t.data || {},
195
+ direction: t.direction,
196
+ expanded: t.expanded,
197
+ children: this.copyChildren(t),
198
+ });
199
+ this.jsMind.remove_node(t) &&
200
+ (this.logger.info('Node cut:', t.topic), this.showMessage('节点已剪切'));
201
+ } catch (e) {
202
+ this.logger.error('Cut failed:', e), this.showMessage('剪切失败', 'error');
203
+ }
204
+ } else this.logger.warn('No node selected for cutting');
205
+ }
206
+ copyChildren(e) {
207
+ return e.children && 0 !== e.children.length
208
+ ? e.children.map(e => ({
209
+ id: e.id,
210
+ topic: e.topic,
211
+ data: e.data || {},
212
+ direction: e.direction,
213
+ expanded: e.expanded,
214
+ children: this.copyChildren(e),
215
+ }))
216
+ : [];
217
+ }
218
+ prepareBatchData(e) {
219
+ return {
220
+ id: n.uuid.newid(),
221
+ topic: e.topic,
222
+ data: e.data || {},
223
+ children:
224
+ e.children && e.children.length > 0
225
+ ? e.children.map(e => this.prepareBatchData(e))
226
+ : void 0,
227
+ };
228
+ }
229
+ pasteChildren(e, t) {
230
+ if (!t || 0 === t.length) return [];
231
+ const i = t.map(e => this.prepareBatchData(e));
232
+ return this.jsMind.add_nodes(e, i);
233
+ }
234
+ showMessage(e, t = 'info') {
235
+ console.log(`[CopyPaste ${t.toUpperCase()}]: ${e}`);
236
+ }
237
+ clear() {
238
+ (this.clipboardData = null), this.logger.info('Clipboard cleared');
239
+ }
240
+ getStatus() {
241
+ return { hasData: !!this.clipboardData, data: this.clipboardData };
242
+ }
243
+ }
244
+ const r = new t.default.plugin('copy-paste', function (e, t) {
245
+ var i = t || {};
246
+ i.shortcuts = i.shortcuts || { copy: 'meta+c', paste: 'meta+v', cut: 'meta+x' };
247
+ var n = new o(e, i);
248
+ e.view &&
249
+ e.view.e_panel &&
250
+ e.view.e_panel.addEventListener('keydown', function (e) {
251
+ (!e.metaKey && !e.ctrlKey) || 'c' !== e.key || e.shiftKey || e.altKey
252
+ ? (!e.metaKey && !e.ctrlKey) || 'v' !== e.key || e.shiftKey || e.altKey
253
+ ? (!e.metaKey && !e.ctrlKey) ||
254
+ 'x' !== e.key ||
255
+ e.shiftKey ||
256
+ e.altKey ||
257
+ n.handleCut(e)
258
+ : n.handlePaste(e)
259
+ : n.handleCopy(e);
260
+ }),
261
+ (e.copy_paste_handler = n);
262
+ });
263
+ t.default.register_plugin(r), (exports.copy_paste_plugin = r), (exports.default = o);
9
264
  //# sourceMappingURL=jsmind.copy-paste.js.map
@@ -5,5 +5,5 @@
5
5
  * Project Home:
6
6
  * https://github.com/hizzgdev/jsmind/
7
7
  */
8
- "use strict";function t(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}Object.defineProperty(exports,"__esModule",{value:!0});var e=t(require("@umbraci/jsmind"));if(!e.default)throw new Error("jsMind is not defined");const i=e.default.$,s="getSelection"in i.w?function(){i.w.getSelection().removeAllRanges()}:function(){i.d.selection.empty()},o={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 n{constructor(t,i){var s={};e.default.util.json.merge(s,o),e.default.util.json.merge(s,i),this.version="0.4.0",this.jm=t,this.options=s,this.is_svg_engine="svg"===t.view.opts.engine,this.e_canvas=null,this.canvas_ctx=null,this.helper_line=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=t.get_view_draggable(),this.view_panel=t.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.is_svg_engine?(this.e_canvas.setAttribute("width",this.jm.view.size.w),this.e_canvas.setAttribute("height",this.jm.view.size.h)):(this.e_canvas.width=this.jm.view.size.w,this.e_canvas.height=this.jm.view.size.h)}create_canvas(){if(this.is_svg_engine){var t=this._create_svg_element("svg");t.setAttribute("class","jsmind-draggable-helper"),t.setAttribute("style","position: absolute; top: 0; left: 0; pointer-events: none;"),this.jm.view.e_panel.appendChild(t),this.e_canvas=t}else{var e=i.c("canvas");this.jm.view.e_panel.appendChild(e);var s=e.getContext("2d");this.e_canvas=e,this.canvas_ctx=s}}_create_svg_element(t){return i.d.createElementNS("http://www.w3.org/2000/svg",t)}create_shadow(){var t=i.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.clear_lines();var s=i?this.options.line_color_invalid:this.options.line_color;this.is_svg_engine?this.svg_draw_line(t.x,t.y,e.x,e.y,s):(this.canvas_ctx.lineWidth=this.options.line_width,this.canvas_ctx.strokeStyle=s,this.canvas_ctx.lineCap="round",this.canvas_lineto(t.x,t.y,e.x,e.y))}clear_lines(){this.is_svg_engine?this.helper_line&&this.helper_line.parentNode&&(this.e_canvas.removeChild(this.helper_line),this.helper_line=null):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()}svg_draw_line(t,e,i,s,o){this.helper_line=this._create_svg_element("path"),this.helper_line.setAttribute("stroke",o),this.helper_line.setAttribute("stroke-width",this.options.line_width),this.helper_line.setAttribute("fill","transparent"),this.helper_line.setAttribute("stroke-linecap","round"),this._svg_bezier_to(this.helper_line,t,e,i,s),this.e_canvas.appendChild(this.helper_line)}_svg_bezier_to(t,e,i,s,o){t.setAttribute("d","M "+e+" "+i+" C "+(e+2*(s-e)/3)+" "+i+", "+e+" "+o+", "+s+" "+o)}event_bind(){var t=this,e=this.jm.view.container;i.on(e,"mousedown",function(e){0===e.button&&t.dragstart.call(t,e)}),i.on(e,"mousemove",function(e){0===e.movementX&&0===e.movementY||t.drag.call(t,e)}),i.on(e,"mouseup",function(e){t.dragend.call(t,e)}),i.on(e,"touchstart",function(e){t.dragstart.call(t,e)}),i.on(e,"touchmove",function(e){t.drag.call(t,e)}),i.on(e,"touchend",function(e){t.dragend.call(t,e)})}dragstart(t){if(this.jm.get_editable()&&!this.capture){var e=this.jm.view;if(!e.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=e.get_binded_nodeid(s);if(o){var n=this.jm.get_node(o);if(!n.isroot){if(n.data&&!1===n.data.draggable)return;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)/e.zoom_current-s.offsetLeft,this.offset_y=(t.clientY||t.touches[0].clientY)/e.zoom_current-s.offsetTop,this.client_hw=Math.floor(s.clientWidth/2),this.client_hh=Math.floor(s.clientHeight/2),0!=this.hlookup_delay&&i.w.clearTimeout(this.hlookup_delay),0!=this.hlookup_timer&&i.w.clearInterval(this.hlookup_timer);var h=this;this.hlookup_delay=i.w.setTimeout(function(){h.hlookup_delay=0,h.hlookup_timer=i.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,s();var e=this.jm.view,i=(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=i+"px",this.shadow.style.top=o+"px",s()}}dragend(t){if(this.jm.get_editable()){if(this.view_draggable&&this.jm.enable_view_draggable(),this.capture){if(0!=this.hlookup_delay&&(i.w.clearTimeout(this.hlookup_delay),this.hlookup_delay=0,this.clear_lines()),0!=this.hlookup_timer&&(i.w.clearInterval(this.hlookup_timer),this.hlookup_timer=0,this.clear_lines()),this.moved){var e=this.active_node,s=this.target_node,o=this.target_direct;this.move_node(e,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 t=this.shadow.offsetLeft,i=this.shadow.offsetTop;if(t===this.shadow_p_x&&i===this.shadow_p_y)return;this.shadow_p_x=t,this.shadow_p_y=i;let s=this.shadow_p_x+this.shadow_w/2>=this.get_root_x()?e.default.direction.right:e.default.direction.left,o=this.lookup_overlapping_node_parent(s)||this.lookup_close_node(s);if(o){let t=this.calc_point_of_node(o,s),i=e.default.node.inherited(this.active_node,o);this.magnet_shadow(t.sp,t.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,e){return i.d.elementsFromPoint(t,e).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(t,i){return i==e.default.direction.right&&this.shadow_to_right_of_node(t)>0||i==e.default.direction.left&&this.shadow_to_left_of_node(t)>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(t,i){return(i===e.default.direction.right?Math.abs(this.shadow_to_right_of_node(t)):Math.abs(this.shadow_to_left_of_node(t)))+Math.abs(this.shadow_to_base_line_of_node(t))}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(t,i,s){var o=this.shadow.offsetTop;if(i&&t&&!e.default.node.inherited(t,i)){if(this.options.validate_drag&&"function"==typeof this.options.validate_drag){if(!this.options.validate_drag(t,i))return this.active_node=null,this.target_node=null,void(this.target_direct=null)}for(var n=i.children,h=n.length,l=null,_=Number.MAX_VALUE,a=null,r="_last_";h--;)if((l=n[h]).direction==s&&l.id!=t.id){var d=l.get_location().y-o;d>0&&d<_&&(_=d,a=l,r="_first_")}a&&(r=a.id),this.jm.move_node(t.id,r,i.id,s)}this.active_node=null,this.target_node=null,this.target_direct=null}jm_event_handle(t,i){t===e.default.event_type.resize&&this.resize()}}const h=new e.default.plugin("draggable_node",function(t,e){var i=new n(t,e);i.init(),t.add_event_listener(function(t,e){i.jm_event_handle.call(i,t,e)})});e.default.register_plugin(h),exports.DraggableNode=n,exports.default=n,exports.draggable_plugin=h;
8
+ "use strict";function t(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}Object.defineProperty(exports,"__esModule",{value:!0});var e=t(require("@umbraci/jsmind"));"function"!=typeof String.prototype.startsWith&&(String.prototype.startsWith=function(t){return this.slice(0,t.length)===t});class i{static instanceName="";static preload=!1;constructor({jm:t,pluginOpt:e}){this.jm=t,this.options=e||{}}beforePluginRemove(){}beforePluginDestroy(){this.beforePluginRemove()}}if(!e.default)throw new Error("jsMind is not defined");const s=e.default.$,o="getSelection"in s.w?function(){s.w.getSelection().removeAllRanges()}:function(){s.d.selection.empty()},n={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 h{constructor(t,i){var s={};e.default.util.json.merge(s,n),e.default.util.json.merge(s,i),this.version="0.4.0",this.jm=t,this.options=s,this.is_svg_engine="svg"===t.view.opts.engine,this.e_canvas=null,this.canvas_ctx=null,this.helper_line=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=t.get_view_draggable(),this.view_panel=t.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.is_svg_engine?(this.e_canvas.setAttribute("width",this.jm.view.size.w),this.e_canvas.setAttribute("height",this.jm.view.size.h)):(this.e_canvas.width=this.jm.view.size.w,this.e_canvas.height=this.jm.view.size.h)}create_canvas(){if(this.is_svg_engine){var t=this._create_svg_element("svg");t.setAttribute("class","jsmind-draggable-helper"),t.setAttribute("style","position: absolute; top: 0; left: 0; pointer-events: none;"),this.jm.view.e_panel.appendChild(t),this.e_canvas=t}else{var e=s.c("canvas");this.jm.view.e_panel.appendChild(e);var i=e.getContext("2d");this.e_canvas=e,this.canvas_ctx=i}}_create_svg_element(t){return s.d.createElementNS("http://www.w3.org/2000/svg",t)}create_shadow(){var t=s.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,i=t.style,o=s.w.getComputedStyle(t);this.shadow.innerHTML=t.innerHTML;["left","top","width","height","backgroundImage","backgroundSize","transform"].forEach(t=>{e[t]=i[t]});["whiteSpace","wordBreak","overflowWrap","maxWidth"].forEach(t=>{e[t]=i[t]||o[t]}),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.clear_lines();var s=i?this.options.line_color_invalid:this.options.line_color;this.is_svg_engine?this.svg_draw_line(t.x,t.y,e.x,e.y,s):(this.canvas_ctx.lineWidth=this.options.line_width,this.canvas_ctx.strokeStyle=s,this.canvas_ctx.lineCap="round",this.canvas_lineto(t.x,t.y,e.x,e.y))}clear_lines(){this.is_svg_engine?this.helper_line&&this.helper_line.parentNode&&(this.e_canvas.removeChild(this.helper_line),this.helper_line=null):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()}svg_draw_line(t,e,i,s,o){this.helper_line=this._create_svg_element("path"),this.helper_line.setAttribute("stroke",o),this.helper_line.setAttribute("stroke-width",this.options.line_width),this.helper_line.setAttribute("fill","transparent"),this.helper_line.setAttribute("stroke-linecap","round"),this._svg_bezier_to(this.helper_line,t,e,i,s),this.e_canvas.appendChild(this.helper_line)}_svg_bezier_to(t,e,i,s,o){t.setAttribute("d","M "+e+" "+i+" C "+(e+2*(s-e)/3)+" "+i+", "+e+" "+o+", "+s+" "+o)}event_bind(){var t=this,e=this.jm.view.container;s.on(e,"mousedown",function(e){0===e.button&&t.dragstart.call(t,e)}),s.on(e,"mousemove",function(e){0===e.movementX&&0===e.movementY||t.drag.call(t,e)}),s.on(e,"mouseup",function(e){t.dragend.call(t,e)}),s.on(e,"touchstart",function(e){t.dragstart.call(t,e)}),s.on(e,"touchmove",function(e){t.drag.call(t,e)}),s.on(e,"touchend",function(e){t.dragend.call(t,e)})}dragstart(t){if(this.jm.get_editable()&&!this.capture){var e=this.jm.view;if(!e.is_editing()){this.active_node=null,this.view_draggable=this.jm.get_view_draggable();var i=this.find_node_element(t.target);if(i){this.view_draggable&&this.jm.disable_view_draggable();var o=e.get_binded_nodeid(i);if(o){var n=this.jm.get_node(o);if(!n.isroot){if(n.data&&!1===n.data.draggable)return;this.reset_shadow(i),this.view_panel_rect=this.view_panel.getBoundingClientRect(),this.active_node=n,this.offset_x=(t.clientX||t.touches[0].clientX)/e.zoom_current-i.offsetLeft,this.offset_y=(t.clientY||t.touches[0].clientY)/e.zoom_current-i.offsetTop,this.client_hw=Math.floor(i.clientWidth/2),this.client_hh=Math.floor(i.clientHeight/2),0!=this.hlookup_delay&&s.w.clearTimeout(this.hlookup_delay),0!=this.hlookup_timer&&s.w.clearInterval(this.hlookup_timer);var h=this;this.hlookup_delay=s.w.setTimeout(function(){h.hlookup_delay=0,h.hlookup_timer=s.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,o();var e=this.jm.view,i=(t.clientX||t.touches[0].clientX)/e.zoom_current-this.offset_x,s=(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=i+"px",this.shadow.style.top=s+"px",o()}}dragend(t){if(this.jm.get_editable()){if(this.view_draggable&&this.jm.enable_view_draggable(),this.capture){if(0!=this.hlookup_delay&&(s.w.clearTimeout(this.hlookup_delay),this.hlookup_delay=0,this.clear_lines()),0!=this.hlookup_timer&&(s.w.clearInterval(this.hlookup_timer),this.hlookup_timer=0,this.clear_lines()),this.moved){var e=this.active_node,i=this.target_node,o=this.target_direct;this.move_node(e,i,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 t=this.shadow.offsetLeft,i=this.shadow.offsetTop;if(t===this.shadow_p_x&&i===this.shadow_p_y)return;this.shadow_p_x=t,this.shadow_p_y=i;let s=this.shadow_p_x+this.shadow_w/2>=this.get_root_x()?e.default.direction.right:e.default.direction.left,o=this.lookup_overlapping_node_parent(s)||this.lookup_close_node(s);if(o){let t=this.calc_point_of_node(o,s),i=e.default.node.inherited(this.active_node,o);this.magnet_shadow(t.sp,t.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,e){return s.d.elementsFromPoint(t,e).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(t,i){return i==e.default.direction.right&&this.shadow_to_right_of_node(t)>0||i==e.default.direction.left&&this.shadow_to_left_of_node(t)>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(t,i){return(i===e.default.direction.right?Math.abs(this.shadow_to_right_of_node(t)):Math.abs(this.shadow_to_left_of_node(t)))+Math.abs(this.shadow_to_base_line_of_node(t))}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(t,i,s){var o=this.shadow.offsetTop;if(i&&t&&!e.default.node.inherited(t,i)){if(this.options.validate_drag&&"function"==typeof this.options.validate_drag){if(!this.options.validate_drag(t,i))return this.active_node=null,this.target_node=null,void(this.target_direct=null)}for(var n=i.children,h=n.length,l=null,a=Number.MAX_VALUE,_=null,r="_last_";h--;)if((l=n[h]).direction==s&&l.id!=t.id){var d=l.get_location().y-o;d>0&&d<a&&(a=d,_=l,r="_first_")}_&&(r=_.id),this.jm.move_node(t.id,r,i.id,s)}this.active_node=null,this.target_node=null,this.target_direct=null}jm_event_handle(t,i){t===e.default.event_type.resize&&this.resize()}}class l extends i{static instanceName="draggable";static preload=!1;constructor({jm:t,pluginOpt:e}){super({jm:t,pluginOpt:e}),this.draggable=new h(t,e),this.draggable.init(),this._eventHandle=(t,e)=>{this.draggable.jm_event_handle(t,e)},t.add_event_listener(this._eventHandle),t.draggable=this.draggable}beforePluginRemove(){delete this.jm.draggable}}e.default.usePlugin(l),exports.DraggableNode=h,exports.DraggableNodePlugin=l,exports.default=h;
9
9
  //# sourceMappingURL=jsmind.draggable-node.js.map