CKEditor 4 表格选择与 image2 组件:深入解析 1027 组件取消选中问题及测试用例
前端UI组件【免费下载链接】ckeditor4The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.项目地址https://gitcode.com/gh_mirrors/ck/ckeditor4点击查看免费下载导读本篇文章围绕 CKEditor 4 仓库中一张与表格选择Table Selection及 image2 组件Widget相关的集成测试用例文档展开重点剖析在表格中点击图片组件后如何正确地取消选中组件、恢复单元格光标从而保证用户能够在表格内自由输入文字与插入新图片。文中将完整还原该手动测试Manual Test的复现步骤、预期行为与判定标准并结合 tableselection 插件源码 与 image2 插件源码 中的关键逻辑说明其底层实现原理帮助开发者理解这一类组件与表格选择互斥场景的成因与处理方式。一、测试文档背景tableselection 与 image2 的集成场景1.1 关联文档位置与文件构成本次讨论的关联文档位于仓库的集成测试目录下测试说明手动测试步骤deselectwidget.md测试页面HTML 夹具deselectwidget.html该目录位于tests/plugins/tableselection/integrations/image2/从路径可以看出它是表格选择tableselection插件与增强图片image2插件之间的集成测试。同目录下还包含一个自动化的单元测试 paste.js用于验证表格内粘贴图片组件的行为与本手动测试共同覆盖了两者在表格场景下的协作。1.2 涉及的核心插件插件作用仓库位置table基础表格内容支持plugins/table/plugin.jstableselection提供表格内的伪选择fake selection能力支持跨单元格框选plugins/tableselection/plugin.jsimage2将图片增强为可编辑组件Widget支持拖拽缩放、对齐、加注等plugins/image2/plugin.jswidget组件框架为 image2 提供底座plugins/widget/plugin.jswysiwygarea经典 iframe 编辑区域plugins/wysiwygarea/plugin.jsundo/clipboard/basicstyles/toolbar/resize撤销、剪贴板、基础样式、工具栏与窗口缩放对应 plugins 目录其中tableselection插件的依赖声明为requires: clipboard,tabletools见 plugins/tableselection/plugin.js#L1195并声明了isSupportedEnvironment()不支持 IE 11 以下版本L1197-L1199这也是测试页面中会调用bender.tools.ignoreUnsupportedEnvironment( tableselection )的原因。二、测试用例全解析手动复现步骤与判定标准2.1 Bender 测试元数据文档首部的 Bender 标签声明了该用例的属性bender-tags: 1027, 4.8.0, widget, bug bender-ui: collapsed bender-ckeditor-plugins: undo,clipboard,basicstyles,toolbar,wysiwygarea,widget,table,tableselection,resize,image2字段含义1027关联的缺陷Bug编号即后文提到的 #10274.8.0该缺陷在 4.8.0 版本引入或修复结合源码注释该修复随 4.8.0 一并发布widget/bug用例类型标签表示这是组件相关的缺陷回归测试bender-ui: collapsed手动测试以折叠 UI 方式呈现便于聚焦编辑器内容bender-ckeditor-plugins测试页面加载的插件列表完整复刻了缺陷场景所需的运行环境。2.2 测试页面夹具Fixture配套的 HTML 文件 deselectwidget.html 定义了测试环境labelLenas path: input styleborder:2px solid black typetext value%BASE_PATH%_assets/lena.jpg readonly/label textarea ideditor table border1 cellpadding1 cellspacing1 stylewidth:500px tbody tr tdText/td tdTest/td /tr tr tdimg altLena src%BASE_PATH%_assets/lena.jpg styleheight:150px; width:150px //td tdnbsp;/td /tr tr tdnbsp;/td tdnbsp;/td /tr /tbody /table pnbsp;/p /textarea script if ( bender.tools.env.mobile ) { bender.ignore(); } bender.tools.ignoreUnsupportedEnvironment( tableselection ); CKEDITOR.replace( editor, { extraPlugins: image2 } ); /script要点说明表格结构一个 3 行 × 2 列的表格第二行第一列放置了一张 150px × 150px 的 Lena 图片lena.jpg为测试资产位于 tests/_assets/lena.jpg。图片路径提示页面上方提供只读输入框展示 Lena 图片的路径%BASE_PATH%_assets/lena.jpg供测试者在插入新图片步骤中使用。运行环境过滤移动端直接bender.ignore()跳过通过bender.tools.ignoreUnsupportedEnvironment( tableselection )在不支持 tableselection 的浏览器IE 11上自动忽略。编辑器初始化CKEDITOR.replace( editor, { extraPlugins: image2 } )在默认插件集基础上额外启用image2从而让lena.jpg在进入编辑器后被 upcast 为图片组件Widget。2.3 复现步骤文档原文完整继承按文档所述操作步骤为点击图片Lena 的图片使图片组件获得焦点并处于选中状态点击表格中的另一个单元格然后开始操作注意不要点击表格外部输入一些文字插入一张新图片Lena 图片的路径显示在编辑器上方。2.4 预期行为Expected可以自由地输入文字并编辑文本可以添加新的图片图片不再保持残留选中状态。2.5 非预期行为Unexpected无法执行上述预期中的任何操作选择Selection始终停留在图片上。简而言之点击单元格后光标应当从组件移入单元格用户可以正常编辑如果选择一直粘在图片上则说明出现了 #1027 所描述的回归缺陷。三、缺陷根因为什么选择会粘在图片组件上3.1 两套选择机制的冲突在启用tableselection后表格内存在两套并行的选择机制Widget 的假选择fake selection点击image2图片组件时widget 插件会用一个不可见的假选择fake selection包裹组件表现为图片外围出现高亮/控制手柄参见 plugins/widget/plugin.js 中Widget.focus()相关逻辑。表格的伪选择fake table selectiontableselection通过给单元格添加cke_table-faked-selection类来模拟跨单元格框选见 plugins/tableselection/plugin.js#L9其视觉样式定义于 plugins/tableselection/styles/tableselection.css。当用户先选中图片组件、再点击表格单元格时tableselection的鼠标处理逻辑fakeSelectionMouseHandlerL288会尝试判断是否清除当前选择。如果判断失误就会把组件的选中状态残留下来导致后续输入、插入图片全部失效——这正是文档中Unexpected描述的现象。3.2 关键修复点识别组件作为事件目标#1027在 plugins/tableselection/plugin.js#L218 附近fakeSelectByMouse函数中有一段针对 #1027 的注释与逻辑// The selection is inside one cell, so we should allow native selection, // but only in case if no other cell between mousedown and mouseup // was selected. // We dont want to clear selection if widget is event target (#1027). if ( !fakeSelection.dirty cells.length 1 !( isWidget( evt.data.getTarget() ) ) ) { return clearFakeCellSelection( editor, evt.name mouseup ); }其含义是当鼠标按下到抬起之间只经过一个单元格、且事件目标不是组件时才允许清除表格伪选择、恢复原生选择。若事件目标是组件例如图片 Widget则不要清除选择以免破坏组件自身的假选择状态。配套的isWidget工具函数定义在 plugins/tableselection/plugin.js#L20-L22function isWidget( element ) { return CKEDITOR.plugins.widget CKEDITOR.plugins.widget.isDomWidget( element ); }而CKEDITOR.plugins.widget.isDomWidget的定义位于 plugins/widget/plugin.js#L1723-L1725Widget.isDomWidget function( node ) { return node ? this.isDomWidgetWrapper( node ) || this.isDomWidgetElement( node ) : false; };即只要 DOM 节点带有data-cke-widget-wrapper组件包装层或data-widget组件元素属性就被判定为组件。这两个属性分别由 Widget.isDomWidgetWrapper 与 Widget.isDomWidgetElement 判断。3.3 另一处组件感知处理鼠标事件过滤在fakeSelectionMouseHandler入口plugins/tableselection/plugin.js#L288-L297还有一层组件防护// Prevent applying table selection when widget is selected. // Mouseup remains a possibility to finish table selection when user release mouse button above widget in table. if ( evt.name ! mouseup isWidget( evt.data.getTarget() ) ) { return; }意思是除 mouseup 之外的鼠标事件如 mousedown、mousemove若命中组件则直接忽略不触发表格伪选择mouseup 仍保留作为在表格内释放鼠标、结束框选的兜底路径。这就确保了用户对组件的常规操作点击、拖动不会被表格选择逻辑干扰。3.4 组件本身对 image 类型选择的避让除了 tableselection 一侧的防护fakeSelectionChangeHandler中还针对图片被选中的情况做了处理plugins/tableselection/plugin.js#L230-L254var enclosedNode ranges ranges[ 0 ].getEnclosedNode(), isEnclosedNodeAnImage enclosedNode ( enclosedNode.type CKEDITOR.NODE_ELEMENT ) enclosedNode.is( img ), ... // Dont perform fake selection when image is selected (#2235). if ( isEnclosedNodeAnImage ) { editor.getSelection().reset(); return; }当选区封闭节点是img元素时直接重置选择并返回不做表格伪选择。这从另一条路径保证了图片被选中时表格选择不介入。四、从源码结构理解整个点击单元格 → 取消选中组件的链路综合上文一次完整的交互链路可以概括为用户点击图片组件 └─ widget 插件接管组件获得焦点fake selection on widget 用户点击表格内另一单元格事件目标为单元格或单元格内文本 ├─ fakeSelectionMouseHandler 收到 mousedown/mouseup │ ├─ 目标非组件 → 允许进入表格伪选择流程 │ ├─ cells.length 1 且 fakeSelection.dirty false │ │ └─ 清除表格伪选择 clearFakeCellSelection( editor, true ) │ │ └─ 移除 cke_table-faked-selection 类并重置原生选择 │ └─ 目标为组件 → 跳过/不干预#1027 防护 └─ 光标落入单元格可自由输入文字 / 插入新图片其中clearFakeCellSelectionplugins/tableselection/plugin.js#L120-L149承担清除工作移除编辑区域上的cke_table-faked-selection-editor类遍历并移除所有单元格上的cke_table-faked-selection类清除表格上的cke-table-faked-selection-table数据属性在reset为true时重置fakeSelection状态并仅在当前选择确实在表格内时调用editor.getSelection().reset()——源码注释明确指出这一步是为了避免破坏组件选择L143-L147。此外tableselection的初始化L1223-L1243将fakeSelectionMouseHandler绑定在文档级的mousedown/mousemove/mouseup事件上并将fakeSelectionChangeHandler绑定在编辑器的selectionCheck事件上构成鼠标拖拽 选区变化双重驱动的伪选择体系。五、测试资产与配套验证5.1 手动测试所需的图片资产测试步骤中插入新图片所引用的 Lena 图片路径为%BASE_PATH%_assets/lena.jpg对应仓库中的 tests/_assets/lena.jpg。手动测试时可直接将页面上方输入框中的路径复制到图片对话框中使用。5.2 同目录下的自动化集成测试与手动测试互补的自动化用例是 paste.js它验证了在tableselection image2组合下粘贴图片的关键行为function pasteImage( editor, callback ) { editor.once( afterPaste, function() { resume( function() { var images editor.editable().find( .cke_widget_image ); ...从源码结构看其断言方向包括粘贴后图片以cke_widget_image类标识的组件形式存在即被 upcast 为 image2 组件撤销undo只产生一个撤销步骤且撤销/重做行为正确paste.js#L25-L26粘贴后正确的单元格被选中。该用例同时覆盖 classic 与 inline 两种编辑器paste.js#L7-L12与手动测试共同组成对表格-组件集成行为的回归保障。5.3 image2 的组件化机制对测试前提的意义测试页面之所以能复现缺陷前提是lena.jpg在加载后被image2的 upcast 逻辑转换为组件。image2 插件的 upcast 定义位于 plugins/image2/plugin.js#L899-L971它会将独立的img或aimg、带 caption 类的figure识别为组件元素并交给 widget 框架处理同时排除带有data-cke-realelement的粘贴伪对象L910-L912。这正是点击图片后它会表现为一个可聚焦组件的机制来源。六、如何运行与回归验证6.1 运行 Bender 手动测试本仓库使用 Bender 作为测试框架见 bender.js 与 package.json 中的benderjs依赖。运行手动测试的一般方式# 安装依赖如尚未安装 npm install # 启动 bender 服务器并进入手动测试交互界面 ./node_modules/.bin/bender server run在打开的 Bender 测试列表中定位到tests/plugins/tableselection/integrations/image2/manual/deselectwidget.html随后按照本文2.3 复现步骤操作并对照2.4 预期行为与2.5 非预期行为判断结果。6.2 验证要点速查操作预期结果点击 Lena 图片图片组件被选中出现组件焦点样式点击表格另一单元格输入文字光标进入单元格文字可正常输入图片不再保持选中点击表格另一单元格插入新图片新图片可正常插入并成为组件原图片不再保持选中全程不点击表格外部上述行为在表格内部即可完成6.3 适用版本与运行前提该缺陷与修复与4.8.0版本相关见bender-tags当前仓库源码中的修复逻辑以注释(#1027)标注tableselection仅在 IE 11 及以上浏览器生效plugins/tableselection/plugin.js#L1197-L1199旧版 IE 中该测试会被自动忽略手动测试在移动端会被跳过bender.ignore()。七、总结本文以 deselectwidget.md 这份手动测试文档为核心完整还原了表格内点击图片组件后如何取消选中、恢复单元格编辑这一场景的复现步骤与预期标准并从源码层面解释了其背后组件假选择与表格伪选择两套机制的协调逻辑tableselection通过isWidget()识别事件目标是否为组件避免误清组件选择#1027 修复点plugin.js#L218-L220除 mouseup 外的鼠标事件命中组件时直接忽略防止表格选择干扰组件操作plugin.js#L293-L297选区封闭节点为img时重置选择、跳过表格伪选择plugin.js#L250-L254。对于需要深度定制表格 图片组件行为的开发者本文可作为理解两者交互边界、排查选择残留类问题的切入点同时 paste.js 与手动用例互为补充共同保障了这一集成场景的长期稳定。赞分享前端UI组件【免费下载链接】ckeditor4The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.项目地址https://gitcode.com/gh_mirrors/ck/ckeditor4点击查看免费下载相关推荐深入 CKEditor 4 Link 插件getSelectedLink 链接选中机制与手动测试用例解析深入 CKEditor 4 Link 插件getSelectedLink 链接选中机制与手动测试用例解析 导读 在 CKEditor 4 中编辑一个既有超链接前端UI组件CKEditor 4 Easy Image 插件与表格单元格选择Table Selection的交互ticket 1542 手动测试全解析CKEditor 4 Easy Image 插件与表格单元格选择Table Selection的交互ticket 1542 手动测试全解析 导读 本文围绕前端UI组件上一篇douyin-downloader 快速上手3 个场景把创作者主页无水印批量下载存进本地下一篇SQLFlow 实战用 SQL 训练 DNN 分类器对 Iris 鸢尾花数据集进行分类创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

