CKEditor 4 Table Selection 与 Link 插件集成:多单元格批量加链接的实现原理与手动测试指南

📅 发布时间:2026/10/17 5:27:11
CKEditor 4 Table Selection 与 Link 插件集成:多单元格批量加链接的实现原理与手动测试指南
前端UI组件【免费下载链接】ckeditor4The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.项目地址https://gitcode.com/gh_mirrors/ck/ckeditor4点击查看免费下载导读本文围绕仓库中tests/plugins/tableselection/manual/integrations/link/link.md这一手动测试用例展开深入讲解 CKEditor 4 的 Table Selection表格单元格多选插件与 Link链接插件之间的集成机制当用户一次框选多个表格单元格后按下链接按钮或Ctrl/CmdL快捷键时编辑器如何把同一个链接批量应用到每一个被选中的单元格而不是只作用到第一个单元格。读完本文你将掌握这条链路的完整工作方式——从多单元格假选择fake selection的建立到链接对话框对多范围multi-range选择逐段应用行内样式再到配套的自动集成测试与验收标准。关联文档速览link.md 说了什么被指定的关联文档 link.md 是一份标准的手动测试manual test规范由 Bender 测试框架驱动其文件头携带三条元数据bender-ui: collapsed bender-tags: bug, trac16755, 4.7.0, tp1723 bender-ckeditor-plugins: wysiwygarea, toolbar, tableselection, link, sourcearea, undo, elementspathbender-tags表明该用例关联的是trac16755缺陷对应 4.7.0 版本引入的 Table Selection 功能以及tp1723工单即多单元格选择时应用链接的集成行为bender-ckeditor-plugins列出了测试所需插件集合wysiwygarea经典编辑器的 iframe 承载、toolbar、tableselection、link、sourcearea、undo与elementspath这组插件恰好构成了一次表格多选 链接对话框 撤销回退 路径栏展示的完整闭环bender-ui: collapsed表示该用例在 Bender UI 中以折叠形式呈现。测试步骤与验收标准原文核心内容文档正文要求对每个编辑器都执行以下步骤文档中同时存在 Classic、Divarea、Inline 三种编辑器实例框选多个单元格例如从 Cell 1.1.1 开始、到 Cell 1.3.1 结束的 1 行 × 3 列选择注意这里的 1x3 是按起始行 × 结束列的矩形区域理解实际选中的是第一列自上而下的三个单元格按下工具栏上的Link按钮在 URL 输入框中输入foobar.com点击OK关闭对话框。Expected期望行为链接被应用到每一个被选中的单元格上。Unexpected缺陷行为链接只被应用到了第一个单元格上。键盘路径改用测试用例 1 的步骤但不用鼠标点击 Link 按钮而是按ctrl/cmdl快捷键触发同样的命令。这条期望 vs 非期望的对比正是该集成点要守护的核心回归场景表格多选状态必须被链接命令完整消费而不是退化成普通文本选区。测试页面结构三种编辑器形态的覆盖与 link.md 配对的 link.html 构建了三种编辑器形态保证测试覆盖不同承载方式Classic editor经典编辑器CKEDITOR.replace( editor1 )基于 iframewysiwygareaDivarea editorCKEDITOR.replace( editor2, { extraPlugins: divarea } )用div模拟编辑区Inline editor内联编辑器CKEDITOR.inline( editor3, { extraPlugins: floatingspace } )直接对contenteditabletrue的元素初始化。每个编辑器内的表格结构一致均为 3 行 × 4 列table border1 tr tdCell 1.1.1/td tdCell 1.1.2/td tdCell 1.1.3/td tdCell 1.1.4/td /tr !-- 第 2、3 行结构相同单元格依次为 Cell 1.2.x / Cell 1.3.x -- /table页面脚本还做了两处环境防护这是 CKEditor 4 手动测试的惯例if ( bender.tools.env.mobile ) { bender.ignore(); // 移动端直接跳过该用例 } bender.tools.ignoreUnsupportedEnvironment( tableselection ); // 不支持 tableselection 的环境跳过也就是说该用例只在桌面端、且浏览器能力满足 Table Selection 要求的环境中执行。源码纵深批量加链接是如何实现的第一步多单元格选择 多范围multi-range选择Table Selection 插件的核心思路是把框选一片单元格翻译成多个 DOM Range 的选区。在 plugins/tableselection/plugin.js 中fakeSelectCells对每个单元格各创建一个范围并一次性选中function fakeSelectCells( editor, cells ) { var ranges [], range, i; for ( i 0; i cells.length; i ) { range editor.createRange(); range.setStartBefore( cells[ i ] ); range.setEndAfter( cells[ i ] ); ranges.push( range ); } editor.getSelection().selectRanges( ranges ); }选中后被选中的单元格会统一打上cke_table-faked-selection样式类见 plugin.js 中的fakeSelectedClass同时编辑器容器加cke_table-faked-selection-editor类表格本身记录cke-table-faked-selection-table数据属性。这一整套假选择状态由 fakeSelectionChangeHandler 维护检测到selection.isFake且位于表格内时就调用getSelectedCells还原出所有单元格并加样式。值得注意的是getSelectedCells并非 tableselection 自己实现而是从 Tabletools 插件取来的别名plugin.jstabletools CKEDITOR.plugins.tabletools; getSelectedCells tabletools.getSelectedCells;tabletools.getSelectedCellsplugins/tabletools/plugin.js会遍历选区的所有范围把每个范围内经过的td/th收集起来——这从数据层面保证了多单元格确实是以一组 range的形式存在。第二步链接对话框把样式应用到每一个 range当用户点击 Link 按钮或按Ctrl/CmdL时触发的是link命令。该命令在 plugins/link/plugin.js 中注册为对话框命令editor.addCommand( link, new CKEDITOR.dialogCommand( link, { allowedContent: allowed, requiredContent: required } ) );快捷键也在同一文件中绑定plugin.jseditor.setKeystroke( CKEDITOR.CTRL 76 /*L*/, link ); editor.setKeystroke( CKEDITOR.CTRL 75 /*K*/, link ); // (#2478)对话框确认后真正批量应用链接的逻辑在 plugins/link/dialogs/link.js 的insertLinksIntoSelection中。它遍历editor.getSelection().getRanges()对每一个 range单独处理function insertLinksIntoSelection( editor, data ) { var attributes plugin.getLinkAttributes( editor, data ), ranges editor.getSelection().getRanges(), style new CKEDITOR.style( { element: a, attributes: attributes.set } ), rangesToSelect [], range, text, nestedLinks, i, j; style.type CKEDITOR.STYLE_INLINE; for ( i 0; i ranges.length; i ) { range ranges[ i ]; // 折叠光标时插入一个以 URL 为文本的 a if ( range.collapsed ) { ... } // 否则先移除范围内已嵌套的 a再对整个 range 应用行内链接样式 else { nestedLinks range._find( a ); for ( j 0; j nestedLinks.length; j ) { nestedLinks[ j ].remove( true ); } style.applyToRange( range, editor ); rangesToSelect.push( range ); } } editor.getSelection().selectRanges( rangesToSelect ); }关键点在于tableselection 的多单元格选择天然是多 range 选区因此insertLinksIntoSelection的循环会逐单元格执行style.applyToRange把a href...行内样式套到每个单元格的内容上——这正是链接应用到每个被选中单元格的机制来源。如果选区只有一个 range例如只选中了一个单元格则只会应用一次。第三步编辑已有链接时如何命中多个aedit.mdtests/plugins/tableselection/manual/integrations/link/edit.md对应工单 tp2245验证的是编辑路径先给两个单元格加链接再只选中第二个单元格重新打开对话框期望看到修改过的值而非默认值。这依赖CKEDITOR.plugins.link.getSelectedLink( editor, returnMultiple )plugins/link/plugin.js。当传入returnMultiple true时它对选区的每个 range 都执行一次range.shrink( CKEDITOR.SHRINK_ELEMENT, true, { skipBogus: true } )再从公共祖先的元素路径中向上查找a元素收集全部链接for ( var i 0; i ranges.length; i ) { range selection.getRanges()[ i ]; // Skip bogus to cover cases of multiple selection inside tables (#tp2245). range.shrink( CKEDITOR.SHRINK_ELEMENT, true, { skipBogus: true } ); link editor.elementPath( range.getCommonAncestor() ).contains( a, 1 ); if ( link returnMultiple ) { links.push( link ); } else if ( link ) { return link; } } return returnMultiple ? links : null;源码注释明确写道#tp2245场景需要skipBogus: true——这正是 edit.md 用例所回归的缺陷单元格里的br填充符bogus node导致getSelectedLink找不到链接从而对话框回退到默认值。对话框的getModelplugins/link/dialogs/link.js正是以getSelectedLink( editor, true )的结果作为编辑模型onOk时若存在已选中的链接元素则走editLinksInSelectiondialogs/link.js逐个元素setAttributes/removeAttributes覆盖并重新选中。第四步显示文本Display Text字段的显隐规则同目录的text.mdtests/plugins/tableselection/manual/integrations/link/text.md对应 tp2231验证的是另一个细节在普通文本选区foo [bar] baz上按Ctrl/CmdL时链接对话框必须显示Display Text显示文本字段。其判定逻辑在 plugins/link/plugin.js 的showDisplayTextForElementshowDisplayTextForElement: function( element, editor ) { var undesiredElements { img: 1, table: 1, tbody: 1, thead: 1, tfoot: 1, input: 1, select: 1, textarea: 1 }, selection editor.getSelection(); // Widget duck typingwidget 不显示显示文本 if ( editor.widgets editor.widgets.focused ) { return false; } // 多个 range 的选区例如多单元格选择不显示显示文本 if ( selection selection.getRanges().length 1 ) { return false; } return !element || !element.getName || !element.is( undesiredElements ); }对话框在onShowdialogs/link.js中结合选中链接数量共同决策if ( elements.length 1 plugin.showDisplayTextForElement( firstLink, editor ) ) { displayTextField.show(); } else { displayTextField.hide(); }可以看到设计意图很清晰普通文本选区是给这段文字加链接需要让用户自定义显示文本而多单元格/多链接的批量场景没有统一的文本语义因此隐藏该字段只保留 URL 等属性输入。这也解释了为什么 link.md 的主用例不涉及 Display Text 字段。自动化集成测试同一行为的机器验证除手动测试外仓库还提供了对应的自动化集成测试 tests/plugins/tableselection/integrations/link/link.js头部声明/* bender-tags: tableselection, link */ /* bender-ckeditor-plugins: link,tableselection */ /* bender-include: ../../_helpers/tableselection.js */测试通过tableSelectionHelpers.getRangesForCells为指定单元格构造多 range 选区然后以 Bender 的editorBot.dialog( link, ... )方式驱动真实对话框。用例清单覆盖了本文讨论的全部行为测试用例验证点test create link单选单元格加链接期望 Display Text 字段可见URL 正确写入test create link on multiple cells多选单元格加链接期望 Display Text 字段隐藏所有单元格都带上a href对照table-with-linksfixturetest edit link (text selected)多选已加链接的单元格并改 URL期望全部链接被更新test get link info from the cell with br filler#tp2245单元格含br填充符时对话框仍能回读正确的 URL 与协议https://test unlink command多选已链接单元格执行 unlink期望链接全部移除test getSelectedLink for table selection (links)getSelectedLink( editor, true )能按 DOM 顺序返回全部选中链接test create anchor/test edit anchor/test removeAnchor command/test getSelectedLink ... (anchors)锚点a[name]在多单元格选择下的创建、编辑、删除与读取其中各测试的输入/期望 HTML 都来自同目录的 link.htmlfixtures例如多链接场景table-with-links期望输出为两个单元格分别包裹a hrefhttp://ckeditor.com。自动测试与手动测试互为印证手动用例验证真实交互手感自动用例守护同一行为不回归。相关配置项调整链接行为的几个开关结合 plugins/link/plugin.js 中CKEDITOR.tools.extend( CKEDITOR.config, ... )声明的配置与表格集成相关且常用的选项如下配置项默认值说明linkDefaultProtocolhttp://链接对话框默认协议可取http://、https://、ftp://、news://或空串other选项。edit.md 用例即涉及修改协议后重新打开对话框应显示修改后的值linkShowAdvancedTabtrue是否显示高级标签页linkShowTargetTabtrue是否显示目标标签页linkJavaScriptLinksAllowedfalse是否允许javascript:协议的链接通过对话框校验linkPhoneRegExp/linkPhoneMsg未设置电话链接tel:类型的可选校验正则与提示文案配置示例CKEDITOR.replace( editor, { extraPlugins: tableselection, linkDefaultProtocol: https://, linkShowAdvancedTab: false } );如何运行与验收手动测试用例由仓库自带的 Bender 测试框架驱动配置见 bender.js、bender.ci.js 与 bender-runner.config.json。在 Bender 中打开 link.md 对应的用例页面后按以下清单验收创建链接鼠标路径在任一编辑器中从 Cell 1.1.1 拖选到 Cell 1.3.1点击 Link 按钮输入foobar.com并确定——三个单元格内容都应被a包裹且sourcearea视图可见该结构创建链接键盘路径同样选区下按Ctrl/CmdL重复上述操作行为应与按钮一致编辑链接对应 edit.md给首行两个单元格加链接例如https://foo再只选中第二个单元格打开对话框URL 与协议应显示已修改的值显示文本字段对应 text.md在普通段落文本上按Ctrl/CmdL对话框应出现 Display Text 字段而在多单元格选区上打开对话框时该字段应被隐藏撤销回退执行加链接后按撤销表格应恢复原状用例插件清单中包含undo正是为了覆盖该回归点。以上任一步骤出现链接只应用到第一个单元格、对话框显示默认值而非修改值、或 Display Text 字段异常显隐即视为回归缺陷。相关文件索引手动测试用例link.md、link.html配套手动用例edit.md、text.md自动化集成测试integrations/link/link.js 与 integrations/link/link.html核心实现plugins/tableselection/plugin.js、plugins/link/plugin.js、plugins/link/dialogs/link.js、plugins/tabletools/plugin.js测试框架配置bender.js、bender-runner.config.json赞分享前端UI组件【免费下载链接】ckeditor4The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.项目地址https://gitcode.com/gh_mirrors/ck/ckeditor4点击查看免费下载相关推荐Pandoc Org 读取器 EXCLUDE_TAGS 标签排除机制详解以 4284 回归测试为线索Pandoc Org 读取器 EXCLUDE_TAGS 标签排除机制详解以 4284 回归测试为线索 导读 本文以 pandoc 仓库中的回归测试 test前端UI组件CKEditor 4 Table Selection 手动测试指南带 caption 表格的单元格选择验证CKEditor 4 Table Selection 手动测试指南带 caption 表格的单元格选择验证 导读 本文以 CKEditor 4 官方手动测试用前端UI组件CKEditor 4 Easy Image 插件与表格单元格选择Table Selection的交互ticket 1542 手动测试全解析CKEditor 4 Easy Image 插件与表格单元格选择Table Selection的交互ticket 1542 手动测试全解析 导读 本文围绕前端UI组件上一篇革命性动态配置工具django-constance5分钟实现Django设置热更新下一篇【亲测免费】 DevOS开发者的操作系统创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考