Skip to content

Conversation

@UmbraCi
Copy link
Contributor

@UmbraCi UmbraCi commented Sep 21, 2025

Overview

This PR refactors the multiline text editing functionality into an independent plugin form, following the maintainer's recommendations.

Key Changes

  • Plugin Refactoring: Refactored multiline editing functionality into an independent jsmind.multiline-text.js plugin
  • Optimized Editor: Improved editor text processing logic, fixed multiline text encoding/decoding issues
  • Browser Compatibility: Enhanced HTML entity processing and browser compatibility
  • Build Configuration: Updated rollup configuration to support new plugin structure
  • Example Updates: Simplified example page to demonstrate basic plugin usage

Technical Implementation

  • Uses contenteditable for multiline editing
  • Supports Shift+Enter for line breaks, Enter to finish editing
  • Automatically adjusts node size to accommodate multiline content
  • Maintains compatibility with existing jsMind API

Usage

// Load the plugin
import 'jsmind.multiline-text.js';

// Plugin automatically registers when creating jsMind instance
const jm = new jsMind(options);

// Plugin automatically handles multiline text editing and display

Backward Compatibility

  • Fully backward compatible, does not affect existing functionality
  • Plugin uses non-invasive design, won't impact core jsMind functionality

Testing

  • Tested multiline text editing and display
  • Tested compatibility with drag-and-drop plugin
  • Tested cross-browser compatibility

@UmbraCi
Copy link
Contributor Author

UmbraCi commented Oct 1, 2025

@hizzgdev 当前插件系统异步初始化, 插件在渲染后才初始化,无法直接影响初始渲染,初始化渲染的逻辑在ViewProvider 类中,且打包出来的UMD 模块有作用域隔离。
在实现多行文本功能,我需要覆写ViewProvider的render函数以及edit相关逻辑,目前想到的方案是:

  • 通过原型链覆盖ViewProvider中的render方法;
  • 脑图被原始render函数初始化后,使用覆盖后的render方法再渲染一次;
    但是这带来了额外的性能开销,请问是否考虑增加一个参数来让插件从【运行时动态加载插件】改为,初始化jsmind类时【同步加载插件】呢,这个逻辑可以由我来写;

@hizzgdev
Copy link
Owner

hizzgdev commented Oct 1, 2025

@hizzgdev 当前插件系统异步初始化, 插件在渲染后才初始化,无法直接影响初始渲染,初始化渲染的逻辑在ViewProvider 类中,且打包出来的UMD 模块有作用域隔离。 在实现多行文本功能,我需要覆写ViewProvider的render函数以及edit相关逻辑,目前想到的方案是:

  • 通过原型链覆盖ViewProvider中的render方法;
  • 脑图被原始render函数初始化后,使用覆盖后的render方法再渲染一次;
    但是这带来了额外的性能开销,请问是否考虑增加一个参数来让插件从【运行时动态加载插件】改为,初始化jsmind类时【同步加载插件】呢,这个逻辑可以由我来写;

这个插件是一个 editor 吧,它为什么需要在初始化的时候加载呢?在脑图没有画出来之前就已经需要用到 editor 了吗?还是说这个插件其实也修改了 render 逻辑?如果修改了,那为什么需要修改呢?

@UmbraCi
Copy link
Contributor Author

UmbraCi commented Oct 1, 2025

@hizzgdev 当前插件系统异步初始化, 插件在渲染后才初始化,无法直接影响初始渲染,初始化渲染的逻辑在ViewProvider 类中,且打包出来的UMD 模块有作用域隔离。 在实现多行文本功能,我需要覆写ViewProvider的render函数以及edit相关逻辑,目前想到的方案是:

  • 通过原型链覆盖ViewProvider中的render方法;
  • 脑图被原始render函数初始化后,使用覆盖后的render方法再渲染一次;
    但是这带来了额外的性能开销,请问是否考虑增加一个参数来让插件从【运行时动态加载插件】改为,初始化jsmind类时【同步加载插件】呢,这个逻辑可以由我来写;

