
前端UI组件【免费下载链接】ckeditor4The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.项目地址https://gitcode.com/gh_mirrors/ck/ckeditor4点击查看免费下载导读本文围绕 tests/plugins/language/manual/recognizelangelements.md 这份手工测试用例深入剖析 CKEditor 4language插件如何识别光标所在的外语标记元素span lang...并联动工具栏Set Language按钮在 ON/OFF 之间切换的底层机制。读完本文你将掌握该插件getCurrentLangElement的核心算法、命令状态刷新链路、RTL 方向处理策略以及如何通过config.language_list定制语言清单并了解配套的自动化测试与回归修复#5085、#779。1. 关联文档解读一次按钮状态手工验收recognizelangelements.md是 CKEditor 4 仓库中一份典型的 Bender manual 测试脚本用于在真实浏览器环境下验收language插件的一个关键交互行为bender-tags: 4.19.1, bug, 5085 bender-ui: collapsed bender-ckeditor-plugins: wysiwygarea, toolbar, sourcearea, language, format 1. Click on the word inside the editor. **Expected:** Toolbar button Set Language is ON. **Unexpected:** Toolbar button Set Language is OFF. 2. Repeat above step for the editor with RTL language.测试要点非常明确当光标点击到已标记语言的词如span langfrSalut/span内部时工具栏的Set Language按钮必须处于 ON激活状态反之则为异常。并且该行为需要在 LTR 与 RTL 两种编辑器/语言环境下都成立。对应的测试页面 recognizelangelements.html 提供了两个编辑器实例一个用 LTR 的span langfrSalut/span另一个用 RTL 的span langarأهلاً/span二者共用allowedContent: true与language: en的配置h2LTR/h2 textarea nameeditor1 pspan langfrSalut/span./p /textarea h2RTL/h2 textarea nameeditor2 pspan langarأهلاً/span./p /textarea script var config { allowedContent: true, language: en }; CKEDITOR.replace( editor1, config ); CKEDITOR.replace( editor2, config ); /script可以看到测试数据中语言标记元素只携带lang属性而没有dir属性这是 #5085 的典型复现场景下文会详细说明。文档标记为4.19.1, bug, 5085说明该用例正是为 4.19.1 中修复的缺陷 #5085 而新增的回归验收。2. 按钮状态如何被点亮getCurrentLangElement源码剖析Set Language按钮实际注册名为Language类型为CKEDITOR.UI_MENUBUTTON的 ON/OFF 状态由language命令的refresh回调驱动。在 plugins/language/plugin.js 中可以看到editor.addCommand( language, { allowedContent: allowedContent, requiredContent: requiredContent, contextSensitive: true, exec: function( editor, languageId ) { var item items[ language_ languageId ]; if ( item ) editor item.style.checkActive( editor.elementPath(), editor ) ? removeStyle : applyStyle ; }, refresh: function( editor ) { this.setState( plugin.getCurrentLangElement( editor ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF ); } } );refresh在每次选区变化selection change时被触发其逻辑非常简洁当前选区路径中只要存在语言元素命令状态即为CKEDITOR.TRISTATE_ON否则为CKEDITOR.TRISTATE_OFF。而判断是否存在语言元素正是插件核心方法getCurrentLangElement的职责getCurrentLangElement: function( editor ) { var elementPath editor.elementPath(), activePath elementPath elementPath.elements, pathMember, ret; // IE8: upon initialization if there is no path elementPath() returns null. if ( elementPath ) { for ( var i 0; i activePath.length; i ) { pathMember activePath[ i ]; if ( !ret pathMember.getName() span pathMember.hasAttribute( lang ) ) ret pathMember; } } return ret; }该方法的判定规则可以概括为两点遍历元素路径从editor.elementPath()拿到选区所处的祖先元素链elements数组从内到外逐个检查精确匹配条件元素必须是span且带有lang属性命中即返回该元素并停止遍历。这段实现有两点值得注意只认span标签与插件的allowedContent: span[!lang,dir]声明完全一致——语言标记在 CKEditor 4 中统一以span承载只要lang属性存在即判定为语言元素不要求dir属性。这保证了即使遇到 #5085 中只有lang没有dir的历史数据按钮也能正确点亮这是 4.19.1 修复后刻意放宽的行为。3. 从命令状态到按钮 UI菜单与按钮的联动细节命令状态确定后还需要两处 UI 联动才能让用户看到当前语言3.1 按钮本体按钮通过editor.ui.add( Language, CKEDITOR.UI_MENUBUTTON, ... )注册其command: language属性把按钮状态绑定到命令状态上。因此当命令刷新为TRISTATE_ON时Set Language按钮即处于按下/激活外观。3.2 菜单项高亮onMenu回调负责在展开菜单时高亮当前语言项并控制移除语言项的可点击性onMenu: function() { var activeItems {}, currentLanguagedElement plugin.getCurrentLangElement( editor ); for ( var prop in items ) activeItems[ prop ] CKEDITOR.TRISTATE_OFF; activeItems.language_remove currentLanguagedElement ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED; if ( currentLanguagedElement ) activeItems[ language_ currentLanguagedElement.getAttribute( lang ) ] CKEDITOR.TRISTATE_ON; return activeItems; }这里体现了识别的第二次应用不仅按钮要 ON菜单中对应语言项也要打勾TRISTATE_ON且Remove language项仅在存在语言元素时可点击。这与此前 CHANGES.md 中记录的能力一致——#10856 为该插件添加了活动语言高亮并添加了移除语言的选项。4. LTR 与 RTL方向信息从哪来manual 测试要求 LTRfr与 RTLar两种场景下按钮都能点亮而这背后涉及插件对文本方向的两层处理。4.1language_list配置中的方向标注插件的语言清单来自config.language_list默认值为[ ar:Arabic:rtl, fr:French, es:Spanish ]。每个条目遵循languageCode:languageLabel[:textDirection]三段式格式第三段可选默认ltrconfig.language_list [ he:Hebrew:rtl, pt:Portuguese, de:German ];插件在init中解析该配置并为每种语言预生成一个CKEDITOR.styleitems[ languageButtonId ].style new CKEDITOR.style( { element: span, attributes: { lang: curLanguageId, dir: items[ languageButtonId ].ltr ? ltr : rtl } } );也就是说通过菜单应用语言时span会同时写入lang与dir两个属性dir的值由配置第三段决定。exec中style.checkActive( editor.elementPath(), editor )判断该样式是否已激活从而决定是applyStyle还是removeStyle——这正是点击同一语言项两次即移除标记的切换语义。4.2 核心 RTL 语言表core/lang.js中维护了编辑器核心支持的 RTL 语言集合rtl: { ar: 1, fa: 1, he: 1, ku: 1, ug: 1 },该表在编辑器加载语言包时用于自动推导dir见CKEDITOR.lang.load中that[ languageCode ].dir that.rtl[ languageCode ] ? rtl : ltr。manual 测试选用的ar正是核心 RTL 表内成员而fr则是典型 LTR 语言。5. #5085 回归修复缺失dir时自动补全之所以recognizelangelements.md被标记为4.19.1, bug, 5085是因为 CKEditor 4.19.1 修复了这样一个缺陷见 CHANGES.mdFixed: The Language plugin removes the element marking the text in foreign language if said element does not have an information about the text direction.即当span只有lang属性、缺少dir属性时旧版本会在数据处理阶段把整个语言标记元素删除导致Set Language按钮无法识别、语言信息丢失。修复方式是在Language按钮feature上注册内容变换规则contentTransformationscontentTransformations: [ [ // Add missing proper dir attribute when span element has only lang attribute (#5085). { element: span, left: function( element ) { return element.attributes.lang ( !element.attributes.dir || element.attributes.dir ); }, right: function( element ) { var rtlLanguages CKEDITOR.tools.object.keys( CKEDITOR.lang.rtl ), isRtlLanguage CKEDITOR.tools.array.indexOf( rtlLanguages, element.attributes.lang ) ! -1, dirAttribute isRtlLanguage ? rtl : ltr; element.attributes.dir dirAttribute; } } ] ]这条变换规则的含义是遇到有lang但dir缺失或为空的span时查询CKEDITOR.lang.rtl判断该语言是否为 RTL然后自动补上正确的dirrtl或dirltr。这样一来span langfr会被规范化为span langfr dirltrspan langar会被规范化为span langar dirrtl元素不再被过滤器误删按钮识别也就恢复了。配套的 manual 用例正是 addmissingdirattribute.md期望粘贴含span langfrSalut/span的内容后源码中保留dirltr属性而不是被移除。6. 自动化测试印证按钮状态与方向补全除 manual 测试外language插件还有完整的 Bender 单元测试 tests/plugins/language/language.js其中直接对应本文主题的两个用例test selection on lang element should toggle ON language button in LTR language: function() { bender.editorBot.create( { name: editor_lang_ltr, config: { plugins: language,toolbar, allowedContent: true } }, function( bot ) { var editor bot.editor, inputHtml pspan langfrSa^lut/span/p, expectedButtonState CKEDITOR.TRISTATE_ON; bot.setHtmlWithSelection( inputHtml ); var languageButtonState editor.ui.get( Language ).getState(); assert.areSame( expectedButtonState, languageButtonState ); } ); }, test selection on lang element should toggle ON language button in RTL language: function() { // ... 使用 pspan langarأ^هلاً/span/p断言同上 }这两个用例与recognizelangelements.md的验收目标完全一致光标置于带lang属性的span内部时editor.ui.get( Language ).getState()必须返回CKEDITOR.TRISTATE_ON。测试文件还覆盖了 apply/remove 语言、多段落选区逐段包裹、无效语言码不生效、默认language_list可用性等场景。此外测试文件末尾用CKEDITOR.lang.languages与CKEDITOR.lang.rtl生成了对全部支持语言的补全dir参数化用例对每种语言输入span langxxbar/span无dir期望输出span dirltr|rtl langxxbar/span与第 5 节的变换规则相互印证。7. 与 Remove Format 的协作#779 保护机制语言标记元素还可能被清除格式命令误伤。manual 用例 removeformatlanguage.md标记4.7.3, bug, 779要求给文本应用语言后执行Remove Format带lang/dir的span必须保留。插件在init中通过移除格式过滤器实现保护if ( editor.addRemoveFormatFilter ) { editor.addRemoveFormatFilter( function( element ) { return !( element.is( span ) element.getAttribute( dir ) element.getAttribute( lang ) ); } ); }该过滤器挂载到 plugins/removeformat/plugin.js 提供的addRemoveFormatFilter机制上内部存于editor._.removeFormatFiltersremoveFormat命令执行时逐条调用凡是同时带有dir和lang的span返回false即被豁免于格式清除。这解释了为什么 #5085 修复中要补全而非删除dir属性——保留dir是 #779 保护逻辑成立的前提两条回归修复在数据规范上形成了闭环。8. 配置与实战要点小结基于以上分析围绕语言元素识别与按钮联动这一主题可沉淀出以下可直接落地的配置与排查要点关注点说明依据语言清单config.language_list [ code:Label[:rtl|ltr] ]第三段缺省为ltrplugins/language/plugin.js 配置注释标记结构语言标记固定为span规范形态同时含lang与dirallowedContent: span[!lang,dir]同上识别规则光标所在元素链中首个带lang的span即当前语言元素getCurrentLangElement按钮状态命令refresh依据getCurrentLangElement返回结果置TRISTATE_ON/OFF命令定义缺失dir4.19.1 起由contentTransformations依据CKEDITOR.lang.rtl自动补全#5085 修复Remove Format同时含langdir的span受过滤器保护不被清除#779 修复验证手段manual 用例见tests/plugins/language/manual/自动化用例见tests/plugins/language/language.js仓库测试目录8.1 定制语言清单示例在实际项目中可按如下方式定制语言列表例如加入希伯来语并声明 RTL 方向config.language_list [ ar:Arabic:rtl, fr:French, de:German, he:Hebrew:rtl, pt:Portuguese, es:Spanish ];解析逻辑为按:分割第一段为写入lang属性的 ISO 639 语言码推荐 2 位 ISO-639-1第二段为菜单显示标签第三段可选为rtl或ltr。即使配置中漏写方向language_list缺省条目ar:Arabic:rtl之外的 LTR 语言也能正常以ltr处理且 4.19.1 的自动补全规则会在数据进入编辑器时兜底规范化。8.2 排查清单若遇到点击语言词但按钮不亮的问题按顺序检查确认span带有lang属性识别硬性条件确认插件已加载且工具栏配置中包含Language按钮toolbar: bidi,30是默认挂载位确认allowedContent未因配置收紧而把span[lang,dir]过滤掉allowedContent: true为放行若数据源来自外部粘贴且缺少dir确认使用的是 4.19.1 版本自动补全dir若问题出现在执行Remove Format之后确认 4.7.3 且语言span同时保留了dir属性。结语一份只有几行的 manual 测试文档背后串联的是language插件识别语言元素—刷新命令状态—联动按钮/菜单的完整链路以及 #5085、#779 两条回归修复在数据规范化上的设计闭环。理解getCurrentLangElement的判定规则与contentTransformations的补全策略是诊断和定制 CKEditor 4 多语言标记行为的关键读者可结合 plugins/language/plugin.js、core/lang.js 与 tests/plugins/language/language.js 继续深入验证。赞分享前端UI组件【免费下载链接】ckeditor4The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.项目地址https://gitcode.com/gh_mirrors/ck/ckeditor4点击查看免费下载相关推荐CKEditor 4 Language 插件 dir 属性自动补全机制解析从 bug 5085 修复看内容过滤转换与手动测试实践CKEditor 4 Language 插件 dir 属性自动补全机制解析从 bug 5085 修复看内容过滤转换与手动测试实践 本文围绕 CKEditor前端UI组件CKEditor 4 菜单按钮无障碍ARIA测试指南以 Language 插件验证 aria-expanded 与屏幕阅读器朗读行为CKEditor 4 菜单按钮无障碍ARIA测试指南以 Language 插件验证 aria expanded 与屏幕阅读器朗读行为 导读 本文围绕 CK前端UI组件CKEditor 4 Balloon Toolbar 按钮防拖拽机制与手动测试详解CKEditor 4 Balloon Toolbar 按钮防拖拽机制与手动测试详解 导读 本文围绕 CKEditor 4 的 Balloon Toolbar气前端UI组件上一篇pnpm 修复 ssh:// Git 依赖解析带括号 IPv6 主机与无用户信息 URL 的处理方案下一篇Sketchfab模型免费下载终极指南Firefox浏览器一键获取3D资源创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考