匹配滤波与脉冲压缩:从柯西-施瓦兹不等式到雷达工程实现

匹配滤波与脉冲压缩:从柯西-施瓦兹不等式到雷达工程实现

简介:面向雷达信号处理初学者与工程人员,这份压缩包从柯西-施瓦兹不等式切入,系统讲解匹配滤波器的数学原理与设计思路。内容既涵盖不等式在信号内积、相关性分析中的理论基础,也结合雷达目标检测场景,说明如何利用已知…

2026/10/16 1:39:41 阅读更多 →
airi Stage Tamagotchi 扩展激活规划器:用静态 Kit 声明决定 Provider 与 Consumer 的加载顺序

airi Stage Tamagotchi 扩展激活规划器:用静态 Kit 声明决定 Provider 与 Consumer 的加载顺序

人工智能AI AgentMCP 服务工具调用GUI 自动化语音数字人交互助手 【免费下载链接】airi 💖🧸 自托管、归你拥有的 Grok 风格 AI 伴侣与 waifu / 赛博生命灵魂容器,目标是接近 Neuro-sama 的高度;支持实时语音聊天、Minecraft 和 F…

2026/10/16 1:39:41 阅读更多 →
老 Mac 升不上新系统?用 OpenCore Legacy Patcher 三步装好 macOS Sonoma

