news 2026/10/17 1:49:18

CKEditor 4 嵌套表格中图片右键菜单集成修复:2235 手动测试指南与源码解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CKEditor 4 嵌套表格中图片右键菜单集成修复:2235 手动测试指南与源码解析
  • 前端
  • UI组件

【免费下载链接】ckeditor4

The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.

项目地址:https://gitcode.com/gh_mirrors/ck/ckeditor4
点击查看免费下载

本文以 CKEditor 4 仓库中的手动测试文档 nestedimage.md 为核心骨架,围绕 Table Selection(tableselection)插件与 Image(image)插件在嵌套表格场景下的交互,完整解读其两个验证场景,并结合 plugins/tableselection/plugin.js 与 plugins/image/plugin.js 的源码实现,还原 #2235 缺陷的成因、修复方式与自动化回归测试,帮助开发者理解表格选区与图片编辑之间的边界处理。

测试文档定位:一个针对 #2235 缺陷回归的手动测试

tests/plugins/tableselection/manual/integrations/image/nestedimage.md是 CKEditor 4 的 Bender 手动测试用例,其文件头部的元数据明确了它的身份与验证目标:

@bender-ui: collapsed @bender-tags: bug, 2235, 4.12.0 @bender-ckeditor-plugins: wysiwygarea, tableselection, image, undo
  • @bender-tags: bug, 2235, 4.12.0:表明该用例是bug 回归测试,对应缺陷编号#2235,自4.12.0版本起纳入验证范围。
  • @bender-ckeditor-plugins: wysiwygarea, tableselection, image, undo:声明测试所需的插件集合——经典的wysiwygarea编辑区、本测试的主角tableselection(表格选区)、image(图片)以及undo(撤销)。undo的存在说明该场景还关注删除操作的可撤销性。

该缺陷在 CHANGES.md 的 4.12.0 版本发布说明中有明确记载:

Fixed: An Image in a table cell has an empty URL field when edited from the context menu opened by right-click when the Table Selection plugin is in use.

翻译过来即:当 Table Selection 插件启用时,通过右键打开上下文菜单编辑表格单元格内的图片,会出现URL 字段为空的异常。本手动测试就是用来验证该修复是否生效,以及是否引入了新的回归。

测试场景一:右键图片编辑"图片属性"

文档的第一个场景验证的是 #2235 的核心症状——上下文菜单编辑图片时 URL 丢失:

操作步骤:

  1. 右键点击图片,打开上下文菜单(Context menu)。
  2. 选择Image properties(图片属性)。

期望结果(Expected result):

  • URL 字段应已填充(即当前图片的src应显示在对话框中);
  • 预览区域应能看到图片。

异常结果(Unexpected result):

  • URL 字段为空;
  • 或预览区域无法显示图片。

场景一的缺陷成因:表格选区"吞掉"了图片选择

要理解为什么会出现"URL 字段为空",需要回到 Table Selection 插件的行为。该插件通过给选中单元格添加cke_table-faked-selection类来模拟"假选中"(fake selection),从而支持跨单元格的选区、复制、删除等操作。

在 plugins/tableselection/plugin.js 的fakeSelectionChangeHandler中,有这样一个关键判断:

var enclosedNode = ranges && ranges[ 0 ].getEnclosedNode(), isEnclosedNodeAnImage = enclosedNode && ( enclosedNode.type == CKEDITOR.NODE_ELEMENT ) && enclosedNode.is( 'img' ), ... // Don't perform fake selection when image is selected (#2235). if ( isEnclosedNodeAnImage ) { editor.getSelection().reset(); return; }

修复前的行为是:当用户选中表格单元格里的图片时,selectionCheck事件触发后,tableselection 会把整格做成 fake selection(给单元格加cke_table-faked-selection类)。此时编辑器"真正的选择"被重置为单元格级的伪选区,图片元素本身不再处于被选中状态。于是当用户在图片上右键打开上下文菜单并选择Image properties时,Image 插件的对话框读取不到当前的图片元素,URL 字段自然就是空的。

修复后,fakeSelectionChangeHandler会先检查选区封闭节点(enclosed node)是否为img元素:若是,则放弃 fake selection(editor.getSelection().reset()后直接返回),把真正的选择权交还给图片本身。这样 Image 对话框就能正确读取src并填充 URL 字段与预览。

配套的自动化回归测试位于 tests/plugins/tableselection/integrations/image/imageurl.js,其测试夹具 imageurl.html 构建了同样的嵌套表格结构,断言:

'Is whole cell fake selected when img inside is selected': function() { ... assert.isFalse( editor.getSelection().getSelectedElement().hasClass( 'cke_table-faked-selection' ) ); }

即:当图片被选中时,整格不应被加上 fake selection 类——这正是场景一期望结果在源码层的直接体现。

场景一的菜单来源:Image 插件的上下文菜单注册

Image properties菜单项并非 tableselection 提供,而是 Image 插件在 plugins/image/plugin.js 中注册的:

