ly_ueditor_plus zblog 编辑器粘贴换行丢失修复 |
| 发表者:admin分类:应用服务2026-09-01 10:36:24 阅读[0] |
ly_ueditor_plus 粘贴换行丢失修复总结报告
zblog-php版本使用 ly_ueditor_plus编辑器插件,复制的文章内容不支持自动换行解决方法。
针对「从网上复制文章/终端内容,粘贴进 UEditorPlus 编辑器后换行丢失、代码黏成一行」问题的完整分析、修复与验证记录。
一、问题现象
在 UEditorPlus(v2.0.0)编辑器里粘贴以下内容时,换行全部丢失,所有代码黏成一行:
- 从网页复制的代码块(
<pre>/<pre><code>/<span class="token …">高亮结构) - 从终端 / 纯文本文件复制的多行命令脚本(
#注释、\续行、空行)
典型表现:…libfastjson# (关键:…、/root/rpmbuild/RPMS/x86_64rpm -Uvh … 直接粘连。
二、根因分析(三层叠加,缺一不可)
粘贴管线(UE.plugins.paste)处理顺序为:
pastebin innerHTML → UE.filterWord → 换行转换(本次新增) → UE.htmlparser → filterInputRule → insertHtml根因 1:UE.filterWord 折叠全量换行
filterWord 内部 t() 函数第一行执行 .replace(/[\t\r\n]+/g," "),会把**整段 HTML(含 <pre> 内部)**的换行/制表符折叠成空格。
- 触发条件:内容匹配 Word 特征(
class="?Mso/mso-样式 /w:WordDocument/lang=等),带lang=属性的网页很常见; - 原代码无任何
<pre>保护,代码块换行被无差别压平。
根因 2:纯文本粘贴的 \n 无换行渲染
从终端/文本文件复制时,剪贴板只有 text/plain。Chrome 将多行内容作为单个含 \n 的文本节点插入编辑器,而正文 white-space: normal 会把文本节点里的 \n 渲染折叠成空格 → 视觉上一行。
根因 3:UE.htmlparser 剥除标签相邻换行(最终真凶)
网页代码块普遍是 <pre><code><span class="token …">行内容</span>\n…</code></pre> 结构,换行符其实都在。但 htmlparser 的空白清理正则
[\r\t\n ]*</?(\w+)…>[ \t\r\n]*会把 span/code/pre/br 等白名单标签两侧的 \n\r 全部剥掉(</span>\n<span>、</code>\n 等位置的换行被吞),且此清理发生在解析阶段,后续任何处理都无法找回。
三者关系:修复 1 只管 Word 样式内容;修复 2 覆盖纯文本;但即使前两者都通过,只要换行以
\n形式进入 htmlparser 且紧贴 span/code 标签,仍会被根因 3 剥除——这正是历次修复后线上仍失败的原因。
三、修复方案(ueditor-plus/ueditor.all.js 粘贴插件,共 4 处)
修复 A:filterWord 保护 <pre> 块
UE.filterWord 内部 t() 函数开头摘出所有 <pre>…</pre> 块(占位符 \u0000UEPRE{n}\u0000),完成 Word 清理链后再原样还原:
function t(t){var a=[];return t=t.replace(/<pre[\s\S]*?<\/pre>/gi,function(e){ return a.push(e),"\u0000UEPRE"+(a.length-1)+"\u0000"}), t.replace(/[\t\r\n]+/g," ") /* …原 Word 清理链… */ .replace(/\u0000UEPRE(\d+)\u0000/g,function(e,i){return a[i]});}修复 B:粘贴时读取剪贴板 text/plain 回退恢复
来源网页若连 \n 都不给(行间无换行符渲染),HTML 已无法自愈。修复在粘贴事件里读取 clipboardData.getData("text/plain")(纯文本永远带换行),当 <pre> 内换行数明显少于纯文本行数、且两者去空白后内容一致时,用纯文本按行重建 pre:
// 事件监听处i(e, t.clipboardData && t.clipboardData.getData ? t.clipboardData.getData("text/plain") : "")// i(e,p) 内:恢复逻辑(实体解码、空白不敏感匹配、$1/$& 替换符用函数回调防吞)修复 C:<pre> 内 \n 直接转为 <br/>(关键)
把换行转换中的 pre 处理从「占位保护再还原」改为直接替换,让 \n 根本不出现在 htmlparser 输入里,从而根除根因 3:
i = i.replace(/\r\n?/g,"\n") .replace(/<pre[\s\S]*?<\/pre>/gi, function(e){ return e.replace(/\n/g,"<br/>"); }) // pre 内 \n→<br/> .replace(/<[^>]*>/g, function(e){ return e.replace(/\n/g,"\u0002"); }) // 标签内换行安全清理 .replace(/([^<>\u0001\u0002])(\n+)(?=[^<>\u0001\u0002])/g, /*文本内换行→等量<br/>*/) .replace(/\n/g,"").replace(/\u0002/g,""); // 标签间残留清理<br/> 是 UEditor 代码块的天然换行格式(自带「插入代码」功能即以此存储),htmlparser 不再有 \n 可剥。
修复 D:纯文本(无 pre)换行 → <br/>
修复 C 中第三段正则同时覆盖普通文本节点:line1\nline2 → line1<br/>line2,空行 \n\n → 双 <br/>;段落间 </p>\n<p> 因 \n 紧贴标签而自动忽略,不产生多余 <br>。
四、验证结果
| 检查项 | 结果 |
|---|---|
node --check ueditor.all.js 语法 | ✅ 通过 |
真实场景:pre>code>span 逐行代码块(每行 </span>\n)→ 每行 <br/>,缩进 保留,span 结构保留 | ✅ |
| 来源网页无换行 + 纯文本回退 → 19 行全部恢复 | ✅ |
| 正常 pre(换行充足)→ 恢复逻辑跳过、不重复处理 | ✅ |
| pre 与纯文本不匹配 / 无 pre / 单行 → 原样不动 | ✅ |
代码含 $1 $& && → 不被替换符吞掉 | ✅ |
纯文本多行 → 逐行 <br/>,空行 → 双 <br/> | ✅ |
段落间 </p>\n<p> → 不产生多余 <br> | ✅ |
| Word 样式 + pre(修复 A)回归 | ✅ |
仿真方法:Node 环境加载真实 ueditor.all.js,从文件中抽取注入的转换/恢复表达式,全链路复刻 恢复 → filterWord → 换行转换 → htmlparser → filterInputRule → toHtml,断言最终 insertHtml 内容。测试脚本:test_paste_pipeline.js(工作区根目录,可随时重跑复验)。
五、部署与缓存
改动涉及两个文件,必须同时上传:
| 文件 | 改动 |
|---|---|
ueditor-plus/ueditor.all.js | 修复 A/B/C/D |
ly_ueditor_plus_core.php | 加载版本号 ?0309 → ?0313(破浏览器缓存) |
上传后 Ctrl+F5 强刷编辑页。若仍有异常,可用 paste_diagnose.html(上传到插件目录后浏览器打开)——它直接读取剪贴板 text/html 与 text/plain,并逐步复刻粘贴管线,红色步骤即换行丢失点。
六、文件变更清单
ueditor-plus/ueditor.all.js 粘贴插件修复(4处)+filterWord pre 保护ly_ueditor_plus_core.php 版本号 ?0309→?0313paste_diagnose.html 诊断页(捕获剪贴板双格式+管线分步)test_paste_pipeline.js Node 全链路仿真测试(13 用例)
转载请标明出处【ly_ueditor_plus zblog 编辑器粘贴换行丢失修复】。
《www.micoder.cc》
虚拟化云计算,系统运维,安全技术服务.
| Tags: | [阅读全文...] |
最新评论