- 前端
- UI组件
【免费下载链接】ckeditor4
The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.
导读
本文围绕 CKEditor 4 Emoji 插件在 4.20.0 版本引入的emoji_followingSpace配置项展开,以官方手动测试用例 followingspace.md 为主线,结合 Autocomplete 插件源码与自动化测试,讲清"在编辑器中通过:bug这类别名触发自动补全、按回车确认插入表情后,编辑器如何自动在表情符号后面补一个空格"这一行为的前因后果。读完本文,你将掌握该配置的启用方式、默认行为、底层实现原理、防重复空格机制,以及与之配套的emoji_minChars、匹配规则等相邻配置。
一、功能背景:为什么要在表情后面自动补空格
在 CKEditor 4 的 Emoji 插件中,用户可以在可编辑区域直接输入形如:bug的短别名来触发自动补全建议框,并按回车(Enter)确认,将选中的表情符号(如 🐛)插入到光标处。这在带来便捷的同时也引入了一个体验问题:
- 插入表情后光标紧贴表情符号(
🐛^),用户若想继续输入文字,必须先手动敲一个空格,否则后续文字会与表情粘连; - 表情属于宽字符(部分系统下渲染宽度接近两个 ASCII 字符),粘连排版极易造成视觉混乱。
为此,CKEditor 4 在 4.20.0 版本(对应 issue #2008)为 Emoji 与 Mentions 两个基于 Autocomplete 的插件同时引入了"插入后自动补空格"的开关。CHANGES.md 中对本次功能扩展有明确记录:
config.emoji_followingSpace选项用于 Emoji 插件;configDefinition.followingSpace选项用于 Mentions 插件。
该开关默认关闭,即默认情况下沿用旧行为(🐛^);开启后则变为🐛 ^。
二、官方手动测试用例解析
关联文档 tests/plugins/emoji/manual/followingspace.md 是一个标准的 Bender 手动测试用例,用于人工验证上述功能。其测试前置条件由文档头部的 Bender 标签声明:
@bender-tags: 4.20.0, feature, 2008 @bender-ui: collapsed @bender-ckeditor-plugins: wysiwygarea, toolbar, basicstyles, autocomplete, textmatch, emoji测试步骤非常简洁,共三步:
- 将光标置于编辑器可编辑区域(Place cursor on the editable);
- 输入
:bug(此时应弹出包含 🐛 的自动补全建议框); - 按回车键确认插入(Press enter)。
期望结果(Expected)
插入后表情符号后面自动补了一个空格:🐛 ^(Space has been added after the insertion)。注意这里的空格在数据层面是不换行空格 ,而非普通半角空格。
非期望结果(Unexpected)
插入后表情符号后面没有空格:🐛^(Space has not been added after the insertion)。
与它配套的测试页面 tests/plugins/emoji/manual/followingspace.html 揭示了该用例的启用前提——在替换编辑器时显式打开配置:
<div id="editor"></div> <script> bender.tools.ignoreUnsupportedEnvironment( 'emoji' ); CKEDITOR.replace( 'editor', { emoji_followingSpace: true } ); </script>也就是说:只有当emoji_followingSpace: true被显式设置时,才会得到期望结果;在默认配置下,同样的三步操作会得到"非期望结果"(即旧行为),这正是该开关存在的意义。
三、配置项详解与启用方式
emoji_followingSpace是 Emoji 插件暴露给CKEDITOR.config的公开配置项,其官方文档注释位于 plugins/emoji/plugin.js:
/** * Indicates if a following space should be added after inserted match into an editor. * * @since 4.20.0 * @cfg {Boolean} [emoji_followingSpace=false] * @member CKEDITOR.config */ CKEDITOR.config.emoji_followingSpace = false;要点汇总:
| 属性 | 值 |
|---|---|
| 配置名 | emoji_followingSpace |
| 类型 | Boolean |
| 默认值 | false(不自动补空格) |
| 引入版本 | 4.20.0 |
| 作用对象 | 通过输入别名触发自动补全并回车确认的插入场景 |
在页面中启用方式即如上文测试页面所示,在CKEDITOR.replace的配置对象中加入该选项即可:
CKEDITOR.replace( 'editor', { emoji_followingSpace: true } );相邻配置:emoji_minChars 与匹配规则
理解该开关前,需要先明确 emoji 自动补全的触发条件。Emoji 插件在初始化时会读取两个关键配置(见 plugins/emoji/plugin.js):
emoji_emojiListUrl:表情数据 JSON 的地址,默认指向plugins/emoji/emoji.json,通过CKEDITOR.ajax.load异步加载;emoji_minChars:触发建议框所需的别名最少字符数(不含前置的:冒号),默认值为 2。
在插件源码中,匹配回调使用如下正则来识别输入别名(plugins/emoji/plugin.js):
match = left.match( new RegExp( '(?:\\s|^)(:\\S{' + charactersToStart + '}\\S*)$' ) );其中charactersToStart即emoji_minChars。该正则要求别名前必须是空白符(空格或换行)或行首,因此输入:bug前通常需要一个前置空格或直接位于段落开头,这与 tests/plugins/emoji/manual/spacerequired.md 手动用例所验证的行为一致。触发后,dataCallback会对加载的表情列表按id做大小写不敏感的子串匹配并排序(plugins/emoji/plugin.js),例如:bug会命中 id 为:bug:、符号为 🐛 的条目。
四、源码实现原理:空格是如何被插入的
emoji_followingSpace本身并不在 Emoji 插件中直接做插入逻辑,而是被透传给底层 Autocomplete 插件的实例配置。在 plugins/emoji/plugin.js 中:
function initPlugin() { editor._.emoji.autocomplete = new CKEDITOR.plugins.autocomplete( editor, { textTestCallback: getTextTestCallback(), dataCallback: dataCallback, itemTemplate: '<li>/** * Indicates if a following space should be added after inserted match into an editor. * * @since 4.20.0 * @readonly * @property {Boolean} [followingSpace] */ this.followingSpace = config.followingSpace;commit 提交流程
当用户按回车(或其他提交快捷键)确认建议项时,Autocomplete 的commit方法负责把选中的表情写入编辑器(plugins/autocomplete/plugin.js),核心代码如下:
var item = this.model.getItemById( itemId ), editor = this.editor, html = this.getHtmlToInsert( item ); // Insert space after accepting match (#2008). html += this.followingSpace ? ' ' : ''; editor.fire( 'saveSnapshot' ); editor.getSelection().selectRanges( [ this.model.range ] ); editor.insertHtml( html, 'text' ); if ( this.followingSpace ) { removeLeadingSpace( editor ); } editor.fire( 'saveSnapshot' );整个流程可拆解为:
- 生成插入 HTML:
getHtmlToInsert依据outputTemplate(emoji 插件为'{symbol}')生成要插入的内容; - 追加空格:若
followingSpace为真,则在 HTML 末尾拼接 (不换行空格),这就是手动用例中🐛 ^里那个空格的数据形态; - 快照与插入:先触发
saveSnapshot(供撤销栈使用),再把选区定位到查询词所在范围,用editor.insertHtml( html, 'text' )完成"别名 → 表情 + 空格"的替换; - 防重复清理:若
followingSpace为真,调用removeLeadingSpace( editor )(见下); - 再次保存快照:保证一次提交在撤销历史中可整体回退。
removeLeadingSpace:防止空格重复
如果用户输入:bug时别名前本来就带了空格,插入的表情尾部又自动补了空格,就可能出现两个连续空格。removeLeadingSpace正是为消除这种重复而设计的(plugins/autocomplete/plugin.js):
function removeLeadingSpace( editor ) { var selection = editor.getSelection(), nextNode = selection.getRanges()[ 0 ].getNextNode( function( node ) { return Boolean( node.type == CKEDITOR.NODE_TEXT && node.getText() ); } ); if ( nextNode && nextNode.getText().match( /^\s+/ ) ) { var range = editor.createRange(); range.setStart( nextNode, 0 ); range.setEnd( nextNode, 1 ); range.deleteContents(); } }其逻辑是:插入完成后,查找选区之后的下一个文本节点,若该文本节点以空白字符开头,则用 Range 删除这段前导空白。由于表情之后的 已经由 commit 插入,原来的前导空格被清除后不会造成"空格缺失",从而实现"不多不少恰好一个空格"。
同生态对照:Mentions 插件的 followingSpace
相同的机制同样被 Mentions 插件复用。在 plugins/mentions/plugin.js 中,Mentions 的配置定义声明了同名的followingSpace属性,并在构造内部 Autocomplete 实例时透传:
this.followingSpace = config.followingSpace; // ... this._autocomplete = new CKEDITOR.plugins.autocomplete( editor, { textTestCallback: getTextTestCallback( this.marker, this.minChars, this.pattern ), dataCallback: getDataCallback( feed, this ), itemTemplate: config.itemTemplate, outputTemplate: config.outputTemplate, throttle: this.throttle, itemsLimit: config.itemsLimit, followingSpace: this.followingSpace } );因此,凡是基于 Autocomplete 插件构建的自动补全功能(emoji、mentions,乃至自定义 autocomplete 场景),都可以通过这一开关统一获得"提交后自动补空格"的能力。
五、自动化测试验证:行为被测试用例锁死
除了手动用例,该功能在 Autocomplete 插件还有一组自动化断言,位于 tests/plugins/autocomplete/autocomplete.js,均以// (#2008)标注对应 issue:
1. 空格被正确插入(test following space is inserted after accepting match)
创建带followingSpace: true的 Autocomplete 实例,在空内容中触发并回车提交后断言:
assert.areEqual( '<p>item1 </p>', editor.getData() );2. 空格不会被重复(test following space is not doubled)
光标前预置^ foo(即别名前已有空格),提交后断言恰好一个空格:
assert.areEqual( '<p>item1 foo</p>', editor.getData() );3/4. 输出模板场景(outputTemplate 相关两条)
使用<strong>{name}</strong>作为输出模板,分别验证"原有空格"与"无空格"两种前置条件下,提交结果均为:
assert.beautified.html( '<p><strong>item1</strong> foo</p>', editable.getData() );这四条用例从正反两个方向锁定了"补空格"与"不重复补空格"两个行为,并覆盖了自定义输出模板的情况。需要留意的是,这些用例在 IE 11 以下版本会被跳过(// Ignore test due to IE issue (#2077).),这与 Emoji 插件本身的环境支持策略一致——isSupportedEnvironment要求非 IE 或 IE 11+(见 plugins/emoji/plugin.js)。
此外,Autocomplete 插件也提供了对应的手动用例 tests/plugins/autocomplete/manual/followingspace.html(其脚本中同样以followingSpace: true初始化实例)以及 tests/plugins/autocomplete/manual/existingspace.html、tests/plugins/autocomplete/manual/outputtemplatespace.html,分别验证既有空格与输出模板下的空格行为,与 emoji 的手动用例相互印证。
六、实践建议与验证方法
- 何时开启:如果你的业务场景中用户习惯"输入别名 → 回车插入 → 立即继续打字",建议开启
emoji_followingSpace: true,避免表情与后续文字粘连;如果表情通常作为独立元素或句子末尾使用,可保持默认关闭。 - 与前置空格的关系:由于匹配正则要求别名前有空格或换行(plugins/emoji/plugin.js),配合
followingSpace开启后,最终效果是"前置空格被清除、表情后补一个 ",整体排版仍保持表情前后各一个分隔空隙,removeLeadingSpace保证了不会出现双空格。 - 如何验证:可参照 tests/plugins/emoji/manual/followingspace.md 的步骤,在配置了
emoji_followingSpace: true的编辑器实例中依次执行"定位光标 → 输入:bug→ 按回车",观察插入结果是否为🐛 ^;再在同一实例下对比关闭该配置时的🐛^行为差异。 - 环境注意:该功能要求 Emoji 插件的受支持环境(IE 11 及以上或非 IE 浏览器),在旧版 IE 中相关测试会被忽略,配置项不会生效。
总而言之,emoji_followingSpace是一个小而精的体验优化开关:它由 Emoji 插件对外暴露配置,由 Autocomplete 插件在提交流程中统一实现,通过 追加与removeLeadingSpace去重两个动作,最终保证了"插入表情后自动补一个且仅一个空格",并被手动用例与自动化测试双重覆盖。
- 前端
- UI组件
【免费下载链接】ckeditor4
The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.
相关推荐
CKEditor 4 Autocomplete `followingSpace` 配置实战:在自动补全匹配项后自动插入空格
CKEditor 4 Autocomplete followingSpace 配置实战:在自动补全匹配项后自动插入空格 导读 本篇文章围绕 CKEditor 4
前端UI组件CKEditor 5 Emoji 表情功能实战:安装配置、`:` 自动补全与表情仓库加载机制详解
CKEditor 5 Emoji 表情功能实战:安装配置、 : 自动补全与表情仓库加载机制详解 本文以 CKEditor 5 仓库中 emoji 功能官方文档
前端富文本UI组件CKEditor 4与表情符号集成:Emoji插件开发与使用终极指南
CKEditor 4与表情符号集成:Emoji插件开发与使用终极指南 在现代化的富文本编辑体验中,表情符号已成为不可或缺的沟通元素。CKEditor 4作为企业
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考