- 前端
- UI组件
【免费下载链接】ckeditor4
The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.
导读
本文围绕 CKEditor 4 仓库中位于tests/plugins/clipboard/manual/draganddropimage.md的手动测试用例,系统讲解自 4.17.0 起引入的"拖放图片自动转 Base64"能力(对应 issue #4681):将 PNG/JPEG/GIF 图片从文件系统拖入编辑器后,clipboard 插件会通过FileReader把图片读取为data:image/...;base64,...并插入<img>标签;而 PDF 等不支持的类型则被静默忽略并弹出通知。读完本文你将掌握该功能的验证方法、底层事件与转换链路、相关配置项(clipboard_handleImages、clipboard_notificationDuration)以及配套自动测试的断言细节。
一、测试用例要验证什么:拖放图片的两种场景
该手动测试文档通过两个场景,分别验证"支持的类型被正确转换"与"不支持的类型被正确拒绝"两条行为路径,且同时覆盖经典(wysiwygarea)与行内(inline)两种编辑器形态。
测试前置标签声明了所需插件集合:
wysiwygarea, sourcearea, clipboard, undo, image, floatingspace,其中clipboard是本功能的核心承载插件,image用于保证<img>在内容中被合法解析与显示。
Scenario 1:拖放受支持的图片格式
操作步骤:
- 打开浏览器控制台(便于观察报错)。
- 依次将
image/png、image/jpeg、image/gif三种格式的图片拖入可编辑区域。 - 对行内编辑器(inline editor)重复上述操作。
预期结果:浏览器控制台无任何报错;图片被正确粘贴;生成的<img>标签src属性为 Base64 格式(data:image/png;base64,...等)。
非预期结果:浏览器控制台出现错误;图片不可见。
Scenario 2:拖放不支持的文件类型
操作步骤:
- 打开浏览器控制台。
- 拖入受支持格式以外的文件,例如
.pdf。 - 对行内编辑器重复上述操作。
预期结果:浏览器控制台无报错;可编辑区域内容不发生任何变化。
非预期结果:浏览器控制台出现错误;可编辑区域内容被改变。
测试夹具:经典编辑器与行内编辑器并存
配套的 HTML 夹具 draganddropimage.html 展示了测试页的构造方式:同时创建经典编辑器与行内编辑器,并借助bender.tools.env.mobile与CKEDITOR.plugins.clipboard.isFileApiSupported做环境探测,在不支持 File API 的浏览器上直接bender.ignore()跳过测试:
<div id="editor"> <p>Drag and drop image here.</p> </div> <p>Inline editor.</p> <div id="inline" contenteditable="true" style="border:1px solid #000000;"> <p>Drag and drop image here.</p> </div> <script> if ( bender.tools.env.mobile ) { bender.ignore(); } var editor = CKEDITOR.replace( 'editor' ), inline = CKEDITOR.inline( 'inline', { extraPlugins: 'sourcedialog' } ); editor.on( 'loaded', function() { if ( !CKEDITOR.plugins.clipboard.isFileApiSupported ) { bender.ignore(); } } ); </script>这里透露出一个重要前提:该能力依赖浏览器 File API,因此isFileApiSupported为false的环境(如 IE9 及以下)无法验证本功能。
二、功能背景:4.17.0 的 Base64 拖放图片支持
该功能在 CHANGES.md 中有明确记录,归属于 4.17.0 版本的功能列表:
- #4612:允许在所有浏览器(除 IE 外)中从剪贴板将图片粘贴为 Base64;
- #4681:允许将拖放(drag and drop)的图片转为 Base64——这正是本文所讲手动测试的验证对象;
- #4750:为粘贴/拖放不支持的文件类型增加通知提示。
由此可以看到一条完整的能力演进链:粘贴图片转 Base64 → 拖放图片转 Base64 → 不支持类型给出通知。本手动测试恰好把这三项能力(转换 + 拒绝 + 通知)集成在两个场景中验证。
三、源码级实现原理
3.1 图片转 Base64 的转换监听器
核心逻辑位于 plugins/clipboard/plugin.js。clipboard 插件在init阶段向编辑器的paste事件注册了一个优先级为 1的监听器(数值越小越先执行),用异步的FileReader把图片文件读成 Data URL:
// Convert image file (if present) to base64 string. // Do it as the first step as the conversion is asynchronous and should hold all further paste processing. editor.on( 'paste', function( evt ) { if ( !isFilePasteSupported || !editor.config.clipboard_handleImages ) { return; } var dataObj = evt.data, data = dataObj.dataValue, dataTransfer = dataObj.dataTransfer; // Allow both dragging and dropping and pasting images as base64 (#4681). if ( data || !isFileData( evt, dataTransfer ) ) { return; } var file = dataTransfer.getFile( 0 ); if ( !testImageBase64Support( file ) ) { return; } var fileReader = new FileReader(); // Convert image file to img tag with base64 image. fileReader.addEventListener( 'load', function() { evt.data.dataValue = '<img src="' + fileReader.result + '" />'; editor.fire( 'paste', evt.data ); }, false ); // abort / error 时走正常流程并重新触发 paste(见下方 IE 特判) fileReader.addEventListener( 'abort', function() { setCustomIEEventAttribute( evt ); editor.fire( 'paste', evt.data ); }, false ); fileReader.addEventListener( 'error', function() { setCustomIEEventAttribute( evt ); editor.fire( 'paste', evt.data ); }, false ); fileReader.readAsDataURL( file ); latestId = dataObj.dataTransfer.id; evt.stop(); }, null, null, 1 );关键设计点:
- 异步前置:注释明确说明"转换是异步的,因此必须挂起后续所有粘贴处理"。
FileReader的load回调中把结果写入evt.data.dataValue并重新fire('paste'),再evt.stop()终止当前这次事件分发,从而保证图片数据就绪后才进入后续的 HTML 过滤与插入流程。 - 拖放与粘贴共用同一路径:注释
Allow both dragging and dropping and pasting images as base64 (#4681)表明,无论图片来自剪贴板粘贴还是拖放,最终都会统一收敛到paste事件上处理——这正是拖放图片能被"粘贴"进编辑器的原因。 - 失败兜底:
FileReader触发abort或error时不会丢弃数据,而是重新触发paste走正常流程。setCustomIEEventAttribute对 IE 设置fileTransferCancel标记,用于防止 IE10+ 在图片加载状态非load时陷入无限循环(见isFileData中对该标记的检查)。
3.2 支持格式白名单与配置开关
testImageBase64Support(plugins/clipboard/plugin.js#L238-L246)定义了可转换的 MIME 类型白名单,并检查配置开关:
function testImageBase64Support( file ) { // Check if turning images into base64 is disabled (#5431). if ( !editor.config.clipboard_handleImages ) { return false; } var supportedImageTypes = [ 'image/png', 'image/jpeg', 'image/gif' ]; return CKEDITOR.tools.indexOf( supportedImageTypes, file.type ) !== -1; }这与手动测试 Scenario 1 要求验证的三种格式(PNG/JPEG/GIF)完全一一对应。application/pdf不在白名单内,因此 Scenario 2 中拖入 PDF 不会生成<img>,编辑器内容保持不变。
注意:testImageBase64Support在 4.19.0 之后还承担"文件匹配器(file matcher)"的职责——插件通过CKEDITOR.plugins.clipboard.addFileMatcher( editor, matcher )(plugin.js#L1748-L1771)注册校验函数,用于判断某文件是否受支持;对不支持的文件,插件会显示通知,但不会取消 paste 事件,是否真正拒绝/上传由集成方负责。
3.3 "仅文件"判定:避免误伤普通拖放
isFileData(plugins/clipboard/plugin.js#L282-L294)限定只有"仅包含单个文件"的 dataTransfer 才会触发图片转换,防止与编辑器内部的文本/HTML 拖放(内部拖放、跨编辑器拖放)混淆:
function isFileData( evt, dataTransfer ) { // Checking for fileTransferCancel on IE to prevent comparing empty string // from dataTransfer.id and falling into infinite loop (#4681). if ( CKEDITOR.env.ie && evt.data.fileTransferCancel ) { return false; } if ( !CKEDITOR.env.ie && ( !dataTransfer || latestId === dataTransfer.id ) ) { return false; } return dataTransfer.isFileTransfer() && dataTransfer.getFilesCount() === 1; }同时,插件在paste事件优先级 1 的位置还有一个"不支持文件类型通知"监听器(plugin.js#L158-L184):遍历 dataTransfer 中的文件,凡是isFileTypeSupported判定失败的类型都会被收集进unsupportedFileTypes,最终通过displayUnsupportedFileTypesNotification调用editor.showNotification( ..., 'info', editor.config.clipboard_notificationDuration )弹出提示。消息文案在 plugins/clipboard/lang/en.js:
fileFormatNotSupportedNotification: 'The ${formats} file format(s) are not supported.', fileWithoutFormatNotSupportedNotification: 'The file format is not supported.'3.4 拖放执行链路:drop → paste
initDragDrop(plugins/clipboard/plugin.js#L1531-L1741)在contentDom阶段为可编辑区域挂接dragstart/dragover/dragend/drop监听。对于来自外部源(如文件系统)的拖放,externalDrop(plugin.js#L1701-L1712)会:
dropRange.select()把光标定位到拖放落点;firePasteEvents( editor, { dataTransfer: dataTransfer, method: 'drop' }, 1 )触发paste事件——dataTransfer 中的文件随之进入 3.1 的 Base64 转换监听器;- 由于
dragend发生在拖放源元素上、外部拖放不会触发它,因此这里显式调用clipboard.resetDragDataTransfer()清理全局拖放状态。
文件头部的执行流程注释(plugin.js#L86-L112)也完整描述了三种拖放分支:内部拖放(带cke-前缀时间戳匹配)、跨编辑器拖放、外部源拖放——外部文件拖放正是走最后一条分支。此外,dragover监听器对 IE 且 dataTransfer 含Files的场景调用preventDefault(),避免浏览器直接用文件路径覆盖文档内容。
四、相关配置项
4.1clipboard_handleImages
定义位于 plugins/clipboard/plugin.js#L3562-L3570:
/** * Whether to use clipboard plugin to handle image pasting and dropping, * turning images into base64 strings on browsers supporting the File API. * * @since 4.17.0 * @cfg {Boolean} [clipboard_handleImages=true] * @member CKEDITOR.config */ CKEDITOR.config.clipboard_handleImages = true;- 默认值:
true; - 引入版本:4.17.0(与本手动测试的
@bender-tags标注一致); - 作用:决定 clipboard 插件是否接管图片的粘贴与拖放并把图片转为 Base64;
- 适用前提:浏览器支持 File API(
CKEDITOR.plugins.clipboard.isFileApiSupported)。
当该配置为false时,testImageBase64Support直接返回false,图片不会被转换,且由于图片此时落入"不受支持类型"分支,编辑器会弹出"文件格式不受支持"通知。仓库中专门提供了两个手动测试文档佐证这一行为:pasteimagedisable.md 与 dropimagedisabled.md,后者描述"从文件系统拖入图片,预期不插入图片,仅输出自定义图片拖放处理收到的数据"。
关闭该配置的典型场景:集成方希望自己接管图片处理(例如配合上传插件把图片上传到服务器,而不是塞进 Base64)。clipboardimagedisabled.js 即演示了在clipboard_handleImages: false时自定义图片处理器插件可自行消费文件。
4.2clipboard_notificationDuration
定义位于 plugins/clipboard/plugin.js#L3553-L3560:
/** * Duration of the notification displayed after pasting was blocked by the browser. * * @since 4.7.0 * @cfg {Number} [clipboard_notificationDuration=10000] * @member CKEDITOR.config */ CKEDITOR.config.clipboard_notificationDuration = 10000;- 默认值:
10000(毫秒); - 作用:控制不支持文件类型通知的展示时长(单位为毫秒),由
editor.showNotification( message, 'info', duration )使用。
五、自动化测试如何验证同一行为
除了手动测试,仓库还提供了与手动测试断言完全对齐的自动化测试,可作为回归验证依据:
5.1 拖放场景:dropimage.js
test drop .png/.jpeg/.gif image:模拟拖放事件后,断言最终 HTML 中出现src="data:image/png;base64,fileMockBase64="的<img>(测试用mockFileReader注入伪造的 Base64 结果);test drop unsupported image type:拖入application/pdf,断言编辑器内容保持<p class="p">Paste image here:</p>不变;test dropping unsupported image type shows notification:断言showNotification被调用一次、消息匹配fileFormatNotSupportedNotification、类型为info、时长为clipboard_notificationDuration;(#5431) test dropping image when the clipboard_handleImages configuration option is OFF ...:关闭配置后拖入 PNG,同样只弹通知、不插入图片。
5.2 粘贴场景:pasteimage.js
- 粘贴 PNG/JPEG/GIF 均断言生成带
data-cke-saved-src与src双属性的 Base64<img>; test unsupported file type(application/pdf)、abort、error、clipboard_handleImages: false等分支与拖放测试一一对应;test pasting image alongside other content(对应 #3585/#3625)验证"图片与其他内容同时粘贴时,文本内容优先、图片被忽略"的边界行为。
自动测试与手动测试共同覆盖的场景矩阵完全一致,说明 draganddropimage.md 中"PNG/JPEG/GIF 成功、PDF 拒绝、内容不变、无控制台报错"的预期并非孤例,而是有代码与断言双重保障的稳定契约。
六、验证建议与边界说明
在本地复现手动测试时,可关注以下几点:
- 浏览器要求:务必使用支持 File API 的现代浏览器(Chrome、Firefox、Edge);IE10 以下会因
isFileApiSupported为false而跳过,且 IE 场景依赖fileTransferCancel标记避免死循环。 - 编辑器形态:经典编辑器(
CKEDITOR.replace)与行内编辑器(CKEDITOR.inline)都应验证,二者共享同一套paste/drop处理逻辑。 - 控制台观察:拖入文件后关注 console 是否有异常;同时可观察编辑器内容中
<img>的src是否以data:image/png;base64,等前缀开头。 - 格式边界:
image/svg+xml、image/webp、application/pdf等均不在白名单内,会被当作不支持类型处理(触发通知、内容不变)。 - 内容优先级:若拖放/粘贴的数据中同时包含文本与文件,文本数据(
dataValue)优先,图片转换不会覆盖已有内容(见 3.3 的if ( data ) return判断)。 - 集成扩展:如需自定义支持格式或接管处理流程,可参考
CKEDITOR.plugins.clipboard.addFileMatcher注册自定义匹配器,并配合clipboard_handleImages: false自行实现图片上传逻辑。
综上,tests/plugins/clipboard/manual/draganddropimage.md是验证 CKEditor 4.17.0 "拖放图片转 Base64"(#4681)能力的权威手动验收入口;理解其背后 plugins/clipboard/plugin.js 中"FileReader 异步转换 + paste 事件重放 + MIME 白名单 + 通知兜底"的完整链路,即可在实际集成中准确预判并扩展这一行为。
- 前端
- UI组件
【免费下载链接】ckeditor4
The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.
相关推荐
CKEditor 4 Balloon Toolbar 按钮防拖拽机制与手动测试详解
CKEditor 4 Balloon Toolbar 按钮防拖拽机制与手动测试详解 导读 本文围绕 CKEditor 4 的 Balloon Toolbar(气
前端UI组件CKEditor 4 剪贴板插件拖放(Drag & Drop)数据流深入解析:基于 draganddropdata 手动测试用例
CKEditor 4 剪贴板插件拖放(Drag & Drop)数据流深入解析:基于 draganddropdata 手动测试用例 导读 本文以仓库中 draga
前端UI组件CKEditor 4 选区滚动定位机制解析:从 selection.scrollIntoView 到手动测试用例
CKEditor 4 选区滚动定位机制解析:从 selection.scrollIntoView 到手动测试用例 CKEditor 4 的 selection.
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考