资讯详情

资讯详情

CKEditor 4 全选删除后元素残留问题深度解析:bogus `<br>` 填充机制与 Enter 模式兼容性

前端UI组件【免费下载链接】ckeditor4The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.项目地址https://gitcode.com/gh_mirrors/ck/ckeditor4点击查看免费下载本文围绕 CKEditor 4 仓库中的手动测试用例 notwantedelementsonselectallandbackspace.md 展开深入剖析全选CtrlA后按 Backspace / Delete 删除全部内容这一经典场景下的 DOM 残留问题为什么small等行内元素不应残留、为什么删除后必须补一个 bogusbr填充节点以及不同 Enter 模式P / DIV / BR与无块内联编辑器下各自应有的行为。读完本文你将掌握该测试用例的完整操作与预期结果、底层按键处理源码core/editable.js的调用链、bogus 填充节点needsBrFiller的判定逻辑以及如何用 Bender 手动测试框架复现与验证该缺陷修复。用例背景一个典型的全选删除回归缺陷在富文本编辑器中全选 → 删除是最基础也最容易出 bug 的用户操作。编辑器需要保证删除后内容区只保留符合当前 Enter 模式的块元素p、div或br而不得残留之前被选中的行内元素如small、b、i等同时为了让光标能正常显示与移动空块内还必须存在一个填充节点bogus filler通常是一个br。该手动测试用例正是为了验证 CKEditor 4.5.0 中修复的这样一个 bug在h1 p结构下全选并删除后psmallSource/small/p中的small不应该出现在结果中而一个 bogusbr应当被补上。相关修复记录可见于 CHANGES.md如 #13142[Edge] Fixed:CtrlAand thenBackspaceresult in an emptydivelement说明该问题在 Edge 浏览器上曾导致删除后残留空div属于跨浏览器的回归类缺陷。用例文档逐句解读文档本体位于 notwantedelementsonselectallandbackspace.md全文仅 11 行由 Bender 手动测试元数据与操作步骤构成bender-tags: 4.5.0, bug bender-ui: collapsed bender-ckeditor-plugins: format, stylescombo, toolbar, wysiwygarea, undobender-tags标注该用例从 4.5.0 版本开始引入属于 bug 回归类测试bugbender-ui: collapsedUI 折叠模式测试页面以最小化界面呈现聚焦编辑区本身bender-ckeditor-plugins声明运行所需插件format、stylescombo、toolbar、wysiwygarea、undo——其中format负责块级格式如h1stylescombo提供样式下拉能产生small这类行内样式undo用于快照回退wysiwygarea提供经典 iframe 编辑区。操作步骤共三步聚焦编辑器Focus editor使用快捷键全选全部文本Select whole text using shortcut即 CtrlA按下Backspace或Delete。预期结果原文为There should be nosmallelement in result and bogusbrshould be present. Please note: There might be either anh1element or apin an editable.即结果中不得出现small元素且应当存在 bogusbr同时允许编辑区内最终保留h1或p之一不同浏览器对删除后保留哪个块元素的行为有差异属于允许范围。测试载体 HTML 的构造与文档配套的 notwantedelementsonselectallandbackspace.html 给出了具体的复现内容div ideditor h1Apollo 11/h1psmallSource/small/p /div p stylefont-family: monospace;strongResult:/strongspan idresult/span/p script ( function() { var editor CKEDITOR.replace( editor ), result CKEDITOR.document.getById( result ); editor.on( change, function() { setTimeout( function() { result.setText( CKEDITOR.instances.editor.editable().getHtml() ); }, 10 ); } ); }() ); /script该页面包含两个关键设计复现结构h1块级标题psmallSource/small/p段落内包裹行内小号文字正是formatstylescombo两个插件能生成的典型内容。全选删除后若实现有缺陷small可能残留在空块中实时回显监听编辑器change事件延迟 10ms 后将editable().getHtml()写入页面上的#result区域方便测试人员肉眼核对删除后的 DOM 结果。扩展用例Edge 变体与四种 Enter 模式针对同源问题仓库还提供了更全面的变体用例 notwantedelementsonselectallandbackspaceedge.md标记为4.5.4, bug, trac13142专门覆盖 Edge 浏览器对应 CHANGES.md 中的 #13142 修复。操作矩阵该用例要求对每种编辑器实例逐一执行先创建三类内容之一空段落、单段落单行文本、多段落文本用 CtrlA 全选分别按下Backspace、Delete、字母数字键、Enter键、或直接开始输入文字反复执行上述组合。预期结果编辑区内只应包含各自 Enter 模式所特有的元素——即 Enter 模式为 P 时只留p为 DIV 时只留div为 BR 时以br分行。文档还给出了三条注意事项p元素以绿色边框显示、div元素以红色边框显示便于肉眼区分样式见 _assets/styles.css在非无块内联编辑器中Edge 下可能出现div闪烁、IE 下可能出现p闪烁已知缺陷全选后按Enter会额外产生多余段落这是文档明确承认的既有 bug测试时需区分对待。四个编辑实例的配置配套页面 notwantedelementsonselectallandbackspaceedge.html 一次构建了四种形态的编辑器script CKEDITOR.disableAutoInline true; /scripteditor0h1 contenteditabletrue无块内联编辑器blockless inline editor通过CKEDITOR.inline( editor0, { plugins: toolbar,basicstyles,floatingspace,undo,format,stylescombo,enterkey } )初始化editor1enterMode CKEDITOR.ENTER_P经典p模式textarea 初始化editor2enterMode CKEDITOR.ENTER_DIVdiv模式editor3enterMode CKEDITOR.ENTER_BRbr模式。公共配置cfg为var cfg { contentsCss: %TEST_DIR%/_assets/styles.css, extraPlugins: wysiwygarea,sourcearea,htmlwriter,entities,toolbar,elementspath,undo,clipboard,format,basicstyles,enterkey,div };其中%TEST_DIR%是 Bender 测试框架注入的占位符指向测试用例所在目录enterkey插件负责 Enter 键的块拆分逻辑div插件是ENTER_DIV模式所依赖的插件。源码级原理Backspace / Delete 按键如何处理回到核心实现 core/editable.js编辑区挂载了一整套按键拦截逻辑。backspaceOrDelete将键码 8Backspace与 46Delete统一处理core/editable.jsvar backspaceOrDelete { 8: 1, 46: 1 };随后通过attachListener( editor, key, ... )拦截按键core/editable.js核心流程为只读保护编辑器处于readOnly时直接放行返回且会主动把 Backspace 键标记为阻塞键以防浏览器历史导航core/editable.js空选区保护若sel.getRanges().length 0无有效范围直接返回避免读取空 range 的路径对应 #13096、#457全选对象删除当选区完全覆盖表格或列表时走整块删除分支isListOrTableInSelection/getSelectedTableList删除前先editor.fire( saveSnapshot )建立撤销快照删除后再次saveSnapshot形成可回退的 undo 区间折叠选区特例range.collapsed时处理 Backspace/Delete 位于表格边界等特殊场景例如光标位于空块且紧邻table时删除该空块并把光标移动到表格单元格起始/末尾对应 #6217返回!isHandled若 CKEditor 已处理该按键则返回false阻止浏览器默认行为否则放行交给浏览器。这套逻辑保证了全选 Backspace/Delete场景下表格、列表等结构性内容能够被完整移除而非只删除文本节点。删除后如何补回 bogusbr测试预期中的bogusbrshould be present由填充节点机制保障。定义在 core/env.jsenv.needsBrFiller env.gecko || env.webkit || ( env.ie version 10 );即 Firefox、WebKit/Blink 系浏览器以及 IE11 需要br填充这些浏览器中空块若不包含内容则无法显示光标其余老 IE 则改用nbsp;填充。生成侧CKEDITOR.dom.element#appendBogus( force )core/dom/element.js会先检查最后一个有效子节点是否已是br否则创建并追加一个brFirefox 下附带type_moz属性判定侧CKEDITOR.dom.walker.bogus()core/dom/walker.js用于判断节点是否为填充节点——needsBrFiller为真时认br否则认末尾为nbsp;的文本节点。针对全选删除后编辑区被清空的场景core/editable.js 还有一段浏览器特判IE11 的无块内联编辑器editor.blockless CKEDITOR.env.ie CKEDITOR.env.needsBrFiller在 keyup 时若检测到 Backspace/Delete 后编辑区已无有效内容会调用this.appendBogus()补br并把光标设置到该填充节点之前因为 IE 倾向于把光标放到填充节点之后。另外针对 WebKit/Blink 在 Backspace/Delete 合并块时失控的问题core/editable.js 注册了优先级 100 的key监听器在删除后调用mergeBlocksCollapsedSelection/mergeBlocksNonCollapsedSelection主动合并块、滚动光标到新位置并保存快照——这正是删除后编辑区只剩一个p或h1这一预期结果背后的实现支撑。Enter 模式与无块编辑器的约束为什么预期结果会说可能是h1也可能是p这取决于编辑器的 Enter 模式配置。在 core/editor.js 中config.enterMode与config.shiftEnterMode会被校验后存入editor.enterMode与editor.activeEnterMode而validateEnterMode有一条硬性规则core/editor.jsfunction validateEnterMode( editor, enterMode ) { return editor.blockless ? CKEDITOR.ENTER_BR : enterMode; }无块blockless内联编辑器强制使用ENTER_BR模式。所谓无块是指内联编辑元素本身不是块级容器core/editor.jseditor.blockless editor.elementMode CKEDITOR.ELEMENT_MODE_INLINE ? !( editor.element.is( textarea ) || CKEDITOR.dtd[ editor.element.getName() ].p ) : false;即内联模式下若宿主元素如h1的 DTD 中不含p则视为无块编辑器。这解释了 edge 变体用例中editor0为什么是h1——在无块编辑器里删除全部内容后不能生成p或div只能以br承载光标。自动化测试如何验证同一行为手动测试之外仓库还提供了自动化按键测试 keystrokes.js 覆盖同一类删除行为。它以bender.editor配置autoParagraph: false, allowedContent: true起步通过assertKeystroke( key, keyModifiers, input, output, msg )断言用bot.setHtmlWithSelection( input )注入带选区标记的 HTML[、]表示选区^表示光标触发editable().fire( keydown, ... )模拟按键并通过监听key事件判断该按键是否被 CKEditor 处理用bender.tools.getHtmlWithSelection( ed )比对最终 DOM 与选区位置。典型的断言包括全选表格单元格内容后按 Delete 应只剩光标table...td[foo]/td.../table→^、全选列表内容后删除、以及无选区时按 Del/Backspace 不应抛错#13096。这些断言本质上与手动用例验证的是同一条删除路径。配套工具 tests/_benderjs/ckeditor/static/tools.js 中还定义了填充节点的专有标记表示可能有 bogusbr、!表示必须有 bogusbr、表示可能为br或nbsp;取决于needsBrFiller。自动化测试正是借助这些标记在跨浏览器环境下对删除后应存在 bogusbr这一预期做正则化断言。如何运行与排查两个手动用例都位于 tests/core/editable/manual 目录由 Bender 测试框架驱动。项目根目录的 bender.js 定义了 Bender 配置browsers、plugins、tests 分组等bender-*注释即被框架解析的用例元数据。运行方式安装依赖执行npm installbenderjs系列位于 package.json 的 devDependencies启动 Bender 服务并运行手动测试npx bender runbender.js中配置的startBrowser指定默认浏览器在浏览器中打开对应的手动测试页面按文档步骤操作并核对#result回显区。排查全选删除后元素残留问题时可依次核对检查项依据删除后是否存在small等行内元素若存在说明删除路径未正确移除行内包装节点重点复查 core/editable.js 的全选对象删除分支空块内是否补了 bogusbr核对env.needsBrFillercore/env.js与appendBoguscore/dom/element.js是否生效删除后保留的是p、div还是br核对当前实例的enterModecore/editor.js无块编辑器恒为ENTER_BREdge/WebKit 下是否残留空div对应 #13142 修复验证 WebKit 块合并逻辑core/editable.js小结notwantedelementsonselectallandbackspace系列手动用例虽只有寥寥数行却是 CKEditor 4 编辑核心core/editable.js中全选删除路径的真实缩影它把不得残留行内元素必须补 bogusbr结果元素应符合 Enter 模式这三条硬性约束固化为可复现的验收步骤。结合 edge 变体对四种 Enter 模式的矩阵化覆盖以及 keystrokes.js 的自动化断言读者可以完整理解从用户按键到 DOM 收敛的整条链路——这也是排查任何删除后内容异常类问题的起点。赞分享前端UI组件【免费下载链接】ckeditor4The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.项目地址https://gitcode.com/gh_mirrors/ck/ckeditor4点击查看免费下载相关推荐卸载后数据残留Sandboxie Plus默认沙箱删除机制深度解析卸载后数据残留Sandboxie Plus默认沙箱删除机制深度解析 在网络安全日益重要的今天沙箱技术已成为保护系统免受恶意软件侵害的关键工具。Sandbox应用安全虚拟化桌面应用Wayback Machine 网页存档工具终极指南从消失的网页到永久的数字记忆Wayback Machine 网页存档工具终极指南从消失的网页到永久的数字记忆 您是否曾经遇到过这样的情况昨天还能访问的重要资料页面今天却变成了404错前端浏览器控制上一篇Shardeum Network Account Compare多环境网络账户配置对比 CLI 工具实战指南下一篇Data Engineering Zoomcamp在 Linux 上安装 Spark 4.x 与 PySpark 的完整实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →