我要提问
ARTICLE DETAIL

资讯详情

前沿编程新知与开发实战干货的深度解读。

CKEditor 4 粘贴修复实战:从 Word/Outlook 粘贴含水平线的图文内容不再失败(4873 手动测试全解析)

CKEditor 4 粘贴修复实战:从 Word/Outlook 粘贴含水平线的图文内容不再失败(4873 手动测试全解析) 前端UI组件【免费下载链接】ckeditor4The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.项目地址https://gitcode.com/gh_mirrors/ck/ckeditor4点击查看免费下载本文围绕 CKEditor 4 4.17.2 版本修复的缺陷 #4873 展开从 Word 或 Outlook 复制包含水平线hr的图文内容粘贴进编辑器时图片会丢失且控制台抛出pastetools-failed-image-extraction错误。文章以仓库中的手动测试用例 pasteimagewithhrline.md 为骨架结合 image.js 源码与自动化测试完整还原问题根因、修复逻辑、复现步骤与回归验证方法帮助读者理解 CKEditor 4 从 RTF 剪贴板提取图片的底层机制并掌握如何手工验证该场景。一、问题背景粘贴含水平线的 Word 内容导致图片无法上传在 CKEditor 4 4.17.2 之前的版本中用户从 Microsoft Word 或 Outlook 复制一段水平线 图片的内容粘贴到编辑器时会遇到两类典型的异常表现图片没有被粘贴进编辑器水平线可能正常图片丢失浏览器控制台出现错误信息Error code: pastetools-failed-image-extraction. {rtf: 2, html: 1}。该缺陷的官方编号为 #4873在仓库的 CHANGES.md 的 4.17.2 版本记录中有明确描述Fixed: Pasting content from MS Word and Outlook with horizontal lines prevents images from being uploaded.修复从 MS Word 和 Outlook 粘贴带水平线的内容会阻止图片上传。这段图文内容之所以特殊在于 Word/Outlook 中的水平线在 RTF 剪贴板数据里以\pictpicture分组的形式出现内部含fHorizRule控制词导致编辑器在统计RTF 中的图片数量与HTML 中的img数量时产生不一致进而中断整段内容的图片提取。本文将逐步拆解这个过程。二、手动测试用例复现与验收标准仓库在 tests/plugins/pastefromword/manual/pasteimagewithhrline.md 中提供了一个标准的 Bender 手动测试用例用于验证 #4873 的修复效果。它的元数据与操作步骤是该场景最权威的复现说明。2.1 测试元数据bender-tags: 4.17.2, bug, 4873 bender-ui: collapsed bender-ckeditor-plugins:basicstyles, elementspath, horizontalrule, pastefromword, showborders, sourcearea, table, toolbar, wysiwygarea, autogrow, image, undo从中可以提取出该场景的依赖插件清单插件在该场景中的作用pastefromword核心插件负责识别并清理来自 Office 的粘贴内容image允许编辑器接收img标签并展示粘贴的图片horizontalrule与粘贴内容中的水平线元素对应wysiwygarea提供可视化编辑区域iframebasicstyles、elementspath、showborders、sourcearea、table、toolbar、autogrow、undo提供基础样式、路径栏、边框显示、源码视图、表格、工具栏、自动增高与撤销支持bender-ui: collapsed表示该用例以折叠面板形式展示测试数据文件存放在同目录的_assets子目录下。2.2 复现步骤原文档步骤打开浏览器控制台方便观察是否有报错。打开测试数据文件之一outlook1.msgOutlook 邮件格式或 image_with_hrline.docxWord 文档。全选并复制该文件中的全部内容ctrl/cmd c。将内容粘贴进编辑器。2.3 预期结果 vs 非预期结果预期结果修复后水平线和图片都被正确粘贴进编辑器控制台没有任何错误输出。非预期结果修复前图片未出现在编辑器中浏览器控制台出现错误Error code: pastetools-failed-image-extraction. {rtf: 2, html: 1}。其中{rtf: 2, html: 1}的含义是RTF 剪贴板数据中解析出了 2 张图片而 HTML 数据中只找到 1 个img标签——正是这种数量不匹配触发了失败。2.4 对应的 HTML 测试页与 Markdown 描述配套的 pasteimagewithhrline.html 实现了该用例的编辑器环境textarea nameeditor1/textarea script ( function() { if ( CKEDITOR.env.ie || bender.tools.env.mobile ) { bender.ignore(); } CKEDITOR.replace( editor1 ); } )(); /script值得注意该用例在 IE 及移动端环境下会被bender.ignore()跳过因为图片内嵌依赖现代浏览器的 Clipboard API见下文第 5 节。普通桌面浏览器Chrome / Firefox / Safari / Edge直接通过CKEDITOR.replace( editor1 )启动编辑器即可执行验证。三、根因分析RTF 图片提取的数量不匹配要理解水平线为什么会破坏图片粘贴需要进入 CKEditor 4 的粘贴处理链路。当内容被识别为来自 Office 时详见 pastefromword/plugin.js 中的canHandle判断编辑器会依次执行清理与图片内嵌逻辑其中图片处理由 plugins/pastetools/filter/image.js 中的CKEDITOR.pasteFilters.image完成。3.1 图片过滤器的主流程核心入口逻辑如下image.jsCKEDITOR.pasteFilters.image function( html, editor, rtf ) { var imgTags; // 如果编辑器不允许 img[src]直接跳过内嵌。 if ( editor.activeFilter !editor.activeFilter.check( img[src] ) ) { return html; } imgTags extractTagsFromHtml( html ); if ( imgTags.length 0 ) { return html; } if ( rtf ) { return handleRtfImages( html, rtf, imgTags ); } return handleBlobImages( editor, html, imgTags ); };extractTagsFromHtml从 HTML 中提取所有img的src属性值若剪贴板中存在text/rtf数据走handleRtfImagesRTF 提取路线否则走handleBlobImagesBlob URL 提取路线见第 6 节。3.2extractFromRtf从 RTF 中数出图片数量RTF 图片提取的核心是extractFromRtfimage.js其处理步骤为剔除干扰分组使用CKEDITOR.plugins.pastetools.filters.common.rtf.removeGroups删除\header*/\footer*页眉页脚、\nonshppict非 Word 图片以及\shprslt绘制对象例如图片对齐信息等分组。相关工具方法定义在 plugins/pastetools/filter/common.js。抓取\pict分组通过getGroups( rtfContent, pict )取得全部图片分组。逐组分析判断每个分组的类型isDuplicated同一\blipuid的图片重复出现Word 会为同一图片复用 idisAlternateFormat紧跟原图出现的另一格式副本isWordArtShape含\defshp控制词的 WordArt 形状isHorizontalLine图片内容中包含fHorizRule控制词isSupportedType类型属于image/png、image/jpeg、image/gif之一。3.3 #4873 的修复点跳过水平线图片分组水平线的元凶就在fHorizRule上。Word/Outlook 中的水平线在 RTF 里同样以\pict分组表达并携带fHorizRule控制词。修复前的代码会把水平线也计入RTF 中的图片导致RTF 中解析出 2 张图水平线 真实图片HTML 中只有 1 个img水平线对应的是hr标签不是img。两者数量不匹配后handleRtfImages就会抛出pastetools-failed-image-extraction并中止替换image.jsif ( imgTags.length ! newSrcValues.length ) { CKEDITOR.error( pastetools-failed-image-extraction, { rtf: hexImages.length, html: imgTags.length } ); return html; }这正是手动测试用例中{rtf: 2, html: 1}错误的来源。修复方式是在提取阶段直接跳过水平线分组image.jsvar isHorizontalLine CKEDITOR.tools.indexOf( currentImage, fHorizRule ) ! -1; // ... // Continue when the element is a hr line to allow paste image with horizontal line. (#4873) if ( isHorizontalLine ) { continue; }这样 RTF 中剩余的图片数量就与 HTML 中的img数量重新对齐真实图片得以继续被替换为内嵌数据。四、修复后的替换逻辑file:// 源替换为 Base64 数据 URL当数量匹配后handleRtfImagesimage.js会将每张图片的十六进制内容转换为 Base64 数据 URLnewSrcValues CKEDITOR.tools.array.map( hexImages, function( img ) { return createSrcWithBase64( img ); }, this );createSrcWithBase64image.js对受支持类型输出形如data:image/png;base64,xxxx的数据 URL对于不支持的格式如 EMF、WMF会返回null并在替换阶段抛出pastetools-unsupported-image错误替换仅针对file://开头的srcWord 粘贴产生的本地文件路径引用并使用new RegExp( (img [^]*src[\]?) escapedPath )精确匹配img标签避免误伤 VML 形状Windows 路径中的反斜杠会先被转义image.js。从源码注释与类型标记image.js可知RTF 图片类型通过控制词识别RTF 控制词识别出的 MIME 类型是否支持内嵌\pngblipimage/png是\jpegblipimage/jpeg是\emfblipimage/emf否触发pastetools-unsupported-image\wmetafile\dimage/wmf否五、easyimage 变体云端上传场景的验证除基础image插件外仓库还提供了 Easy Image云端图片上传场景的变体用例 pasteimagewithhrlineeasyimage.md其插件清单将image替换为easyimage并额外引入辅助脚本bender-include: ../_helpers/easyimage.js对应的 pasteimagewithhrlineeasyimage.html 在编辑器配置中注入了云服务上传网关与令牌地址来自 tests/plugins/pastefromword/_helpers/easyimage.jsvar config { cloudServices_uploadUrl: easyImage.CLOUD_SERVICES_UPLOAD_GATEWAY, cloudServices_tokenUrl: easyImage.CLOUD_SERVICES_TOKEN_URL }; CKEDITOR.replace( editor1, config );两个变体的操作步骤、预期/非预期结果与基础版完全一致用于确认水平线 图片的内容在 Easy Image 的云端上传链路上同样不再失败。由于 easyimage 对运行环境有额外要求HTML 中调用bender.tools.ignoreUnsupportedEnvironment( easyimage )在不受支持的环境下自动跳过。六、无 RTF 时的兜底路线Blob URL 转 Base64当剪贴板不提供text/rtf时图片过滤器走handleBlobImagesimage.js路线从img srcblob:...提取 Blob URL通过CKEDITOR.ajax.load( blobUrlSrc, ..., arraybuffer )异步读取二进制数据再依据文件头签名识别类型并转成 Base64image.js文件头十六进制签名识别出的类型ffd8ffimage/jpeg47494638image/gif89504e47image/png该路线的异步特性解释了为什么粘贴大图时浏览器可能短暂无图以及为什么粘贴后需要等 Promise 全部 resolve 才会刷新src属性。七、自动化测试佐证错误信息与数量不匹配仓库的自动化测试 tests/plugins/pastetools/filter/image.js 精确复现了手动用例中的错误场景可作为回归验证依据RTF 中图片多于 HTML时抛出pastetools-failed-image-extraction参数为{ rtf: 2, html: 1 }image.js#L71-L99与手动用例文档中的错误信息完全一致HTML 中图片多于 RTF时抛出{ rtf: 1, html: 2 }image.js#L101-L129前两类 RTF 结构普通\pict与带\shppict包装的\pict都能正确转换为data:image/png;base64,...image.js#L22-L39非file://源的图片如http://不会被转换EMF 等不支持格式会触发pastetools-unsupported-imageimage.js#L41-L69。这些用例通过sinon.spy( CKEDITOR, error )断言错误参数从代码层面印证了{rtf, html}计数机制正是本缺陷的诊断窗口。八、相关配置项与适用前提在 plugins/pastefromword/plugin.js 中与该场景直接相关的配置项包括config.pasteFromWord_inlineImages默认true自 4.8.0 起是否在粘贴 Word 内容时内嵌图片。设置为false可关闭图片内嵌但也会放弃该修复带来的能力plugin.js#L175-L187。开启内嵌的前提是CKEDITOR.plugins.clipboard.isCustomDataTypesSupported为真即需要支持 Clipboard API 的现代浏览器config.pasteFromWordCleanupFile默认plugin path filter/default.js自定义 Word 清理过滤器文件路径plugin.js#L155-L173config.pasteFromWordPromptCleanup默认false粘贴 Word 内容前是否弹出清理确认框plugin.js#L145-L153。默认过滤器链由 plugin.js#L26-L30 定义依次加载pastetools/filter/common.js、pastetools/filter/image.js与pastefromword/filter/default.js图片内嵌仅在图片过滤器已加载且编辑器允许img[src]时执行plugin.js#L110-L113。九、本地验证与回归建议若要在本地仓库中验证 #4873 的修复效果建议按以下方式操作使用 Bender 测试框架运行手动用例 pasteimagewithhrline.html项目根目录提供 bender.js 与 bender-runner.config.json 等配置文件准备测试数据 outlook1.msg 或 image_with_hrline.docx全选复制后在编辑器内粘贴观察两件事图片与水平线是否同时出现控制台是否出现pastetools-failed-image-extraction若需覆盖 Easy Image 场景改用 pasteimagewithhrlineeasyimage.html 重复上述步骤运行自动化测试 tests/plugins/pastetools/filter/image.js 确认数量不匹配与类型不支持的断言均通过。值得注意的是本修复依赖 4.17.2 及以上版本在更早版本中extractFromRtf尚不存在isHorizontalLine判断该判断带#4873注释因此同样的操作会稳定复现{rtf: 2, html: 1}报错。升级版本或确认补丁已合入是解决此类粘贴丢图问题的第一道关卡。赞分享前端UI组件【免费下载链接】ckeditor4The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.项目地址https://gitcode.com/gh_mirrors/ck/ckeditor4点击查看免费下载相关推荐CKEditor 4 禁用 ACF 后粘贴 Word 内容的行为剖析从 nofilter 手动测试看完整保真粘贴CKEditor 4 禁用 ACF 后粘贴 Word 内容的行为剖析从 nofilter 手动测试看完整保真粘贴 导读 CKEditor 4 默认启用内容过滤前端UI组件CKEditor 4 Safari 粘贴 Word 图片内嵌base64修复解析pasteimagessafari 手动测试与 pastefromword 图片处理链路CKEditor 4 Safari 粘贴 Word 图片内嵌base64修复解析pasteimagessafari 手动测试与 pastefromword前端UI组件CKEditor 4 粘贴内容类型回归测试指南从 PowerPoint / Excel 复制内容必须按 HTML 文本粘贴而非图片CKEditor 4 粘贴内容类型回归测试指南从 PowerPoint / Excel 复制内容必须按 HTML 文本粘贴而非图片 本文基于 CKEditor前端UI组件上一篇Spectre.css移动端设计模式触控优先的界面设计原则下一篇Kronos股票预测AI模型终极指南如何用深度学习技术实现千股批量预测创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表