老 Mac 升不上新系统?用 OpenCore Legacy Patcher 三步装好 macOS Sonoma

老 Mac 升不上新系统?用 OpenCore Legacy Patcher 三步装好 macOS Sonoma 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher OpenCore Legacy Patche…

2026/10/16 1:38:41 阅读更多 →

最新新闻

微信小程序圆环组件开发:Canvas 2D与CSS方案选型及性能优化实战

微信小程序圆环组件开发:Canvas 2D与CSS方案选型及性能优化实战

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

2026/10/16 3:13:02 阅读更多 →
interface 的底层原理

interface 的底层原理

深入浅出 Go 语言:Interface 的底层实现原理在 Go 语言中,接口(interface)是实现多态和解耦的核心机制。与其他面向对象语言不同,Go 采用的是“隐式实现”(Duck Typing,鸭子类型)——…

2026/10/16 3:13:02 阅读更多 →
【C++入门】编译链接模型 - 08 静态库为什么像一包目标文件

【C++入门】编译链接模型 - 08 静态库为什么像一包目标文件

博主介绍:程序喵大人 35 - 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章,首发gzh,见文末👇&#x…

2026/10/16 3:13:02 阅读更多 →
重复测量数据全攻略:2026 一篇讲透论文重复测量实验设计,把变量控制与记录规范讲清

重复测量数据全攻略:2026 一篇讲透论文重复测量实验设计,把变量控制与记录规范讲清

同一批被试在四个时间点各测一次,交到导师手里却被追问「你的实验设计写在哪」。重复测量方差分析、线性混合模型这些名称不难写,难的是交代清楚每次观测为何落在这个时点、谁在中途退出、缺失值依据什么规则处置。下文从自变量控制、测量间隔、批次安排…

2026/10/16 3:13:02 阅读更多 →
信贷风控用户画像实战:从标签体系到贷前贷中贷后策略落地

信贷风控用户画像实战:从标签体系到贷前贷中贷后策略落地

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

2026/10/16 3:13:02 阅读更多 →
Java字符串转数字的正确方法

Java字符串转数字的正确方法

java中把字符串转成 的方法更新时间为二零二三年七月七日零九点四十分零三秒, 作者是。在Java环境里头, 大家可以利用某个类里面的那个叫作静态的方法, 把一段写着数字的字符串变成对应那种类型的数, 这篇文章会配上一些具体的代码例子, 来把这个事情从字符串弄成具体数值的过程…

2026/10/16 3:12:01 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

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

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/15 9:49:14 阅读更多 →