☰
CKEditor 4 iframe 对话框编辑模式(editing mode)手动测试:creation 与 editing 状态判定原理及实操验证
2026/10/16 9:15:47 网站建设 项目流程
  • 前端
  • UI组件

【免费下载链接】ckeditor4

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

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

本篇围绕仓库中的手动测试文档 editingmode.md 展开:它用于验证 CKEditor 4 自 4.13.0 版本(feature #2423)引入的"对话框模型与编辑模式"机制在 iframe 插件中的真实行为。读完本文,你将理解这份手动测试的每一步操作与预期结果的来龙去脉,掌握dialog.getModel()/dialog.getMode()的底层判定逻辑,并能借助仓库内的 Bender 测试框架实际复现该验证流程。

一、测试目标与功能背景

editingmode.md对应的功能编号是 #2423,属于 4.13.0 版本引入的对话框(dialog)"模型(model)+ 编辑模式(editing mode)"特性。在 CKEditor 4 中,iframe元素在编辑器内并不可见编辑——它会通过fakeobjects机制被替换成一个带cke_iframe类的假图片(placeholder),编辑行为统一收敛到"iframe 对话框"中完成。

该特性给对话框带来了一个关键问题:打开对话框时,究竟是在"新建"内容,还是在"修改"某个已有对象?手动测试要验证的就是 iframe 对话框在这两种场景下被正确识别:

  • 通过工具栏Iframe按钮打开对话框 →creation(创建)模式;
  • 双击编辑区中已有的 iframe 假对象打开对话框 →editing(编辑)模式。

文档开头的 NOTE 还说明了一个观察细节:在现代浏览器中,预期结果里显示的[element HTML]实际会渲染为真实的 HTML 字符串(即当前正在编辑的元素的外层 HTML),而不是字面量[element HTML]占位符。

二、测试文件构成与 Bender 指令

手动测试由两个文件配合完成:

文件作用
editingmode.html测试页面:提供一个<div id="editor">,初始化编辑器并挂接状态观测工具
editingmode.md手动测试步骤与预期结果脚本(供测试人员/Bender 手动测试面板逐步执行)

editingmode.html的全部内容只有一个容器与一行初始化脚本:

<div id="editor"></div> <script> dialogTools.initDialogEditingModeTest( CKEDITOR.replace( 'editor' ) ); </script>

即:用CKEDITOR.replace('editor')初始化编辑器,然后把实例交给dialogTools.initDialogEditingModeTest()做观测。

editingmode.md开头四行是 Bender 的手动测试元数据指令:

@bender-include: ../../dialog/manual/_helpers/tools.js @bender-tags: dialog, 4.13.0, 2423, feature @bender-ui: collapsed @bender-ckeditor-plugins: wysiwygarea, iframe, toolbar

逐项解读:

  • @bender-include:向测试页面注入 tools.js 辅助脚本。这是 dialog 插件手动测试共用的工具(注意原文路径是相对tests/plugins/iframe/manual/的局部路径,在仓库中的实际位置即tests/plugins/dialog/manual/_helpers/tools.js);
  • @bender-tags:标签声明——属于dialog范畴、与版本4.13.0相关、对应 feature2423、类型为feature,Bender 可据此筛选回归范围;
  • @bender-ui: collapsed:手动测试 UI 默认折叠;
  • @bender-ckeditor-plugins: wysiwygarea, iframe, toolbar:声明本页编辑器需要加载的插件集合——wysiwygarea提供真实可编辑区域,iframe提供 Iframe 按钮与对话框,toolbar使按钮可显示在工具栏上。

三、观测工具 dialogTools:状态面板是如何工作的

dialogTools定义在共用的 tools.js 中,其核心逻辑是:监听每次dialogShow事件,把对话框的模式与模型打印到页面上方的状态面板,测试者据此对照预期结果人工判定。

initDialogEditingModeTest(tools.js 第 31–45 行)先注入状态面板 DOM,支持单个或多个编辑器实例:

// 单个编辑器实例 dialogTools.initDialogEditingModeTest( editor ); // 多个编辑器实例 dialogTools.initDialogEditingModeTest( CKEDITOR.instances );

状态面板由四行文本组成(dialogStatusHtml,tools.js 第 4–15 行),正是editingmode.md中 "Verify status above the editor" 一语的落点:

Dialog name: {对话框名} in {编辑器名} editor. Dialog is in {模式} mode. Currently editing: {模型}

dialogShowListener(tools.js 第 48–62 行)在每次对话框显示时执行三件事:

  1. dialog.getMode( editor )取模式,并映射为文本:CKEDITOR.dialog.EDITING_MODE ? 'editing' : 'creation';
  2. dialog.getModel( editor )取模型,经stringifyModel()转成可读文本;
  3. 通过dialog.once('hide', ...)在对话框隐藏后复位状态面板。

stringifyModel(tools.js 第 64–96 行)对模型做了关键处理:当模型元素带有cke-real-element-type数据(即 fakeobject 假元素)时,先调用editor.restoreRealElement( val )还原出真实的 iframe 元素,再输出其getOuterHtml()。这就是为什么编辑模式下 "Currently editing" 显示的是完整 iframe 标签,而创建模式下显示的是null。

四、手动测试步骤与预期结果(完整继承原文档)

以下按 editingmode.md 原文的编号步骤完整复述,并补充每一步在源码中的对应依据。

阶段 1:验证 creation 模式

  1. Clickiframebutton.—— 点击工具栏中的 Iframe 按钮。按钮由 plugins/iframe/plugin.js 第 40–44 行注册(toolbar: 'insert,80'),点击后执行dialogCommand打开名为iframe的对话框。
  2. Verify status above the editor.—— 核对编辑器上方状态面板。

预期结果(原文档 Expected 部分):

Dialog name:iframeineditoreditor.

Dialog is increationmode.

Currently editing: null

解释:此时编辑区没有选中任何 iframe 对象,getModel()返回null;getMode()因模型为空而判定为CREATION_MODE。面板显示Currently editing: null(stringifyModel对空值直接返回String(null))。

阶段 2:插入 iframe 并验证 editing 模式

  1. Insertexample.comiframeURL and clickOK.—— 在对话框 URL 输入框(info/src字段,必填,带notEmpty校验)中填入example.com,点击 OK 插入 iframe。此时编辑区中出现的其实是一个 80×80 的占位假图片(见下文onOk流程)。
  2. Double clickiframeto open dialog again.—— 双击该占位图,重新打开对话框。双击行为由 plugins/iframe/plugin.js 第 46–50 行注册:当被双击的元素是img且data('cke-real-element-type') == 'iframe'时,将evt.data.dialog设为'iframe'。
  3. Verify status above the editor.—— 再次核对状态面板。

预期结果(原文档 Expected 部分):

Dialog name:iframeineditoreditor.

Dialog is ineditingmode.

Currently editing:[element HTML]

即 "Currently editing" 显示的是当前正被编辑的 iframe 元素的完整 HTML(例如<iframe ... src="example.com" ...></iframe>),而非null。

五、原理剖析:getMode 与 getModel 的判定链

1. 对话框侧:通用的模式判定

plugins/dialog/plugin.js 中的getMode()是模式判定的核心:

getMode: function( editor ) { if ( this.definition.getMode ) { return this.definition.getMode( editor ); } var model = this.getModel( editor ); if ( !model || ( model instanceof CKEDITOR.dom.element && !model.getParent() ) ) { return CKEDITOR.dialog.CREATION_MODE; } return CKEDITOR.dialog.EDITING_MODE; }

判定规则(plugins/dialog/plugin.js 的文档注释也明确说明):

  • 对话框定义若显式提供了getMode函数,则以它为准;
  • 否则依赖getModel():当模型为已挂载到 DOM 的CKEDITOR.dom.element,或是一个CKEDITOR.plugins.widget实例时 →EDITING_MODE;
  • 模型为空、或模型元素尚未挂载到 DOM(!model.getParent())→CREATION_MODE。

两个模式常量的定义见 plugins/dialog/plugin.js:CREATION_MODE: 0(对话框代表"向编辑器引入新变更")、EDITING_MODE: 1(对话框代表"修改已有编辑器状态"),均自 4.13.0 引入。

getModel()(plugins/dialog/plugin.js)的取值优先级为:强制设置的模型(this._.model,经私有方法setModel写入)> 对话框定义中的getModel(editor)函数 >null。

2. iframe 对话框侧:getModel 的具体实现

plugins/iframe/dialogs/iframe.js 提供了 iframe 对话框自己的getModel:

getModel: function( editor ) { var element = editor.getSelection().getSelectedElement(); if ( element && element.data( 'cke-real-element-type' ) === 'iframe' ) { return element; } return null; }

它只认一种模型:当前选区中恰好选中了一个cke-real-element-type === 'iframe'的假图片元素——这正是手动测试阶段 2 中"双击 iframe 占位图"之后的状态。工具栏按钮打开对话框时选区里没有这样的元素,故返回null。两条路径与手动测试的两个 Expected 段严格对应。

3. 创建与编辑两种路径在 onOk 中的分叉

理解"模式"还要看模型如何驱动写入。plugins/iframe/dialogs/iframe.js 的onOk中:

if ( !this.fakeImage ) iframeNode = new CKEDITOR.dom.element( 'iframe' ); // 创建路径:新建 iframe 元素 else iframeNode = this.iframeNode; // 编辑路径:复用 onShow 还原出的原节点

随后统一套用editor.plugins.iframe._.getIframeAttributes( editor, iframeNode )合并附加属性,再用editor.createFakeElement( iframeNode, 'cke_iframe', 'iframe', true )生成新的假元素;fakeImage存在时执行replace(编辑路径,替换旧占位图并选中),不存在时执行editor.insertElement( newFakeImage )(创建路径,插入选区)。这解释了手动测试中"点击 OK 后编辑区出现占位图"的现象。

4. fakeobjects:iframe 在编辑区为何是"假图片"

plugins/iframe/plugin.js 的afterInit阶段向dataProcessor.dataFilter注册规则:数据加载时,每个iframe元素都会被editor.createFakeParserElement( element, 'cke_iframe', 'iframe', true )转换为假元素;onLoad阶段则通过CKEDITOR.addCss注入img.cke_iframe的占位样式(80×80、灰色边框、居中背景图)。这决定了测试者在编辑区"看到"的 iframe 永远是一张贴图,编辑必须经由对话框完成。

5. 安全默认值:iframe_attributes 与 sandbox

onOk中合并的附加属性来自 plugins/iframe/plugin.js 的_.getIframeAttributes,其数据源是配置项iframe_attributes。该配置自 4.21.0 起存在,默认值为{ sandbox: '' }(plugins/iframe/plugin.js 末尾),用于在缺少正确 CSP 配置时对插入的 iframe 做沙箱隔离。源码注释提醒:禁用该选项可能引入安全漏洞;若必须放开,应通过函数形式按src白名单放行,例如(引自 plugins/iframe/plugin.js 的文档注释):

config.iframe_attributes = function( iframe ) { var youtubeOrigin = 'https://www.youtube.com'; if ( youtubeOrigin.indexOf( iframe.attributes.src ) !== -1 ) { return { sandbox: "allow-scripts allow-same-origin" }; } return { sandbox: "" }; }

或对象形式:

config.iframe_attributes = { sandbox: 'allow-scripts allow-same-origin', allow: 'autoplay' };

六、与自动化测试的互证

手动测试验证的判定链,在 tests/plugins/iframe/iframe.js 中有两条同名(#2423)的自动化断言,二者结论互相印证:

// (#2423) 'test dialog model during iframe creation' bot.dialog( 'iframe', function( dialog ) { assert.isNull( dialog.getModel( editor ) ); assert.areEqual( CKEDITOR.dialog.CREATION_MODE, dialog.getMode( editor ) ); } ); // (#2423) 'test dialog model with existing iframe' // 先 setData 一个真实 iframe(被 fakeobject 化),再选中 .cke_iframe 假元素 var iframe = editor.editable().findOne( '.cke_iframe' ); editor.getSelection().selectElement( iframe ); assert.areEqual( iframe, dialog.getModel( editor ) ); assert.areEqual( CKEDITOR.dialog.EDITING_MODE, dialog.getMode( editor ) );

(见 tests/plugins/iframe/iframe.js)——与手动测试的 "Currently editing: null / creation" 和 "Currently editing: 元素 HTML / editing" 一一对应。

七、如何运行这份手动测试

本仓库使用 Bender 作为测试框架,相关配置见 bender.js 与 bender-runner.config.json:

  • bender.js 声明了应用(加载根目录ckeditor.js)、插件组(含benderjs-yui、benderjs-sinon、自定义的tests/_benderjs/ckeditor插件)以及测试分组,其中'Plugins'组的扫描路径为plugins/**、basePath为tests/,因此tests/plugins/iframe/manual/editingmode.md会作为手动测试被收集进该组;
  • bender-runner.config.json 规定 bender 服务监听端口9001、静态资源服务端口9002,并给出浏览器列表(linux 下为 chrome/firefox)。

实际操作方式:在仓库根目录安装依赖后启动 Bender(例如npx bender run,具体以仓库当前依赖清单为准),打开其 Web 界面,在 Plugins 组下找到该 iframe 手动测试条目执行;页面即加载 editingmode.html,随后按 editingmode.md 中的编号步骤逐条操作,并与面板输出比对。

八、小结

这份手动测试文档虽然篇幅很短,但它完整覆盖了 #2423 特性在 iframe 场景的两个关键断言点:

  1. 创建路径:工具栏按钮打开对话框 →getModel()返回null→getMode()判定为CREATION_MODE,面板显示Currently editing: null;
  2. 编辑路径:双击cke_iframe假元素打开对话框 →getModel()返回被选中的假图片元素 →getMode()判定为EDITING_MODE,面板经stringifyModel(含restoreRealElement还原)显示真实 iframe 的完整 HTML。

结合 plugins/iframe/plugin.js 的 fakeobject 转换、plugins/iframe/dialogs/iframe.js 的getModel/onOk分叉逻辑、plugins/dialog/plugin.js 的通用模式判定,以及 tests/plugins/iframe/iframe.js 的自动化断言,即可对该特性的判定机制形成从用户操作、源码实现到测试验证的闭环理解。

  • 前端
  • UI组件

【免费下载链接】ckeditor4

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

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

相关推荐

上一篇:minikube 设计原则解读:本地运行 Kubernetes 的工程哲学与实践落地
下一篇:用 Hister 打造个人搜索引擎工作流:从全局快捷键到索引维护的完整实践

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询