// If the "menu" plugin is loaded, register the menu items. if ( editor.addMenuItems ) { editor.addMenuItems( { image: { label: editor.lang.image.menu, command: 'image', group: 'image' } } ); } // If the "contextmenu" plugin is loaded, register the listeners. if ( editor.contextMenu ) { editor.contextMenu.addListener( function( element ) { if ( getSelectedImage( editor, element ) ) return { image: CKEDITOR.TRISTATE_OFF }; } ); }

菜单项image对应的命令正是image(一个CKEDITOR.dialogCommand,由同文件 L38-L45 注册),执行后打开dialogs/image.js中的图片属性对话框。上下文菜单监听器通过getSelectedImage( editor, element )判断右键目标是否为可编辑图片,命中则激活菜单项。而getSelectedImage依赖编辑器当前的选区状态——这再次印证了上一节的分析:只有图片真正处于选中状态,对话框才能拿到正确的图片元素并回填 URL。

测试场景二:删除外层表格行后图片仍可被选中

文档的第二个场景验证的是修复方案不能引入的回归:

操作步骤:

  1. 选中外层表格的第一行并删除。
  2. 再次点击图片。

期望结果(Expected result):

  • 图片能够被选中。

异常结果(Unexpected result):

  • 图片无法被选中。

场景二的源码逻辑:删除命令与选区的联动

场景二涉及 Table Selection 与表格行删除命令的交互。在 plugins/tableselection/plugin.js 中,插件对cellDelete(单元格删除)命令做了定制化包装:

customizeTableCommand( editor, [ 'cellDelete' ], function( editor ) { clearFakeCellSelection( editor, true ); } );

customizeTableCommand(plugin.js)通过在beforeCommandExec与afterCommandExec钩子中记录selectedCells并执行回调,让表格命令与 fake selection 状态保持同步。行删除(rowDelete)同样走这一机制(L1247-L1256 附近的命令列表包含行插入/删除类命令,统一在afterCommandExec中调用fakeSelectCells重建选区)。

删除外层表格第一行后,若 fake selection 标记(cke_table-faked-selection类、cke_table-faked-selection-table数据属性)残留或选择状态错乱,后续点击图片时可能无法正确建立选区,导致"图片无法选中"。文档要求验证删除操作后图片点击行为仍正常,本质上是验证fake selection 的清理与重建链路在嵌套表格结构下的健壮性。

嵌套表格的特殊性:被当作"同一张表"

场景二特意使用嵌套表格,是因为 Table Selection 对嵌套表格有一套特殊处理。在 plugins/tableselection/plugin.js 的鼠标处理器中:

// Nested tables should be treated as the same one (e.g. user starts dragging from outer table // and ends in inner one). function isSameTable( selectedTable, table ) { if ( !selectedTable || !table ) { return false; } return selectedTable.equals( table ) || selectedTable.contains( table ) || table.contains( selectedTable ) || selectedTable.getCommonAncestor( table ).is( tableElements ); }

isSameTable允许选中范围跨越外层表与内层表(只要二者存在包含关系或共享表格类祖先),并在mouseup时通过restoreFakeSelection( editor )(L366-L373)重建选区。此外,getCellsBetween(L24-L92)也专门注释了"支持从外层表开始、在内层表结束的选区"(L38-L42)。这些设计都是为了保证嵌套表格场景下 fake selection 的起止位置正确,从而让删除行等操作不会破坏后续的图片点击选中行为。

同目录下的自动化测试 tests/plugins/tableselection/integrations/core/selection.js 也覆盖了相关边界:L883-L924 的'test simulating opening context menu in the nested table'模拟在嵌套表格中打开上下文菜单,断言 fake selection 状态与多选区完整;L1056 起还专门为 WebKit/macOS 编写了变体用例,因为 WebKit 系浏览器在上下文菜单点击时会折叠选区并锚定到文本节点。这些测试与手动测试文档互相印证,共同保障嵌套表格场景的稳定。

测试夹具:nestedimage.html 中的嵌套表格结构

手动测试对应的 HTML 夹具位于 tests/plugins/tableselection/manual/integrations/image/nestedimage.html,结构为外层 2×2 表格 + 内层 2×2 表格:

<div id="editor"> <table border="1" cellpadding="5" cellspacing="5" style="width:500px"> <tbody> <tr> <td>&nbsp;</td> <td>&nbsp;</td> </tr> <tr> <td> <table border="1" cellpadding="5" cellspacing="5" style="width:300px"> <tbody> <tr> <td><img alt="" src="%BASE_PATH%_assets/lena.jpg" style="height:100px; width:100px"/></td> <td>&nbsp;</td> </tr> <tr> <td>&nbsp;</td> <td>&nbsp;</td> </tr> </tbody> </table> <p>&nbsp;</p> </td> <td>&nbsp;</td> </tr> </tbody> </table> </div>

