@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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umbraci/jsmind",
3
- "version": "0.10.17",
3
+ "version": "1.0.0-beta",
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
5
  "main": "lib/jsmind.js",
6
6
  "module": "es/jsmind.js",
@@ -13,29 +13,9 @@
13
13
  "require": "./lib/jsmind.js",
14
14
  "types": "./types/generated/index.d.ts"
15
15
  },
16
- "./draggable-node": {
17
- "import": "./es/jsmind.draggable-node.js",
18
- "require": "./lib/jsmind.draggable-node.js",
19
- "types": "./types/generated/plugins/jsmind.draggable-node.d.ts"
20
- },
21
- "./screenshot": {
22
- "import": "./es/jsmind.screenshot.js",
23
- "require": "./lib/jsmind.screenshot.js",
24
- "types": "./types/generated/plugins/jsmind.screenshot.d.ts"
25
- },
26
- "./multiline-text": {
27
- "import": "./es/jsmind.multiline-text.js",
28
- "require": "./lib/jsmind.multiline-text.js",
29
- "types": "./types/generated/plugins/jsmind.multiline-text.d.ts"
30
- },
31
- "./history": {
32
- "import": "./es/jsmind.history.js",
33
- "require": "./lib/jsmind.history.js",
34
- "types": "./types/generated/plugins/history/jsmind.history.d.ts"
35
- },
36
- "./multi-select": {
37
- "import": "./es/jsmind.multi-select.js",
38
- "require": "./lib/jsmind.multi-select.js"
16
+ "./*": {
17
+ "import": "./es/jsmind.*.js",
18
+ "require": "./lib/jsmind.*.js"
39
19
  },
40
20
  "./style/jsmind.css": "./style/jsmind.css"
41
21
  },
@@ -54,8 +34,10 @@
54
34
  ],
55
35
  "scripts": {
56
36
  "server": "http-server",
37
+ "sync-plugins": "node scripts/sync-plugins.mjs",
38
+ "prebuild": "npm run sync-plugins",
57
39
  "build": "rollup -c .config/rollup.config.js",
58
- "build-types": "npx -p typescript tsc -p types/tsconfig.declaration.json",
40
+ "build-types": "npm run sync-plugins && npx -p typescript tsc -p types/tsconfig.declaration.json",
59
41
  "test": "NODE_OPTIONS=--experimental-vm-modules jest tests/unit",
60
42
  "test-es6": "NODE_OPTIONS=--experimental-vm-modules jest tests/unit",
61
43
  "test-types": "NODE_OPTIONS=--experimental-vm-modules jest tests/types",
@@ -111,5 +93,24 @@
111
93
  ],
112
94
  "dependencies": {
113
95
  "fast-equals": "^5.3.2"
96
+ },
97
+ "typesVersions": {
98
+ "*": {
99
+ "draggable-node": [
100
+ "types/generated/plugins/jsmind.draggable-node.d.ts"
101
+ ],
102
+ "history": [
103
+ "types/generated/plugins/history/jsmind.history.d.ts"
104
+ ],
105
+ "multi-select": [
106
+ "types/generated/plugins/jsmind.multi-select.d.ts"
107
+ ],
108
+ "multiline-text": [
109
+ "types/generated/plugins/jsmind.multiline-text.d.ts"
110
+ ],
111
+ "screenshot": [
112
+ "types/generated/plugins/jsmind.screenshot.d.ts"
113
+ ]
114
+ }
114
115
  }
115
116
  }
@@ -28,7 +28,6 @@ declare class jsMind {
28
28
  on: (t: HTMLElement, e: string, h: (ev: Event) => void) => void;
29
29
  };
30
30
  static plugin: typeof Plugin;