这个插件是一个 editor 吧,它为什么需要在初始化的时候加载呢?在脑图没有画出来之前就已经需要用到 editor 了吗?还是说这个插件其实也修改了 render 逻辑?如果修改了,那为什么需要修改呢?

因为如果需要脑图的节点支持多行文本,那么需要1.渲染多行文本功能;2.编辑多行文本功能;3.编辑后的保存多行文本功能;
插件的加载是异步的,且init函数在首次渲染之前,此时,show()函数依赖的是ViewProvider的render方法,我的设想是这个插件也会覆写默认的render方法,从而让节点支持显示多行文本。
我在想,是不是可以让插件系统支持同步的方式加载插件,从而把覆写核心类的权限也开放给插件,并且让插件支持【预加载】(在show方法之前)

@hizzgdev
Copy link
Owner

hizzgdev commented Oct 1, 2025

当前插件系统异步初始化, 插件在渲染后才初始化,无法直接影响初始渲染,初始化渲染的逻辑在ViewProvider 类中,且打包出来的UMD 模块有作用域隔离。 在实现多行文本功能,我需要覆写ViewProvider的render函数以及edit相关逻辑,目前想到的方案是:

  • 通过原型链覆盖ViewProvider中的render方法;
  • 脑图被原始render函数初始化后,使用覆盖后的render方法再渲染一次;
    但是这带来了额外的性能开销,请问是否考虑增加一个参数来让插件从【运行时动态加载插件】改为,初始化jsmind类时【同步加载插件】呢,这个逻辑可以由我来写;

这个插件是一个 editor 吧,它为什么需要在初始化的时候加载呢?在脑图没有画出来之前就已经需要用到 editor 了吗?还是说这个插件其实也修改了 render 逻辑?如果修改了,那为什么需要修改呢?

因为如果需要脑图的节点支持多行文本,那么需要1.渲染多行文本功能;2.编辑多行文本功能;3.编辑后的保存多行文本功能; 插件的加载是异步的,且init函数在首次渲染之前,此时,show()函数依赖的是ViewProvider的render方法,我的设想是这个插件也会覆写默认的render方法,从而让节点支持显示多行文本。 我在想,是不是可以让插件系统支持同步的方式加载插件,从而把覆写核心类的权限也开放给插件,并且让插件支持【预加载】(在show方法之前)

目前的可以支持多行文本,只需要按 html 的方式去支持就好了。 如果你需要用不同的渲染逻辑来支持多行文本,那其实是在定义另一种数据格式,如果是这样的话,你可以使用 custom_node_render,并且在你的插件里对这种节点进行更好的编辑支持。

@UmbraCi
Copy link
Contributor Author

UmbraCi commented Oct 1, 2025

当前插件系统异步初始化, 插件在渲染后才初始化,无法直接影响初始渲染,初始化渲染的逻辑在ViewProvider 类中,且打包出来的UMD 模块有作用域隔离。 在实现多行文本功能,我需要覆写ViewProvider的render函数以及edit相关逻辑,目前想到的方案是:

  • 通过原型链覆盖ViewProvider中的render方法;
  • 脑图被原始render函数初始化后,使用覆盖后的render方法再渲染一次;
    但是这带来了额外的性能开销,请问是否考虑增加一个参数来让插件从【运行时动态加载插件】改为,初始化jsmind类时【同步加载插件】呢,这个逻辑可以由我来写;

这个插件是一个 editor 吧,它为什么需要在初始化的时候加载呢?在脑图没有画出来之前就已经需要用到 editor 了吗?还是说这个插件其实也修改了 render 逻辑?如果修改了,那为什么需要修改呢?

因为如果需要脑图的节点支持多行文本,那么需要1.渲染多行文本功能;2.编辑多行文本功能;3.编辑后的保存多行文本功能; 插件的加载是异步的,且init函数在首次渲染之前,此时,show()函数依赖的是ViewProvider的render方法,我的设想是这个插件也会覆写默认的render方法,从而让节点支持显示多行文本。 我在想,是不是可以让插件系统支持同步的方式加载插件,从而把覆写核心类的权限也开放给插件,并且让插件支持【预加载】(在show方法之前)

目前的可以支持多行文本,只需要按 html 的方式去支持就好了。 如果你需要用不同的渲染逻辑来支持多行文本,那其实是在定义另一种数据格式,如果是这样的话,你可以使用 custom_node_render,并且在你的插件里对这种节点进行更好的编辑支持。

好的,我按照这个思路再重构一下这个PR的插件,先不用CR代码

@UmbraCi
Copy link
Contributor Author

UmbraCi commented Oct 1, 2025

当前插件系统异步初始化, 插件在渲染后才初始化,无法直接影响初始渲染,初始化渲染的逻辑在ViewProvider 类中,且打包出来的UMD 模块有作用域隔离。 在实现多行文本功能,我需要覆写ViewProvider的render函数以及edit相关逻辑,目前想到的方案是:

  • 通过原型链覆盖ViewProvider中的render方法;
  • 脑图被原始render函数初始化后,使用覆盖后的render方法再渲染一次;
    但是这带来了额外的性能开销,请问是否考虑增加一个参数来让插件从【运行时动态加载插件】改为,初始化jsmind类时【同步加载插件】呢,这个逻辑可以由我来写;

这个插件是一个 editor 吧,它为什么需要在初始化的时候加载呢?在脑图没有画出来之前就已经需要用到 editor 了吗?还是说这个插件其实也修改了 render 逻辑?如果修改了,那为什么需要修改呢?

因为如果需要脑图的节点支持多行文本,那么需要1.渲染多行文本功能;2.编辑多行文本功能;3.编辑后的保存多行文本功能; 插件的加载是异步的,且init函数在首次渲染之前,此时,show()函数依赖的是ViewProvider的render方法,我的设想是这个插件也会覆写默认的render方法,从而让节点支持显示多行文本。 我在想,是不是可以让插件系统支持同步的方式加载插件,从而把覆写核心类的权限也开放给插件,并且让插件支持【预加载】(在show方法之前)

目前的可以支持多行文本,只需要按 html 的方式去支持就好了。 如果你需要用不同的渲染逻辑来支持多行文本,那其实是在定义另一种数据格式,如果是这样的话,你可以使用 custom_node_render,并且在你的插件里对这种节点进行更好的编辑支持。

还有个问题,目前jsmind的插件流程如下:

  1. jsMind 实例创建
  2. 调用 show() 方法
  3. 数据加载、布局计算、节点渲染
  4. 异步调用插件初始化(setTimeout)
  5. 插件初始化完成

因为插件异步且在脑图初始化渲染后才会被注册,那么自定义渲染函数custom_node_render或者html的逻辑,如果我写在插件中,是不是首次渲染还是走的ViewProvider中的默认单行渲染函数render,如果我要初始化脑图的时候就支持多行渲染,岂不是还需要用户自己再去jsmind的custom_node_render入参传入一个自定义渲染函数才行;
或者我的插件在加载完以后使用插件中编写的custom_node_render方法再重绘一遍脑图(渲染了两次,是不是有性能问题);

@hizzgdev
Copy link
Owner

hizzgdev commented Oct 1, 2025

当前插件系统异步初始化, 插件在渲染后才初始化,无法直接影响初始渲染,初始化渲染的逻辑在ViewProvider 类中,且打包出来的UMD 模块有作用域隔离。 在实现多行文本功能,我需要覆写ViewProvider的render函数以及edit相关逻辑,目前想到的方案是:

  • 通过原型链覆盖ViewProvider中的render方法;
  • 脑图被原始render函数初始化后,使用覆盖后的render方法再渲染一次;
    但是这带来了额外的性能开销,请问是否考虑增加一个参数来让插件从【运行时动态加载插件】改为,初始化jsmind类时【同步加载插件】呢,这个逻辑可以由我来写;

这个插件是一个 editor 吧,它为什么需要在初始化的时候加载呢?在脑图没有画出来之前就已经需要用到 editor 了吗?还是说这个插件其实也修改了 render 逻辑?如果修改了,那为什么需要修改呢?