关键细节:

  • 图片位于内层表格左上角单元格,src指向测试资产%BASE_PATH%_assets/lena.jpg(tests/_assets/lena.jpg),并显式设置了height:100px; width:100px;
  • 内层表格嵌套在外层表格左下角单元格内,正是场景二"删除外层表格第一行"后结构变化的基础;
  • 夹具末尾(L30-L35)包含环境判断:Table Selection 插件在 IE 11 以下不可用(与isSupportedEnvironment中!( CKEDITOR.env.ie && CKEDITOR.env.version < 11 )的声明一致),因此 IE < 11 环境下直接bender.ignore()跳过测试。

如何运行该手动测试

本用例是 Bender 手动测试(manual test),运行方式遵循仓库的 Bender 测试体系:

  1. 仓库根目录的 bender.js 是 Bender 配置入口,声明了测试框架(YUI)、插件列表(benderjs-yui、benderjs-sinon、benderjs-jquery等)以及测试分组与路径;
  2. 启动 Bender 服务后,手动测试会以独立页面形式在浏览器中打开,由测试人员按文档步骤操作并人工核对"期望结果 / 异常结果";
  3. 由于手动测试依赖真实浏览器交互(右键菜单、鼠标点击),无法被自动化断言完全替代,因此文档中每个场景都同时给出了期望与异常两条判据,供测试人员对照判定。

自动化层面,tests/plugins/tableselection/integrations/下的imageurl.js、selection.js、clipboard/pastenested.js(嵌套表格粘贴用例)等组成了该功能的自动化回归网络,与手动用例形成互补。

小结

nestedimage.md虽是一份简短的 Bender 手动测试文档,但它精准锚定了 CKEditor 4 中两个插件协同时的关键边界问题:

  • 场景一验证 #2235 修复——选中图片时不得触发表格 fake selection,保证 Image 对话框能正确回填 URL 与预览,其修复落实在 plugins/tableselection/plugin.js 的图片节点检测分支;
  • 场景二验证删除外层表格行后图片仍可选中,确保表格命令(cellDelete/rowDelete)与 fake selection 清理、重建逻辑在嵌套表格下不产生残留状态。

结合 CHANGES.md 中 4.12.0 的修复记录、imageurl.js的自动化断言以及selection.js中嵌套表格上下文菜单模拟测试,可以完整还原该缺陷的来龙去脉:Table Selection 的"整格选中"策略必须为图片等内联可编辑元素让路,这正是本文档所承载的回归验证意义。

  • 前端
  • UI组件

【免费下载链接】ckeditor4

The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.

项目地址:https://gitcode.com/gh_mirrors/ck/ckeditor4
点击查看免费下载

相关推荐

上一篇:终极Bevy增强现实开发指南:用Rust构建沉浸式AR体验的完整教程
下一篇:Spotube辅助功能:无障碍访问支持

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 1:47:40

Cherry Markdown 文档生成指南:五种格式导出与批量发布一步到位

Cherry Markdown 文档生成指南&#xff1a;五种格式导出与批量发布一步到位 【免费下载链接】cherry-markdown ✨ A Markdown Editor 项目地址: https://gitcode.com/GitHub_Trending/ch/cherry-markdown 在团队知识库或 API 文档的维护场景中&#xff0c;同一份 Markdo…

作者头像 李华
网站建设 2026/10/17 1:47:38

Kettle 8.2 ETL工具实战:安装配置、数据库连接与数据同步

简介&#xff1a;Kettle&#xff08;Pentaho Data Integration&#xff09;8.2.0.0-11 完整发行包&#xff0c;是纯Java编写的开源ETL工具&#xff0c;支持Windows、Linux、Unix跨平台运行&#xff0c;面向数据集成与数据仓库建设场景&#xff0c;适合需要处理异构数据库间数据…

作者头像 李华
网站建设 2026/10/17 1:46:52

Apache中文手册:运维排错决策树与错误日志解码指南

简介&#xff1a;本资源是面向Web服务器初学者与运维人员的《Apache中文手册》完整离线文档包&#xff0c;系统解决Apache安装配置、模块管理、权限控制、性能调优及安全加固等核心实践问题。资源共196个文件&#xff0c;以175个HTML页面为主体&#xff0c;构成结构清晰、可本地…

作者头像 李华
网站建设 2026/10/17 1:45:18

Word转PDF自动生成目录全攻略:从样式大纲到批量处理与故障排查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/17 1:45:15

video-scroll 实战:信息流视频滚动播放与性能优化指南

简介&#xff1a;这是一份面向前端开发者的轻量级 JavaScript 工具&#xff0c;用于实现页面滚动时自动开始或停止视频播放的交互效果&#xff0c;适合需要制作滚动触发视频场景的网页项目&#xff0c;技能层级偏向入门到中级。资源包共 3 个文件&#xff0c;包含 1 个 js 脚本…

作者头像 李华
网站建设 2026/10/17 1:44:39

嵌入式物联网转型实战:低功耗、可靠通信与远程可维护设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华