news 2026/10/16 2:12:54

CKEditor 4 entities 插件深解:entities_processNumerical = ‘force‘ 的强制数字实体编码实现与 4941 修复验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CKEditor 4 entities 插件深解:entities_processNumerical = ‘force‘ 的强制数字实体编码实现与 4941 修复验证
  • 前端
  • UI组件

【免费下载链接】ckeditor4

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

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

本文以 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
>>>
&lt;&#60;<
&amp;&#38;&
&quot;&#34;"

若输出仍为&nbsp; &gt; &lt; &amp; &quot;,则判定为 Unexpected(bug 复现)。

与.md配对的页面是 entitiesprocessnumericalforce.html,它定义了被测的初始内容与编辑器配置:

<div id="editor"> <p>&nbsp; &gt; &lt; &amp; &quot;</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)被完全旁路——这就是手动测试中&nbsp;不会输出为&nbsp;而是&#160;的直接原因;
  • 非 force 但字符不在命名实体表中:同样退化为数字实体;
  • 否则:输出命名实体(如&eacute;)。

值得注意的是getCodePoint:非 IE 环境使用String.prototype.codePointAt(0)而非charCodeAt(0)。这个区别对 Unicode 平面之外(BMP 之外)的字符至关重要——例如 👍 的码点是 128077,若按 UTF-16 码元逐个取charCodeAt会得到代理对的两个半值 55357 与 56397,输出错误的&#55357;&#56397;。这正是 #4941 的另一半症状,CHANGES.md 记录了该修复:

#4941: Fixed: Some entities got wrongly encoded when usingentities_processNumerical = trueconfiguration option.

同目录的姊妹用例 encodeentities.md(同样标注4.20.0, 4941)验证的就是这一点:entities_processNumerical: true下输入👍,预期源码中只出现一个实体&#128077;,而不是拆成&#55357;&#56397;两个实体。

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 解析中不一定会自动折叠为字符(例如某些浏览器里文本中的&nbsp;可能仍以字面字符串存在)。为此插件构造了两张表:

  1. 正向表entitiesTable:由basicEntities(nbsp,gt,lt,amp)、拉丁实体、希腊实体与entities_additional拼合而成(plugin.js),把“字符 → 实体字符串”;
  2. 反向表baseEntitiesTable:buildTable( [ htmlbase, 'shy' ].join( ',' ), true )(plugin.js),把字面实体字符串&nbsp;、&gt;、&lt;、&amp;、&shy;还原为字符,注释明确其用途是 “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 } );

流程是两步替换:

  1. baseEntitiesRegex先把残留的字面实体字符串解码为真实字符(&nbsp;→ U+00A0);
  2. 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模式下输入&lt;&gt;&amp;原样保留、不做任何转换。

2.4 用源码串一遍手动测试的完整数据流

以entitiesprocessnumericalforce.html的初始内容<p>&nbsp; &gt; &lt; &amp; &quot;</p>为例(配置entities_processNumerical: 'force'):

  1. 内容经 DOM 解析后,&nbsp;、&gt;、&lt;、&amp;、&quot;折叠为字符:NBSP、>、<、&、"(文本节点);
  2. 用户点击 Source,getData走dataProcessor.toDataFormat,文本节点命中 htmlFilter 的text规则;
  3. 第一步baseEntitiesRegex替换:文本中没有字面实体字符串,无变化;
  4. 第二步entitiesRegex替换:由于启用了entities && entities_processNumerical,正则含[^ -~]分支,五个字符全部命中;getEntity因== 'force'走'&#' + getCodePoint() + ';'分支,依次输出&#160;、&#62;、&#60;、&#38;、&#34;;
  5. 源码区最终显示<p>&#160; &#62; &#60; &#38; &#34;</p>,与.md中的Expected完全一致。

三、entities 插件配置项全景

plugin.js 通过 JSDoc 与默认赋值声明了 6 个配置项,汇总如下:

