- 前端
- UI组件
【免费下载链接】ckeditor4
The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.
本文围绕 CKEditor 4(当前仓库ckeditor4)中imagebase插件图片题注(caption)功能的一个关键交互行为展开:当包含空题注的图片 widget 失焦(blur)时,题注及其占位文本应被正确隐藏。我们将从仓库中的手动测试文档 captionblur.md 出发,逐条还原测试步骤与预期结果,并结合 imagebase/plugin.js 中getCaptionFeature()的实现、配套 CSS 与自动化测试,讲清楚"题注何时显示、何时隐藏、占位文本如何注入与清除"的完整机制。读完本文,你将能够:独立复现并判断该缺陷是否修复;理解data-cke-caption-hidden、data-cke-caption-placeholder等内部数据属性的作用;并学会用仓库内的 Bender 测试体系验证相关行为。
一、测试文档定位:这是一份"缺陷验证型"手动测试
captionblur.md位于tests/plugins/imagebase/features/manual/目录,属于 Image Base 插件 caption 功能的**手动测试(manual test)**文档。其头部 bender 元信息直接说明了它的性质与运行环境:
@bender-tags: 4.9.0, bug, 932 @bender-ui: collapsed @bender-ckeditor-plugins: sourcearea, wysiwygarea, floatingspace, toolbar, imagebase, link, htmlwriter, elementspath, easyimage逐项解读:
@bender-tags: 4.9.0, bug, 932:该测试归属于 4.9.0 版本(imagebase插件自 4.9.0 引入),标签为bug(验证缺陷修复),关联的 GitHub issue 编号为 932。仓库 CHANGES.md 中对应版本记录也印证了这一点,例如#1776修复了 "Empty caption placeholder of the Image Base plugin is not hidden when blurred"(空题注占位文本在失焦时未隐藏),#1592修复了 "caption is not visible after paste"(粘贴后题注不可见)。@bender-ui: collapsed:运行该测试时编辑器 UI 以折叠形式呈现,便于直接聚焦交互行为。@bender-ckeditor-plugins:加载了sourcearea、wysiwygarea、floatingspace、toolbar、imagebase、link、htmlwriter、elementspath、easyimage等插件组合。其中imagebase是被测插件,easyimage是它的主要使用者之一(见下文)。
配套的测试夹具 captionblur.html 定义了Classic与Divarea两个编辑器实例,各自放置一个"空题注 widget"(<figure>内含<img>与空的<figcaption></figcaption>),并通过以下代码动态注册了一个带 caption 特性的图片 widget:
plugin.addImageWidget( editor, 'testWidget', plugin.addFeature( editor, 'caption', {} ) );其中addFeature( editor, 'caption', {} )将 caption 特性以 mixin 方式合并进 widget 定义,addImageWidget完成注册并调用editor.addFeature( widget )(见 imagebase/plugin.js 与addFeature实现 imagebase/plugin.js)。
二、手动测试步骤与预期结果逐条解读
文档正文包含两个场景,它们验证的是同一缺陷的两个入口:从 widget 本身失焦与从 caption 可编辑区域失焦。
场景 1:Caption - blurring widget(widget 失焦)
操作步骤:
- 聚焦 widget,使题注占位文本(placeholder)出现;
- 点击编辑器外部,使编辑器失去焦点。
预期(Expected):题注占位文本被移除。非预期(Unexpected):题注占位文本仍然可见。
这个场景验证的核心逻辑是:widget 处于聚焦状态时,空的figcaption需要借助占位文本提示用户"此处可输入题注";而一旦失焦,如果题注仍然是空的,占位文本应随之消失。此时题注区域自身也会被隐藏(见第三节源码分析),从而避免在编辑区留下多余的空白行。
场景 2:Caption - blurring editable(caption 可编辑区失焦)
操作步骤:
- 聚焦 widget,使题注占位文本出现;
- 聚焦 caption 可编辑区域,此时占位文本被隐藏、出现编辑光标(caret);
- 点击编辑器外部,使编辑器失去焦点。
预期:题注占位文本被移除。非预期:题注仍然可见。文本可能已被删除,但图片下方仍残留一行多余高度。
这一场景补充验证了更复杂的交互路径:焦点先进入 caption 这个嵌套可编辑区域(nested editable),再从该区域直接失焦。其非预期结果描述得非常具体——"Text might be removed, but there's still one line of extra height below the image"(文本可能被删除了,但图片下方仍有一行多余高度)——这正是 imagebase.css 中[data-cke-caption-hidden] { display: none; }规则所要消除的"空题注残留高度"问题:如果data-cke-caption-hidden未被正确设置,空的figcaption仍会占据布局高度。
交叉验证:使用 Divarea 编辑器重复测试
文档末尾要求:
Repeat above tests with the "Divarea" editor.
divarea是 CKEditor 4 的另一种编辑器 UI 模式(用div替代iframe承载编辑区)。在 captionblur.html 中,Divarea 实例通过CKEDITOR.replace( 'divarea', CKEDITOR.tools.object.merge( config, { extraPlugins: 'divarea' } ) )创建,与 Classic 实例共享同一套 widget 注册逻辑。要求重复测试是因为两种模式下焦点管理、blur事件派发路径存在差异,失焦隐藏逻辑必须在两种宿主环境中都成立。
三、源码实现:caption 特性的显示/隐藏状态机
要理解上述预期为何成立,需要阅读imagebase插件中 caption 特性的完整实现:getCaptionFeature()。其核心是_refreshCaption方法 imagebase/plugin.js:
_refreshCaption: function( sender ) { var isFocused = getFocusedWidget( this.editor ) === this, caption = this.parts.caption, editable = this.editables.caption; if ( isFocused ) { if ( !editable.getData() && !sender.equals( caption ) ) { addPlaceholder( this ); } else if ( !sender || ( sender.equals( caption ) && sender.data( 'cke-caption-placeholder' ) ) ) { removePlaceholder( this ); } setVisibility( caption, true ); } else if ( isEmptyOrHasPlaceholder( this ) ) { removePlaceholder( this ); setVisibility( caption, false ); } }3.1 聚焦分支:显示题注 + 按需注入占位文本
getFocusedWidget( editor )(imagebase/plugin.js)是判断"当前哪个 widget 处于聚焦状态"的入口:它优先返回widgets.focused,若焦点落在嵌套可编辑区域(currentActive instanceof CKEDITOR.plugins.widget.nestedEditable),则通过widgets.getByElement( currentActive )反查所属 widget。这正是场景 2 中"光标在 caption 里"仍能正确判定 widget 聚焦的原因。- 当 widget 聚焦且题注为空、且触发源不是 caption 自身时,调用
addPlaceholder( this )写入占位文本:function addPlaceholder( widget ) { widget.parts.caption.data( 'cke-caption-placeholder', widget.editor.lang.imagebase.captionPlaceholder ); }占位文本内容取自语言包
editor.lang.imagebase.captionPlaceholder:英文为 "Enter image caption"(lang/en.js),简体中文为 "输入图片标题"(lang/zh-cn.js)。 - 当聚焦且光标进入 caption 编辑区(
sender.equals( caption ))时,占位文本被移除(removePlaceholder),让位给真实输入光标。 - 无论是否显示占位文本,聚焦时都会
setVisibility( caption, true ),即data-cke-caption-active置真、data-cke-caption-hidden置假:function setVisibility( caption, isVisible ) { caption.data( 'cke-caption-active', isVisible ); caption.data( 'cke-caption-hidden', !isVisible ); }
3.2 失焦分支:空题注整体隐藏
当 widget 未聚焦且题注为空或仍带占位文本时(isEmptyOrHasPlaceholder),执行:
removePlaceholder( this ); setVisibility( caption, false );即先清除占位文本数据属性,再设置data-cke-caption-hidden。正是这一步,让"空题注在失焦时被隐藏",对应手动测试场景 1 与场景 2 的预期结果。
3.3 触发时机:selectionChange 与 blur 双监听
这些刷新逻辑不是每次手动调用,而是由 caption 特性的setUp统一注册的(imagebase/plugin.js):
setUp: function( editor ) { var listeners = []; function listener( evt ) { var path = evt.name === 'blur' ? editor.elementPath() : evt.data.path, sender = path ? path.lastElement : null, widgets = getWidgetsWithFeature( editor.widgets.instances, 'caption' ); if ( !editor.filter.check( 'figcaption' ) ) { return CKEDITOR.tools.array.forEach( listeners, function( listener ) { listener.removeListener(); } ); } CKEDITOR.tools.array.forEach( widgets, function( widget ) { widget._refreshCaption( sender ); } ); } listeners.push( editor.on( 'selectionChange', listener , null, null, 9 ) ); listeners.push( editor.on( 'blur', listener ) ); }两个细节值得注意:
blur事件也参与刷新:这是本缺陷(空题注失焦不隐藏)得以修复的关键。仅靠selectionChange在部分浏览器/焦点路径下可能不会在"点击编辑器外部"时触发,因此显式监听blur并基于editor.elementPath()计算sender。- 优先级 9:
selectionChange监听使用较高优先级,确保在其它逻辑之前完成题注显隐状态更新。 - ACF 守卫:若编辑器过滤器不允许
figcaption(例如配置了disallowedContent: 'figcaption'),监听器会被整体移除,题注特性随之失效。自动化测试中的test integration with ACF用例(caption.js)专门验证了这一分支。
3.4 初始化与 upcast:缺失的 figcaption 自动补全
init回调(imagebase/plugin.js)负责:
if ( !this.parts.caption ) { this.parts.caption = createCaption( this ); }即当图片 widget 的 HTML 中没有figcaption时(如<figure><img></figure>),自动创建并追加空题注、注册为嵌套可编辑区域(widget.initEditable( 'caption', ... ))。随后在题注为空且尚无占位文本时立即刷新一次,保证初始状态正确。这与 caption.md 中的检查项一致:源码模式下每个 widget 都包含figcaption元素,且figcaption上不应残留任何属性(占位文本、显隐标记均为 CKEditor 运行时数据属性,不会写入输出的 HTML)。
3.5 样式层:数据属性如何驱动视觉表现
imagebase.css 仅用两条规则完成全部视觉逻辑:
[data-cke-caption-hidden] { display: none; } [data-cke-caption-placeholder]::before { display: inline; color: rgba( 0, 0, 0, .4 ); content: attr(>// Blurs the editor, by putting focus in an element outside of the editor. function blurEditor( options ) { var focusHost = CKEDITOR.document.getById( 'focusHost' ), blurHost = options.blurHost; // Normally we'd listen to focusHost#focus event, but it happens **before** blur, which might handle // this case. blurHost.once( 'blur', function() { resume( function() { options.assert(); } ); }, null, null, 9999 ); // Enforce focus event to be called asynchronously on all browsers. setTimeout( function() { focusHost.focus(); }, 0 ); wait(); }其中focusHost是测试夹具 caption.html 中放置在编辑器外的<input type="text" id="focusHost">,与手动测试"点击编辑器外部"一一对应。直接对应本手动场景的用例包括:
test blurring editor hides visible, empty caption (widget focused)(caption.js)——对应手动场景 1;test blurring editor hides visible, empty caption (caption focused)(caption.js)——对应手动场景 2。其注释特别说明:从 caption 失焦时,blur监听宿主应为widget.editor而非 widget 本身,因为 caption 的 blur 事件先于监听器触发;test blurring editor does not hide the caption(caption.js)——验证非空题注在失焦后保持可见(题注有真实内容时不应隐藏);test empty caption placeholder is hidden when blurred(caption.js,对应 issue #1776)——验证多个 widget 共存时,空题注 widget 失焦后data-cke-caption-hidden被正确设置为'true'。
这些用例在classic、divarea、inline三种编辑器上通过createTestsForEditors循环执行(caption.js),覆盖了手动测试文档中"Classic + Divarea 都要重复验证"的要求,并额外覆盖 inline 模式。
五、相关能力与延伸阅读
- caption 特性是
imagebase三大内置特性之一(另两个是upload与link),三者共同构成 imagebase/plugin.js 中的featuresDefinitions。easyimage插件正是基于addImageWidget与这些特性构建的(见 easyimage/plugin.js),因此本手动测试同时加载easyimage插件。 - 相邻手动测试文档 caption.md 从功能完整性角度补充了四条检查项:空题注失焦隐藏、聚焦显示占位文本、源码模式下每个 widget 都含
figcaption、figcaption上无输出属性。它还提示 Edge 浏览器下可能受 issue #1458 影响需双击 widget 才能聚焦——这属于手动测试中需要知晓的浏览器差异。 - 题注失焦隐藏的交互还与其他场景联动:
test toggling caption系列用例验证了"输入文字后题注保持可见""清空文字后题注重新隐藏"以及"粘贴后题注不被意外隐藏(#1592)"等边界行为。
如何运行这些测试:仓库使用 Bender 测试框架(bender.js、bender-runner.config.json)。手动测试可通过 Bender 的 manual tests 页面打开对应 HTML 夹具按步骤操作;自动化测试则通过npm test(或 Bender CLI)执行tests/plugins/imagebase/features/caption.js。无论采用哪种方式,本手动测试文档都是验证"空题注失焦隐藏"缺陷是否回归的第一道关卡。
- 前端
- UI组件
【免费下载链接】ckeditor4
The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.
相关推荐
CKEditor 4 图片 Widget 标题(Caption)功能机制与手动测试指南
CKEditor 4 图片 Widget 标题(Caption)功能机制与手动测试指南 本篇指南聚焦于 CKEditor 4 中 imagebase 插件提供的
前端UI组件图片缩放控件在只读模式下的行为:CKEditor 4 Enhanced Image 手动测试用例深入解析
图片缩放控件在只读模式下的行为:CKEditor 4 Enhanced Image 手动测试用例深入解析 导读: tests/plugins/image2/ma
前端UI组件CKEditor 4 Enhanced Image 图片拖拽边界测试用例解析:dndwithcaption 手动测试与 Widget 拖放机制
CKEditor 4 Enhanced Image 图片拖拽边界测试用例解析:dndwithcaption 手动测试与 Widget 拖放机制 导读 本文围绕仓
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考