31
- static register_plugin: typeof _register_plugin;
32
31
  static util: {
33
32
  file: {
34
33
  read: (file: File, cb: (result: string, name: string) => void) => void;
@@ -46,22 +45,22 @@ declare class jsMind {
46
45
  is_empty: (s?: string) => boolean;
47
46
  };
48
47
  };
49
- static enhanced_plugin: typeof EnhancedPlugin;
50
- /** @type {Array<import('./jsmind.enhanced-plugin.js').PluginDescriptor>} */
51
- static enhancedPluginList: Array<import("./jsmind.enhanced-plugin.js").PluginDescriptor>;
48
+ static plugin_base: typeof Plugin;
49
+ /** @type {Array<import('./jsmind.plugin.js').PluginDescriptor>} */
50
+ static pluginList: Array<import("./jsmind.plugin.js").PluginDescriptor>;
52
51
  /**
53
- * Register an enhanced plugin
54
- * @param {typeof EnhancedPlugin} PluginClass - Plugin class
52
+ * Register a plugin
53
+ * @param {typeof Plugin} PluginClass - Plugin class
55
54
  * @param {object} [options={}] - Plugin options
56
55
  * @returns {typeof jsMind}
57
56
  */
58
- static usePlugin(PluginClass: typeof EnhancedPlugin, options?: object): typeof jsMind;
57
+ static usePlugin(PluginClass: typeof Plugin, options?: object): typeof jsMind;
59
58
  /**
60
- * Check if an enhanced plugin is registered
61
- * @param {typeof EnhancedPlugin} PluginClass - Plugin class
59
+ * Check if a plugin is registered
60
+ * @param {typeof Plugin} PluginClass - Plugin class
62
61
  * @returns {boolean}
63
62
  */
64
- static hasEnhancedPlugin(PluginClass: typeof EnhancedPlugin): boolean;
63
+ static hasPlugin(PluginClass: typeof Plugin): boolean;
65
64
  /**
66
65
  * Deprecated: static show constructor helper.
67
66
  * @param {import('./jsmind.option.js').JsMindRuntimeOptions} options
@@ -82,7 +81,7 @@ declare class jsMind {
82
81
  event_handles: Array<(type: number, data: EventData) => void>;
83
82
  /** Initialize sub-systems and plugins. */
84
83
  init(): void;
85
- enhancedPluginManager: EnhancedPluginManager;
84
+ pluginManager: PluginManager;
86
85
  data: DataProvider;
87
86
  layout: LayoutProvider;
88
87
  view: ViewProvider;
@@ -305,7 +304,7 @@ declare class jsMind {
305
304
  */
306
305
  remove_node(node: string | import("./jsmind.node.js").Node): boolean;
307
306
  /**
308
- * Update node topic text or multiple node properties.
307
+ * Update the topic (text content) of a node, or update multiple node properties.
309
308
  * @param {string} node_id - The ID of the node to update
310
309
  * @param {string|Partial<Pick<import('./jsmind.node.js').Node, 'topic' | 'data' | 'id' | 'index' | 'expanded' | 'direction'>>} topic_or_updates - Topic string for backward compatibility, or partial Node object for comprehensive updates
311
310
  */
@@ -398,18 +397,18 @@ declare class jsMind {
398
397
  /** @param {number} type @param {EventData} data */
399
398
  _invoke_event_handle(type: number, data: EventData): void;
400
399
  /**
401
- * Remove an enhanced plugin
402
- * @param {typeof EnhancedPlugin} PluginClass - Plugin class
400
+ * Remove a plugin
401
+ * @param {typeof Plugin} PluginClass - Plugin class
403
402
  */
404
- removePlugin(PluginClass: typeof EnhancedPlugin): void;
405
- removePlugin(PluginClass: typeof EnhancedPlugin): void;
403
+ removePlugin(PluginClass: typeof Plugin): void;
404
+ removePlugin(PluginClass: typeof Plugin): void;
406
405
  /**
407
- * Get an enhanced plugin instance
406
+ * Get a plugin instance
408
407
  * @param {string} instanceName - Plugin instance name
409
- * @returns {EnhancedPlugin | undefined}
408
+ * @returns {Plugin | undefined}
410
409
  */
411
- getPlugin(instanceName: string): EnhancedPlugin | undefined;
412
- getPlugin(instanceName: string): EnhancedPlugin | undefined;
410
+ getPlugin(instanceName: string): Plugin | undefined;
411
+ getPlugin(instanceName: string): Plugin | undefined;
413
412
  /**
414
413
  * Destroy the jsMind instance and clean up resources
415
414
  */
@@ -427,12 +426,10 @@ export type EventData = {
427
426
  };
428
427
  export namespace jsMind { }
429
428
  import { Mind } from './jsmind.mind.js';
430
- import { EnhancedPluginManager } from './jsmind.enhanced-plugin.js';
429
+ import { PluginManager } from './jsmind.plugin.js';
431
430
  import { DataProvider } from './jsmind.data_provider.js';
432
431
  import { LayoutProvider } from './jsmind.layout_provider.js';
433
432
  import { ViewProvider } from './jsmind.view_provider.js';
434
433
  import { ShortcutProvider } from './jsmind.shortcut_provider.js';
435
- import { EnhancedPlugin } from './jsmind.enhanced-plugin.js';
436
- import { Node } from './jsmind.node.js';
437
434
  import { Plugin } from './jsmind.plugin.js';
438
- import { register as _register_plugin } from './jsmind.plugin.js';
435
+ import { Node } from './jsmind.node.js';
@@ -106,6 +106,13 @@ export class Mind {
106
106
  * @returns {boolean}
107
107
  */
108
108
  remove_node(node: Node): boolean;
109
+ /**
110
+ * Change a node id while preserving object references.
111
+ * @param {string} old_id
112
+ * @param {string} new_id
113
+ * @returns {boolean}
114
+ */
115
+ change_node_id(old_id: string, new_id: string): boolean;
109
116
  /**
110
117
  * Put node into the map if id is not taken.
111
118
  * @param {Node} node
@@ -3,14 +3,14 @@
3
3
  * Manages the lifecycle of enhanced plugins with synchronous initialization,
4
4
  * preload support, and lifecycle hooks.
5
5
  */
6
- export class EnhancedPluginManager {
6
+ export class PluginManager {
7
7
  /**
8
8
  * @param {import('./jsmind.js').default} jm - jsMind instance
9
9
  */
10
10
  constructor(jm: import("./jsmind.js").default);
11
11
  jm: import("./jsmind.js").default;
12
- /** @type {Map<string, EnhancedPlugin>} */
13
- plugins: Map<string, EnhancedPlugin>;
12
+ /** @type {Map<string, Plugin>} */
13
+ plugins: Map<string, Plugin>;
14
14
  /**
15
15
  * Initialize preload plugins (before core modules)
16
16
  */
@@ -27,9 +27,9 @@ export class EnhancedPluginManager {
27
27
  private _initPlugin;
28
28
  /**
29
29
  * Remove a plugin
30
- * @param {typeof EnhancedPlugin} PluginClass
30
+ * @param {typeof Plugin} PluginClass
31
31
  */
32
- removePlugin(PluginClass: typeof EnhancedPlugin): void;
32
+ removePlugin(PluginClass: typeof Plugin): void;
33
33
  /**
34
34
  * Destroy all plugins
35
35
  */
@@ -37,15 +37,15 @@ export class EnhancedPluginManager {
37
37
  /**
38
38
  * Get plugin instance by name
39
39
  * @param {string} instanceName
40
- * @returns {EnhancedPlugin | undefined}
40
+ * @returns {Plugin | undefined}
41
41
  */
42
- getPlugin(instanceName: string): EnhancedPlugin | undefined;
42
+ getPlugin(instanceName: string): Plugin | undefined;
43
43
  }
44
44
  /**
45
45
  * Enhanced Plugin Base Class
46
46
  * Provides standard interface for enhanced plugins
47
47
  */
48
- export class EnhancedPlugin {
48
+ export class Plugin {
49
49
  /**
50
50
  * Plugin instance name (must be defined by subclass)
51
51
  * @type {string}
@@ -83,7 +83,7 @@ export type PluginDescriptor = {
83
83
  /**
84
84
  * - Plugin class
85
85
  */
86
- PluginClass: typeof EnhancedPlugin;
86
+ PluginClass: typeof Plugin;
87
87
  /**
88
88
  * - Plugin instance name
89
89
  */
@@ -99,5 +99,5 @@ export type PluginDescriptor = {
99
99
  /**
100
100
  * - Plugin instance (after initialization)
101
101
  */
102
- instance: EnhancedPlugin | null;
102
+ instance: Plugin | null;
103
103
  };
@@ -1,21 +1,101 @@
1
1
  /**
2
- * Register a plugin instance.
3
- * @param {Plugin<object>} plugin
2
+ * Plugin Manager
3
+ * Manages plugin lifecycle with synchronous initialization,
4
+ * preload support, and lifecycle hooks.
4
5
  */
5
- export function register(plugin: Plugin<object>): void;
6
+ export class PluginManager {
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, Plugin>} */
13
+ plugins: Map<string, Plugin>;
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 Plugin} PluginClass
31
+ */
32
+ removePlugin(PluginClass: typeof Plugin): void;
33
+ /**
34
+ * Destroy all plugins
35
+ */
36
+ destroyAllPlugins(): void;
37
+ /**
38
+ * Get plugin instance by name
39
+ * @param {string} instanceName
40
+ * @returns {Plugin | undefined}
41
+ */
42
+ getPlugin(instanceName: string): Plugin | undefined;
43
+ }
6
44
  /**
7
- * Apply registered plugins asynchronously.
8
- * @param {import('./jsmind.js').default} jm
9
- * @param {Record<string, object>} options
45
+ * Plugin Base Class
46
+ * Provides standard plugin interface.
10
47
  */
11
- export function apply(jm: import("./jsmind.js").default, options: Record<string, object>): void;
12
48
  export class Plugin {
13
49
  /**
14
- * @template [TOptions=object]
15
- * @param {string} name
16
- * @param {(jm: import('./jsmind.js').default, options: TOptions)=>void} fn_init
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}
17
57
  */
18
- constructor(name: string, fn_init: (jm: import("./jsmind.js").default, options: TOptions) => void);
19
- name: string;
20
- fn_init: (jm: import("./jsmind.js").default, options: TOptions) => void;
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
+ */
71
+ beforePluginRemove(): void;
72
+ /**
73
+ * Called before jsMind instance is destroyed
74
+ */
75
+ beforePluginDestroy(): void;
21
76
  }
77
+ /**
78
+ * Plugin descriptor
79
+ */
80
+ export type PluginDescriptor = {
81
+ /**
82
+ * - Plugin class
83
+ */
84
+ PluginClass: typeof Plugin;
85
+ /**
86
+ * - Plugin instance name
87
+ */
88
+ instanceName: string;
89
+ /**
90
+ * - Whether to preload
91
+ */
92
+ preload: boolean;
93
+ /**
94
+ * - Plugin options
95
+ */
96
+ pluginOpt: object;
97
+ /**
98
+ * - Plugin instance (after initialization)
99
+ */
100
+ instance: Plugin | null;
101
+ };
@@ -316,7 +316,7 @@ export class ViewProvider {
316
316
  y: number;
317
317
  }): void;
318
318
  /** @param {import('./jsmind.node.js').Node} node */
319
- _get_expander_text(node: import("./jsmind.node.js").Node): number | "..." | "-" | "+";
319
+ _get_expander_text(node: import("./jsmind.node.js").Node): number | "..." | "" | "+";
320
320
  /** @param {HTMLElement} ele @param {import('./jsmind.node.js').Node} node */
321
321
  _default_node_render(ele: HTMLElement, node: import("./jsmind.node.js").Node): void;
322
322
  /** @param {HTMLElement} ele @param {import('./jsmind.node.js').Node} node */
@@ -255,6 +255,11 @@ export type FlattenOptions = {
255
255
  * ['name', 'data', 'key'] to match the actual field names in the data.
256
256
  */
257
257
  fields?: string[];
258
+ /**
259
+ * - Array of field names to exclude from diff comparison. These fields will be ignored
260
+ * even if they exist in the node data. Useful for filtering out temporary or UI-only fields.
261
+ */
262
+ excludeFields?: string[];
258
263
  /**
259
264
  * - The field name to use as the node ID. Defaults to 'id'.
260
265
  * When using custom fieldNames (e.g., { id: 'key' }), this should be 'key'.
@@ -276,6 +281,11 @@ export type DiffOptions = {
276
281
  * Note: When using jm.history.diff(), this is automatically handled.
277
282
  */
278
283
  fields?: string[];
284
+ /**
285
+ * - Array of field names to exclude from diff comparison. These fields will be ignored
286
+ * even if they exist in the node data. Useful for filtering out temporary or UI-only fields.
287
+ */
288
+ excludeFields?: string[];
279
289
  /**
280
290
  * - The field name to use as the node ID. Defaults to 'id'.
281
291
  * Note: When using jm.history.diff(), this is automatically handled.
@@ -5,7 +5,7 @@ export type DiffOptions = import("./history-diff.js").DiffOptions;
5
5
  /**
6
6
  * HistoryPlugin skeleton (Task 1)
7
7
  */
8
- export class HistoryPlugin extends EnhancedPlugin {
8
+ export class HistoryPlugin extends Plugin {
9
9
  /**
10
10
  * @param {{ jm: JsMind, pluginOpt?: any }} params
11
11
  */
@@ -38,7 +38,7 @@ export class HistoryPlugin extends EnhancedPlugin {
38
38
  /** Mount public API on jm.history (placeholder defaults) */
39
39
  _mountAPI(): void;
40
40
  }
41
- import { EnhancedPlugin } from '../../jsmind.enhanced-plugin.js';
41
+ import { Plugin } from '../../jsmind.plugin.js';
42
42
  declare class HistoryCore {
43
43
  /** @param {JsMind} jm @param {any} options */
44
44
  constructor(jm: JsMind, options: any);
@@ -241,10 +241,19 @@ export class DraggableNode {
241
241
  jm_event_handle(type: number | string, data?: object): void;
242
242
  }
243
243
  /**
244
- * Draggable node plugin registration.
245
- * @type {import('../jsmind.plugin.js').Plugin<Partial<DraggableNodeOptions>>}
244
+ * Draggable node plugin for unified plugin system.
246
245
  */
247
- export const draggable_plugin: import("../jsmind.plugin.js").Plugin<Partial<DraggableNodeOptions>>;
246
+ export class DraggableNodePlugin extends Plugin {
247
+ /**
248
+ * @param {{ jm: import('../jsmind.js').default, pluginOpt: Partial<DraggableNodeOptions> }} params
249
+ */
250
+ constructor({ jm, pluginOpt }: {
251
+ jm: import("../jsmind.js").default;
252
+ pluginOpt: Partial<DraggableNodeOptions>;
253
+ });
254
+ draggable: DraggableNode;
255
+ _eventHandle: (type: any, data: any) => void;
256
+ }
248
257
  export default DraggableNode;
249
258
  /**
250
259
  * Default options for draggable node plugin.
@@ -260,3 +269,4 @@ export type DraggableNodeOptions = {
260
269
  shadow_node_class_name?: string;
261
270
  validate_drag?: (draggedNode: import("../jsmind.node.js").Node, targetNode: import("../jsmind.node.js").Node | null) => boolean;
262
271
  };
272
+ import { Plugin } from '../jsmind.plugin.js';
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Multi-Select Plugin - Enhanced plugin for jsMind
2
+ * Multi-Select Plugin - Plugin for jsMind
3
3
  */
4
- export class MultiSelectPlugin extends EnhancedPlugin {
4
+ export class MultiSelectPlugin extends Plugin {
5
5
  /**
6
6
  * @param {{ jm: import('../jsmind.js').default, pluginOpt: object }} params
7
7
  */
@@ -50,7 +50,7 @@ export type MultiSelectOptions = {
50
50
  */
51
51
  filter?: ((node: import("../jsmind.node.js").Node) => boolean) | null;
52
52
  };
53
- import { EnhancedPlugin } from '../jsmind.enhanced-plugin.js';
53
+ import { Plugin } from '../jsmind.plugin.js';
54
54
  /**
55
55
  * Multi-Select Core - Handles all multi-select logic
56
56
  */