- 前端
- UI组件
【免费下载链接】ckeditor4
The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.
本文以 CKEditor 4 仓库中的手动测试用例 entitiesprocessnumericalforce.md 为核心,完整还原该用例验证的场景——将 entities 插件配置entities_processNumerical设为'force'后,命名 HTML 实体被强制转换为数字实体( → )的行为。结合 plugins/entities/plugin.js 的源码实现、CHANGES.md 中 #4941 修复记录与 tests/plugins/entities/entities.js 的自动化断言,你将掌握该配置的完整生效链路、全部配置项取值,以及如何在仓库内运行并验证这一行为。
一、手动测试用例:它在验证什么
tests/plugins/entities/manual/entitiesprocessnumericalforce.md 是一个 Bender 手动测试(manual test)的描述文件,全文如下(含元信息):
@bender-tags: bug, 4.20.0, 4941 @bender-ui: collapsed @bender-ckeditor-plugins: wysiwygarea, toolbar, entities, sourcearea 1. Open the source mode. **Expected** Named entities was converted to a numerical HTML entities: `  > < & "`. **Unexpected** Entities was not converted: ` > < & "`.三行元信息各有含义:
@bender-tags: bug, 4.20.0, 4941:标注该用例属于 bug 回归测试,对应问题编号 #4941,修复发布于 CKEditor 4.20.0;@bender-ui: collapsed:测试页面以折叠(最小化)方式呈现编辑器;@bender-ckeditor-plugins:实例化时加载wysiwygarea、toolbar、entities、sourcearea插件——其中sourcearea提供 “Source”(源码模式)按钮,正是本用例的操作入口。
用例的操作步骤只有一条:打开源码模式。预期结果是被测内容中的命名实体全部转换为数字实体:
| 源码中的命名实体 | 预期输出(数字实体) | 对应 Unicode |
|---|---|---|
|   | NO-BREAK SPACE |
> | > | > |
< | < | < |
& | & | & |
" | " | " |
若输出仍为 > < & ",则判定为 Unexpected(bug 复现)。
与.md配对的页面是 entitiesprocessnumericalforce.html,它定义了被测的初始内容与编辑器配置:
<div id="editor"> <p> > < & "</p> </div> <script> CKEDITOR.replace( 'editor', { entities_processNumerical: 'force', lang: 'en' } ); </script>关键配置就是entities_processNumerical: 'force'。测试组与运行环境方面,从 bender.js 的结构看,Plugins测试组指向tests/plugins/**(bender.js),而 Bender 的配置说明中提供了manualBrowsers(接受手动测试的浏览器列表)与manualTestTimeout(手动测试超时,bender.js)两个配置项,即.md描述的 manual 用例由测试人员按步骤人工执行;仓库 package.json 中声明了benderjs ^0.4.6作为测试框架,bender-runner.config.json 约定了 bender 服务端口 9001、测试服务端口 9002。
二、源码实现:'force' 是如何让实体变成数字形式的
实体编码的全部逻辑位于 plugins/entities/plugin.js。下面按数据流顺序拆解。
2.1 核心分支:getEntity 中的 'force' 判断
插件在afterInit阶段注册文本过滤规则,其中决定输出形态的函数是(plugin.js):
function getEntity( character ) { return config.entities_processNumerical == 'force' || !entitiesTable[ character ] ? '&#' + getCodePoint( character ) + ';' : entitiesTable[ character ]; } // (#4941) function getCodePoint( character ) { return CKEDITOR.env.ie ? character.charCodeAt( 0 ) : character.codePointAt( 0 ); }分支语义是:
entities_processNumerical === 'force':无条件返回'&#' + 码点 + ';',即命名实体表(entitiesTable)被完全旁路——这就是手动测试中 不会输出为 而是 的直接原因;- 非 force 但字符不在命名实体表中:同样退化为数字实体;
- 否则:输出命名实体(如
é)。
值得注意的是getCodePoint:非 IE 环境使用String.prototype.codePointAt(0)而非charCodeAt(0)。这个区别对 Unicode 平面之外(BMP 之外)的字符至关重要——例如 👍 的码点是 128077,若按 UTF-16 码元逐个取charCodeAt会得到代理对的两个半值 55357 与 56397,输出错误的��。这正是 #4941 的另一半症状,CHANGES.md 记录了该修复:
#4941: Fixed: Some entities got wrongly encoded when using
entities_processNumerical = trueconfiguration option.
同目录的姊妹用例 encodeentities.md(同样标注4.20.0, 4941)验证的就是这一点:entities_processNumerical: true下输入👍,预期源码中只出现一个实体👍,而不是拆成��两个实体。
2.2 两张映射表:编码表与“反向解码”表
实体表由buildTable构建(plugin.js)。它有一个特殊处理对象specialTable(plugin.js):
// Entities that the browsers' DOM does not automatically transform to the // final character. var specialTable = { nbsp: '\u00A0', // IE | FF shy: '\u00AD', // IE gt: '\u003E', // IE | FF | -- | Opera lt: '\u003C', // IE | FF | Safari | Opera amp: '\u0026', // ALL apos: '\u0027', // IE quot: '\u0022' // IE };从注释看,这些实体在部分浏览器的 DOM 解析中不一定会自动折叠为字符(例如某些浏览器里文本中的 可能仍以字面字符串存在)。为此插件构造了两张表:
- 正向表
entitiesTable:由basicEntities(nbsp,gt,lt,amp)、拉丁实体、希腊实体与entities_additional拼合而成(plugin.js),把“字符 → 实体字符串”; - 反向表
baseEntitiesTable:buildTable( [ htmlbase, 'shy' ].join( ',' ), true )(plugin.js),把字面实体字符串 、>、<、&、­还原为字符,注释明确其用途是 “Decode entities that the browsers has transformed at first place”——先把 DOM 没有折叠干净的实体字符串统一解码成字符。
2.3 双层正则与 htmlFilter 文本规则
编码动作最终通过htmlFilter.addRules注册的text规则完成(plugin.js):
htmlFilter.addRules( { text: function( text ) { return text.replace( baseEntitiesRegex, getChar ).replace( entitiesRegex, getEntity ); } }, { applyToAll: true, excludeNestedEditable: true } );流程是两步替换:
baseEntitiesRegex先把残留的字面实体字符串解码为真实字符( → U+00A0);entitiesRegex再把命中的字符按getEntity编码。
entitiesRegex的拼装规则在(plugin.js):
var entitiesRegex = entitiesTable.regex ? '[' + entitiesTable.regex + ']' : 'a^'; delete entitiesTable.regex; if ( config.entities && config.entities_processNumerical ) { entitiesRegex = '[^ -~]|' + entitiesRegex; } // IE does not support unicode option in the Regex constructor (#4941). entitiesRegex = new RegExp( entitiesRegex, CKEDITOR.env.ie ? 'g' : 'gu' );两个与 #4941 直接相关的细节都在这里:
- 仅当
entities && entities_processNumerical时,才前置[^ -~](非 ASCII 可打印字符),把中文、emoji、希腊字母等 BMP 外/非 ASCII 字符也纳入编码范围; - 正则使用
u标志(Unicode 模式)——在u模式下[^ -~]匹配的是“码点”而非“码元”,emoji 这类代理对才能作为一个整体匹配;IE 不支持u标志,故回退为g并配合charCodeAt,这也是为什么 #4941 相关测试在 IE 下assert.ignore()(见 entities.js 与 encodeentities.html 中的bender.ignore())。
此外,规则注册前有一个前提检查(plugin.js):若editor.dataProcessor.htmlFilter不存在则直接return,即整个实体编码功能依附于 htmlFilter。这一点有自动化测试佐证:entities.js 中把htmlFilter置空为{}后,force模式下输入<>&原样保留、不做任何转换。
2.4 用源码串一遍手动测试的完整数据流
以entitiesprocessnumericalforce.html的初始内容<p> > < & "</p>为例(配置entities_processNumerical: 'force'):
- 内容经 DOM 解析后,
、>、<、&、"折叠为字符:NBSP、>、<、&、"(文本节点); - 用户点击 Source,
getData走dataProcessor.toDataFormat,文本节点命中 htmlFilter 的text规则; - 第一步
baseEntitiesRegex替换:文本中没有字面实体字符串,无变化; - 第二步
entitiesRegex替换:由于启用了entities && entities_processNumerical,正则含[^ -~]分支,五个字符全部命中;getEntity因== 'force'走'&#' + getCodePoint() + ';'分支,依次输出 、>、<、&、"; - 源码区最终显示
<p>  > < & "</p>,与.md中的Expected完全一致。
三、entities 插件配置项全景
plugin.js 通过 JSDoc 与默认赋值声明了 6 个配置项,汇总如下:
| 配置项 | 类型 | 默认值 | 作用 | 源码位置 |
|---|---|---|---|---|
basicEntities | Boolean | true | 是否转义基本 HTML 实体nbsp、gt、lt、amp;文档注明仅在输出 BBCode 等非 HTML 格式时才考虑关闭 | plugin.js |
entities | Boolean | true | 是否在编辑器输出中使用 HTML 实体 | plugin.js |
entities_latin | Boolean | true | 是否把 Latin-1(ISO 8859-1)字母转为实体 | plugin.js |
entities_greek | Boolean | true | 是否把符号、数学符号与希腊字母转为实体,对输入希腊文的用户尤其相关 | plugin.js |
entities_processNumerical | Boolean/String | false | 把 ASCII 表之外的字符转为十进制数字实体;设为'force'时把所有实体(含命名实体)强制转为数字形式,如 →  | plugin.js |
entities_additional | String | '#39' | 逗号分隔的补充实体名单,写法不含&前缀与;后缀,支持实体名或数字(如'#1049'添加西里尔字母 Й) | plugin.js |
官方 JSDoc 给出的两个典型用法(plugin.js):
config.entities_processNumerical = true; config.entities_processNumerical = 'force'; // Converts from ' ' into ' ';true与'force'的行为差异可由 entities.js 中的自动化断言精确定界:
| 配置组合 | 输入 | 期望输出 | 结论 | 断言位置 |
|---|---|---|---|---|
force(其余默认) | > < & " |   > < & " | 命名实体全部数字化,与手动测试预期一致 | entities.js |
force+entities_greek: true | αβγ…ω | αβ…ω | 希腊字母不走命名实体 | entities.js |
force+entities_latin: true | ÀÁÎÏÐ | ÀÁÎÏÐ | 拉丁字母不走命名实体 | entities.js |
force+entities: false | <>& | <>& | entities关闭后basicEntities仍在生效,force 依旧数字化 | entities.js |
force+ 移除 htmlFilter | <>& | <>&(不变) | 功能完全依赖 htmlFilter 的 text 规则 | entities.js |
true(非 force)+entities_latin: false | À…Ð | À…Ð | 非 force 时只有“表中无命名实体”的字符才数字化 | entities.js |
true(非 force) | ¡¢£…›等符号串 | 全部数字实体,不含命名实体 | 未列入名单的特殊字符按数字实体输出 | entities.js |
true(非 force,#4941) | 👍😄😍💗 | 👍😄😍💗 | 单个码点一个实体,不拆分代理对(IE 下跳过) | entities.js |
entities: false(无 force) | <>& | 原样 | 关闭entities且非 force 时不做实体转换 | entities.js |
entities_processNumerical: false | <>& | 原样(按命名实体原路返回) | 默认行为不引入数字实体 | entities.js |
需要说明的适用前提:以上行为以当前仓库版本(package.json 中4.25.1)的源码为准,'force'的强制语义与 #4941 的码点修复自 4.20.0 起生效;IE 环境因正则u标志与codePointAt均不可用,相关数字实体行为按源码中的分支回退处理,测试用例也在 IE 下主动跳过。
四、运行与验证方式
手动验证:仓库为只读源码树,无需构建产物即可验证——entitiesprocessnumericalforce.html 是一个独立页面,只需按仓库目录结构由静态服务器提供,即可用浏览器打开该页面并启用开发者工具观察CKEDITOR.instances.editor.getData()的输出;然后按 entitiesprocessnumericalforce.md 的步骤 1 点击 Source 按钮,比对源码区是否出现  > < & "。同目录还有两个可对照的用例:encodeentities.md(true模式下 emoji 码点)与 additional.md(entities_additional相关回归,#2448)。
自动化验证:仓库使用 Bender 框架(benderjs ^0.4.6,package.json 中还有benderjs-yui、benderjs-sinon等配套插件)。按 bender.js 的定义,Plugins测试组覆盖tests/plugins/**,其中即包含 entities.js;bender.ci.js 进一步为 CI 环境配置了 headless Chrome/Firefox 作为启动浏览器。运行自动化断言时,上表第 1 行(force转数字)的断言与本文开头的手动测试用例互为印证:同一输入 > < & ",同一期望  > < & "。
小结:这个看似只有两步的手动测试用例,背后锚定的是 entities 插件中最容易出错的编码路径——getEntity的force旁路分支、双层“解码—再编码”的 htmlFilter 文本规则,以及 #4941 修复引入的codePointAt码点处理与 Unicode 正则。理解了这条链路,就能准确预测任意entities_*配置组合下的实体输出形态,并知道到哪里去看断言依据(entities.js)与实现依据(plugin.js)。
- 前端
- UI组件
【免费下载链接】ckeditor4
The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.
相关推荐
CKEditor 4 Autolink 插件粘贴 URL 时的 `&` 字符双重编码问题(4858)解析与验证
CKEditor 4 Autolink 插件粘贴 URL 时的 & 字符双重编码问题( 4858)解析与验证 导读 在 CKEditor 4 的 Autolin
前端UI组件CKEditor 4 font 插件的字号/字体样式保持机制:preservestyle 手动测试场景与源码级实现剖析
CKEditor 4 font 插件的字号/字体样式保持机制:preservestyle 手动测试场景与源码级实现剖析 本文围绕 CKEditor 4 仓库中
前端UI组件CKEditor 4 Format 插件行为验证:Format 下拉"重复点击不切换"机制的实现与测试(工单 584)
CKEditor 4 Format 插件行为验证:Format 下拉"重复点击不切换"机制的实现与测试(工单 584) 本文围绕 CKEditor 4 仓库中的
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考