因为如果需要脑图的节点支持多行文本,那么需要1.渲染多行文本功能;2.编辑多行文本功能;3.编辑后的保存多行文本功能; 插件的加载是异步的,且init函数在首次渲染之前,此时,show()函数依赖的是ViewProvider的render方法,我的设想是这个插件也会覆写默认的render方法,从而让节点支持显示多行文本。 我在想,是不是可以让插件系统支持同步的方式加载插件,从而把覆写核心类的权限也开放给插件,并且让插件支持【预加载】(在show方法之前)

目前的可以支持多行文本,只需要按 html 的方式去支持就好了。 如果你需要用不同的渲染逻辑来支持多行文本,那其实是在定义另一种数据格式,如果是这样的话,你可以使用 custom_node_render,并且在你的插件里对这种节点进行更好的编辑支持。

还有个问题,目前jsmind的插件流程如下:

  1. jsMind 实例创建
  2. 调用 show() 方法
  3. 数据加载、布局计算、节点渲染
  4. 异步调用插件初始化(setTimeout)
  5. 插件初始化完成

因为插件异步且在脑图初始化渲染后才会被注册,那么自定义渲染函数custom_node_render或者html的逻辑,如果我写在插件中,是不是首次渲染还是走的ViewProvider中的默认单行渲染函数render,如果我要初始化脑图的时候就支持多行渲染,岂不是还需要用户自己再去jsmind的custom_node_render入参传入一个自定义渲染函数才行; 或者我的插件在加载完以后使用插件中编写的custom_node_render方法再重绘一遍脑图(渲染了两次,是不是有性能问题);

你说的确实如此。我上面说的思路其实是这样的:

  1. 你想要的其实并不只是个编辑器,而是想要自定义渲染逻辑。这样的话不需要做插件,而是应该用 custom_node_render;
  2. 这种节点并不是jsmind能直接支持的格式,所以它的数据格式并不是普通的文本;为了支持更方便地编辑这种节点,你才需要实现一个插件;

这是两步操作。

但我理解你希望的是做一个插件,同时支持编辑器和渲染逻辑。那么你可以做一个独立的library,让它包装一下jsmind,比如 multiline-jsmind 在构造你的类时,自动在option里添加 custom_node_render参数和插件。

另一种思路是你让编辑器生成jsmind能渲染的格式,这样就只需要做editor,为了能够实现你说的保存和再次编辑,你可以在插件里同时把你的特殊的格式保存到节点的 data 里,这样相当于node的topic里保存的是jsmind能直接渲染的数据,data里保存的是editor要使用的格式,相当于把生成的数据和源码一起存起来了。

@UmbraCi
Copy link
Contributor Author

UmbraCi commented Oct 2, 2025

当前插件系统异步初始化, 插件在渲染后才初始化,无法直接影响初始渲染,初始化渲染的逻辑在ViewProvider 类中,且打包出来的UMD 模块有作用域隔离。 在实现多行文本功能,我需要覆写ViewProvider的render函数以及edit相关逻辑,目前想到的方案是:

  • 通过原型链覆盖ViewProvider中的render方法;
  • 脑图被原始render函数初始化后,使用覆盖后的render方法再渲染一次;
    但是这带来了额外的性能开销,请问是否考虑增加一个参数来让插件从【运行时动态加载插件】改为,初始化jsmind类时【同步加载插件】呢,这个逻辑可以由我来写;

这个插件是一个 editor 吧,它为什么需要在初始化的时候加载呢?在脑图没有画出来之前就已经需要用到 editor 了吗?还是说这个插件其实也修改了 render 逻辑?如果修改了,那为什么需要修改呢?

因为如果需要脑图的节点支持多行文本,那么需要1.渲染多行文本功能;2.编辑多行文本功能;3.编辑后的保存多行文本功能; 插件的加载是异步的,且init函数在首次渲染之前,此时,show()函数依赖的是ViewProvider的render方法,我的设想是这个插件也会覆写默认的render方法,从而让节点支持显示多行文本。 我在想,是不是可以让插件系统支持同步的方式加载插件,从而把覆写核心类的权限也开放给插件,并且让插件支持【预加载】(在show方法之前)

目前的可以支持多行文本,只需要按 html 的方式去支持就好了。 如果你需要用不同的渲染逻辑来支持多行文本,那其实是在定义另一种数据格式,如果是这样的话,你可以使用 custom_node_render,并且在你的插件里对这种节点进行更好的编辑支持。

