Joplin 富文本编辑器中的 joplinLists 插件:TinyMCE 列表插件的分支改造与构建流程 📅 发布时间:2026/9/7 14:12:12 👁 浏览次数: Joplin 富文本编辑器中的 joplinLists 插件TinyMCE 列表插件的分支改造与构建流程【免费下载链接】joplinJoplin - the privacy-focused note taking app with sync capabilities for Windows, macOS, Linux, Android and iOS.项目地址: https://gitcode.com/GitHub_Trending/jo/joplinJoplin 桌面端Electron在富文本模式下使用 TinyMCE 作为底层编辑器而其中处理列表缩进、键盘删除与列表切换的lists插件并不直接使用官方原版而是由 Joplin 仓库内 fork 改造而来的joplinLists插件注册名为joplinLists。本文基于仓库文档Assets/TinyMCE/JoplinLists/README.md完整梳理该插件的来历、构建与调试流程并结合插件源码Plugin.ts、Commands.ts、JoplinListUtil.ts与 Gruntfile 构建脚本说明 Joplin 复选框checklist在富文本列表体系中的实现方式与产物去向。读完本文读者将理解该插件如何注册编辑器命令、joplin-checklist类名如何驱动“插入/勾选清单条目”两个自定义命令以及如何用npm run build与buildAndStart完成编译与桌面端联调。插件定位官方 TinyMCE lists 插件的 Joplin 分支README 开门见山地说明了该模块的两点关键信息代码来源它基于 TinyMCE 官方lists插件的某一历史提交tinymce/tinymce仓库中modules/tinymce/src/plugins/lists路径下的代码在 Joplin 仓库内以独立目录Assets/TinyMCE/JoplinLists/维护改造目标在保留官方列表能力的基础上增加对Joplin 复选框checklist的支持——这正是 Joplin 笔记中- [ ]/- [x]语法在富文本编辑器内的表现载体。从源码结构看该插件是一个标准的 TinyMCE 插件工程src/main/ts/下按 TinyMCE 官方插件的典型目录组织划分为actions/如ToggleList.ts、Indendation.ts、api/Api.ts、Commands.ts、Events.ts、Settings.ts、core/Keyboard.ts、Mouse.ts、Delete.ts、SplitList.ts等与listModel/列表模型层含ParseLists.ts、NormalizeEntries.ts等。官方插件中的核心逻辑键盘操作、鼠标拖拽缩进、列表拆分与规范化被整体保留Joplin 的改造集中在两处api/Commands.ts与listModel/JoplinListUtil.ts。一个需要特别留意的仓库事实来自 README 顶部的警告自 2020-11-02 起该模块已无法直接构建出现大量 TypeScript 报错且作者表示未查明原因。这意味着当前仓库中的Assets/TinyMCE/JoplinLists/处于“源码在位、但构建链路已断”的状态桌面端实际使用的插件产物是此前构建并拷贝进去的编译文件。这一点决定了后文“构建”一节只能作为流程性参考而非当前可直接跑通的构建脚本。插件注册机制joplinLists名称从何而来入口文件 Main.ts 仅做一件事——调用Plugin()完成副作用式注册并明确注释“不要导出任何内容否则 Rollup 会在页面上留下全局变量”import Plugin from ./Plugin; Plugin();Plugin.ts 通过 TinyMCE 的PluginManager.add把插件注册为joplinLists而非官方lists这是 Joplin 能够与官方列表插件并存、互不覆盖的关键export default function () { PluginManager.add(joplinLists, function (editor) { Keyboard.setup(editor); Mouse.setup(editor); Buttons.register(editor); Commands.register(editor); return Api.get(editor); }); }注册时依次挂载了四个子系统键盘快捷键Tab/ShiftTab 缩进、Delete/Backspace 删除、鼠标行为、工具栏按钮与编辑器命令。其中Commands.register(editor)是本文重点它把官方的InsertUnorderedList/InsertOrderedList/InsertDefinitionList/RemoveList命令桥接到ToggleList.toggleList与缩进动作上并在末尾调用了 Joplin 的扩展入口addJoplinChecklistCommands(editor, ToggleList)见 Commands.ts。该插件名最终在桌面端编辑器配置中生效。TinyMCE.tsx 在初始化 TinyMCE 时加载本地脚本gui/NoteEditor/NoteBody/TinyMCE/plugins/lists.js约 L382并将插件列表配置为plugins: link joplinLists searchreplace codesample table约 L732。从源码结构看joplinLists替代了官方lists的位置成为富文本编辑器中列表行为的唯一提供方。Joplin 复选框扩展joplin-checklist类名与两条自定义命令Joplin 清单在 HTML 中的表示方式是在无序列表ul上添加joplin-checklist类被勾选的条目li上再添加checked类。整个扩展逻辑集中在 JoplinListUtil.ts核心函数包括isCheckboxListItem(element)判断某个元素是否带有joplin-checklist类以此区分“普通列表容器”与“清单容器”findContainerListTypeFromEvent/findContainerListTypeFromElement从事件元素或 DOM 节点向上查找最近的UL/OL祖先返回joplinChecklist或regular供点击、键盘等交互判断当前所处列表类型isJoplinChecklistItem(element)确认某li是否属于清单节点名必须是LI且容器类型为清单。在此基础上addJoplinChecklistCommands(editor, ToggleList)向编辑器注入两条 TinyMCE 自定义命令editor.addCommand(ToggleJoplinChecklistItem, function (ui, detail) { const element detail.element; if (!isJoplinChecklistItem(element)) return; if (!element.classList || !element.classList.contains(checked)) { element.classList.add(checked); } else { element.classList.remove(checked); } }); editor.addCommand(InsertJoplinChecklist, function (ui, detail) { detail { ...detail, listType: joplinChecklist }; ToggleList.toggleList(editor, UL, detail); });两条命令的分工清晰命令触发语义实现行为ToggleJoplinChecklistItem点击/切换已有清单条目的勾选状态校验目标LI确属清单后对checked类做增删实现勾选/取消勾选InsertJoplinChecklist插入一个新的清单复用官方ToggleList.toggleList(editor, UL, ...)仅把detail.listType标记为joplinChecklist使生成的UL带上清单类名这种“复用官方 toggleList、仅改 detail 参数”的做法保证了清单的插入路径与普通无序列表共用同一套列表规范化与缩进逻辑Joplin 的侵入面被控制在Commands.ts的一个注册调用与JoplinListUtil.ts的少量工具函数内。与渲染层的呼应同样可见于 renderer 的复选框样式 与 MdToHtml 的 checkbox 规则Markdown 侧的- [ ]/- [x]与 HTML 侧的joplin-checklist/checked类名构成一条完整的往返链路。构建流程npm i npm run build与buildAndStart回到 README 给出的两条核心命令。对照 package.json其含义如下npm i npm run buildnpm i安装该子工程的 devDependencies关键依赖为 TinyMCE 官方开发链工具grunt、ephox/swagTinyMCE 构建工具集、rollup经 swag 提供、ts-loader/awesome-typescript-loader、typescript^3.1.6、webpack^4.25.1等npm run build实际执行grunt即运行 Gruntfile.js 中注册的default任务clean → shell → rollup → uglify → concat → copy。各步骤职责依据 Gruntfile.jsclean清理dist与scratch目录shell执行tsc --project tsconfig.json将src/main/ts编译为lib/Main.jsrollup把lib/Main.js打包为 IIFE 模块scratch/compiled/joplinLists.js外部化externaltinymce/core/api/*一系列模块并映射到tinymce.PluginManager、tinymce.util.VK等运行时全局——这保证产物不内嵌 TinyMCE 核心体积小且不产生双实例uglify压缩生成scratch/compiled/joplinLists.min.jsconcat拼接src/text/license-header.js头注释替换BUILD_NUMBER占位符产出dist/joplinLists.js与dist/joplinLists.min.jscopy对 Joplin 而言最关键的一步将dist/joplinLists.js拷贝到../../../packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/plugins/lists.js即 packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/plugins/lists.js。这正是上文TinyMCE.tsx中src字段指向的文件——构建脚本直接完成了“插件产物进入桌面应用”的最后一公里无需人工搬运。第二条命令用于插件改动后的端到端联调npm run buildAndStart在 package.json 中其定义为buildAndStart: yarn build cd .. cd .. cd .. cd packages/app-desktop npm start先完成上述整套插件构建含拷贝到 app-desktop再进入packages/app-desktop执行npm start启动桌面端应用。流程上这是“改插件 → 自动落位 → 起桌面端验证”的闭环对应 README 所说的 “build the plugin and start the desktop application”。需要再次强调的前提由于 README 明确记载 2020-11-02 后该模块出现大量 TypeScript 错误而无法构建上述流程描述的是仓库中脚本所定义的设计流程在当前代码状态下直接执行npm run build是否可通过以实际运行结果为准仓库并未给出修复说明。对修改该插件的实操建议综合以上源码证据若未来需要再次修改该插件可以按以下路径推进定位行为归属列表切换/缩进/命令层改动看 src/main/ts/api/Commands.ts 与 actions/ 目录ToggleList.ts、Indendation.ts清单专属逻辑集中在 listModel/JoplinListUtil.ts键盘/删除行为在 core/ 目录Keyboard.ts、Delete.ts、SplitList.ts等保持注册名不变Plugin.ts中注册的joplinLists名称与TinyMCE.tsx的plugins配置一一对应改名会直接导致插件失效保持产物路径不变构建后必须仍落在packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/plugins/lists.js否则桌面端加载的是旧产物调试时会误判“改动未生效”验证闭环优先用npm run buildAndStart在真实桌面端验证键盘缩进、清单勾选、跨列表复制粘贴等行为依赖编辑器运行时上下文单看单元测试无法覆盖 TinyMCE 的 DOM 交互细节——该子工程的test脚本bedrock-auto同样依赖 TinyMCE 官方测试框架且受构建链路阻塞影响实际可用性需以运行时行为为准注意 TypeScript 版本约束devDependencies 锁定typescript^3.1.6与webpack^4.25.1README 所述“大量 TS 错误”很可能与 TinyMCE 类型定义升级后不兼容有关重建构建链时应优先对齐这些旧版本约束或使用transpileOnly类策略绕过严格检查webpack 配置中ts-loader已设置transpileOnly: true即为同类思路的体现。小结Assets/TinyMCE/JoplinLists/是 Joplin 桌面端富文本编辑器列表能力的定制层它以 TinyMCE 官方lists插件为基座在 Plugin.ts 中以joplinLists之名注册在 JoplinListUtil.ts 中用joplin-checklist/checked类名和InsertJoplinChecklist、ToggleJoplinChecklistItem两条命令扩展出 Joplin 清单能力并通过 Gruntfile.js 的clean → tsc → rollup → uglify → concat → copy流水线把产物直接投放到packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/plugins/lists.js。npm i npm run build与npm run buildAndStart分别对应“纯构建落位”和“构建 启动桌面端”两种工作方式。由于仓库文档明确标注该模块自 2020-11-02 起构建已中断当前仓库中桌面端使用的lists.js属于历史构建产物理解上述注册、命令与拷贝链路是后续排查清单行为或重建构建流程的基础。【免费下载链接】joplinJoplin - the privacy-focused note taking app with sync capabilities for Windows, macOS, Linux, Android and iOS.项目地址: https://gitcode.com/GitHub_Trending/jo/joplin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考