配置项类型默认值作用源码位置
basicEntitiesBooleantrue是否转义基本 HTML 实体nbsp、gt、lt、amp;文档注明仅在输出 BBCode 等非 HTML 格式时才考虑关闭plugin.js
entitiesBooleantrue是否在编辑器输出中使用 HTML 实体plugin.js
entities_latinBooleantrue是否把 Latin-1(ISO 8859-1)字母转为实体plugin.js
entities_greekBooleantrue是否把符号、数学符号与希腊字母转为实体,对输入希腊文的用户尤其相关plugin.js
entities_processNumericalBoolean/Stringfalse把 ASCII 表之外的字符转为十进制数字实体;设为'force'时把所有实体(含命名实体)强制转为数字形式,如&nbsp;→&#160;plugin.js
entities_additionalString'#39'逗号分隔的补充实体名单,写法不含&前缀与;后缀,支持实体名或数字(如'#1049'添加西里尔字母 Й)plugin.js

官方 JSDoc 给出的两个典型用法(plugin.js):

config.entities_processNumerical = true; config.entities_processNumerical = 'force'; // Converts from '&nbsp;' into '&#160;';

true与'force'的行为差异可由 entities.js 中的自动化断言精确定界:

配置组合输入期望输出结论断言位置
force(其余默认)&nbsp; &gt; &lt; &amp; &quot;&#160; &#62; &#60; &#38; &#34;命名实体全部数字化,与手动测试预期一致entities.js
force+entities_greek: trueαβγ…ω&#945;&#946;…&#969;希腊字母不走命名实体entities.js
force+entities_latin: true&Agrave;&Aacute;&Icirc;&Iuml;&ETH;&#192;&#193;&#206;&#207;&#208;拉丁字母不走命名实体entities.js
force+entities: false&lt;&gt;&amp;&#60;&#62;&#38;entities关闭后basicEntities仍在生效,force 依旧数字化entities.js
force+ 移除 htmlFilter&lt;&gt;&amp;&lt;&gt;&amp;(不变)功能完全依赖 htmlFilter 的 text 规则entities.js
true(非 force)+entities_latin: false&Agrave;…&ETH;&#192;…&#208;非 force 时只有“表中无命名实体”的字符才数字化entities.js
true(非 force)¡¢£…›等符号串全部数字实体,不含命名实体未列入名单的特殊字符按数字实体输出entities.js
true(非 force,#4941)👍😄😍💗&#128077;&#128516;&#128525;&#128151;单个码点一个实体,不拆分代理对(IE 下跳过)entities.js
entities: false(无 force)&lt;&gt;&amp;原样关闭entities且非 force 时不做实体转换entities.js
entities_processNumerical: false&lt;&gt;&amp;原样(按命名实体原路返回)默认行为不引入数字实体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 按钮,比对源码区是否出现&#160; &#62; &#60; &#38; &#34;。同目录还有两个可对照的用例: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转数字)的断言与本文开头的手动测试用例互为印证:同一输入&nbsp; &gt; &lt; &amp; &quot;,同一期望&#160; &#62; &#60; &#38; &#34;。

小结:这个看似只有两步的手动测试用例,背后锚定的是 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.

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

相关推荐

上一篇:旧Mac升级macOS Catalina完整指南:让你的老设备重获新生
下一篇:Sreg终极指南:如何快速查询邮箱/手机号/用户名注册的互联网账号

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

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

PX4期望姿态矩阵生成算法拆解:从推力向量到旋转矩阵

/* 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 2:05:18

Step 5 Preview 本地跑起来:从权重下载到部署的一站式实操

Step 5 Preview 本地跑起来&#xff1a;从权重下载到部署的一站式实操 【免费下载链接】Step-5-Preview Step 5 Preview 是阶跃星辰面向智能体工作打造的旗舰模型。该模型在软件工程和专业知识工作领域均展现出前沿级性能&#xff0c;尤其在金融领域表现突出。 Step 5 Preview …

作者头像 李华
网站建设 2026/10/16 2:05:01

PokeClaw安全Guard机制全解析:AI如何不误发邮件、不误点按钮

AI Agent人工智能大模型本地部署移动开发自主智能体GUI 自动化 【免费下载链接】PokeClaw PokeClaw (PocketClaw) — first on-device AI that controls your Android phone. Gemma 4, no cloud, no API key. Poke is short for Pocket. 项目地址&#xff1a; https://gitcode.…

作者头像 李华