还有个问题,目前jsmind的插件流程如下:

  1. jsMind 实例创建
  2. 调用 show() 方法
  3. 数据加载、布局计算、节点渲染
  4. 异步调用插件初始化(setTimeout)
  5. 插件初始化完成

因为插件异步且在脑图初始化渲染后才会被注册,那么自定义渲染函数custom_node_render或者html的逻辑,如果我写在插件中,是不是首次渲染还是走的ViewProvider中的默认单行渲染函数render,如果我要初始化脑图的时候就支持多行渲染,岂不是还需要用户自己再去jsmind的custom_node_render入参传入一个自定义渲染函数才行; 或者我的插件在加载完以后使用插件中编写的custom_node_render方法再重绘一遍脑图(渲染了两次,是不是有性能问题);

你说的确实如此。我上面说的思路其实是这样的:

  1. 你想要的其实并不只是个编辑器,而是想要自定义渲染逻辑。这样的话不需要做插件,而是应该用 custom_node_render;
  2. 这种节点并不是jsmind能直接支持的格式,所以它的数据格式并不是普通的文本;为了支持更方便地编辑这种节点,你才需要实现一个插件;

这是两步操作。
但我理解你希望的是做一个插件,同时支持编辑器和渲染逻辑。那么你可以做一个独立的library,让它包装一下jsmind,比如 multiline-jsmind 在构造你的类时,自动在option里添加 custom_node_render参数和插件。
另一种思路是你让编辑器生成jsmind能渲染的格式,这样就只需要做editor,为了能够实现你说的保存和再次编辑,你可以在插件里同时把你的特殊的格式保存到节点的 data 里,这样相当于node的topic里保存的是jsmind能直接渲染的数据,data里保存的是editor要使用的格式,相当于把生成的数据和源码一起存起来了。

考虑了下,其实目前无法直接通过一个插件就增加自定义节点显示和编辑功能,本质是卡在插件加载时序上导致无法覆写jsmind依赖的view等class中的渲染、编辑方法,为了解决这个问题,也可以为了后续其他插件的拓展能力,我能否提个PR给库增加一个同步注册插件方法usePlugin呢,区别于之前的插件在实例化后的异步注册,这样可以让编写的插件可以在实例化之前就对原本的class覆写。我看了下其他两个库例Mind-Elixir-Core、Simple-Mind-Map都是同步式的插件加载,并且也支持插件移除 @hizzgdev

Features:
- Multiline text display with word wrapping
- Contenteditable-based editor for multiline editing
- Auto-expand editor height based on content
- Keyboard shortcuts (Shift+Enter for newline, Enter to save, Esc to cancel)
- Text normalization (trim whitespace, normalize line endings)

Implementation:
- Created src/plugins/jsmind.multiline-text.js plugin
- Added createMultilineRender() function for custom node rendering
- Overrode edit_node_begin/end for contenteditable editor
- Editor matches node dimensions with no border
- Auto-expands height on input without scrollbar

Configuration:
- text_width: Maximum width for multiline text nodes (default: 200)
- line_height: Line height for text (default: '1.5')

Documentation:
- Added English documentation (docs/en/plugin-multiline-text.md)
- Added Chinese documentation (docs/zh/plugin-multiline-text.md)
- Integrated plugin into example/demo.html

Build:
- Added plugin to rollup.config.js
- Fixed external dependency to prevent bundling jsMind core
- Generated UMD build (es6/jsmind.multiline-text.js)

Breaking Changes:
- Removed standalone multiline-text-demo.html (integrated into demo.html)
- Removed .d.ts file (using JSDoc instead)
@UmbraCi UmbraCi force-pushed the feature/add-mult-line-node-plugin branch from fe412dc to 6b0f2ed Compare October 10, 2025 11:06
@UmbraCi
Copy link
Contributor Author

UmbraCi commented Oct 10, 2025

@hizzgdev 重构了下,目前导出一个自定义节点渲染函数,插件init函数修改默认edit行为改成多行文本。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants