/** * Word / WPS 粘贴富文本的归一化处理。 * * 直接插入 Word 复制出的 HTML 会出现「表格被截断」,原因有三: * ① 表格与单元格带绝对宽度(pt / px),宽度总和超过容器后被整体裁切; * ② 单元格带 `white-space: nowrap` 或 `nowrap` 属性,内容不换行而横向溢出; * ③ Word 私有 `mso-*` 样式与 `overflow: hidden` 把超出部分直接隐藏。 * * 本模块只解除这些「布局锁定」,表格结构(行列、合并、边框、加粗、对齐)全部保留, * 宽度改由各渲染端的 CSS 统一控制,避免同一份文书在不同容器里表现不一致。 * * 解除动作本身是 `unlockTableLayout`,粘贴近来要用,**渲染出去也要用**: * 编辑器序列化出来的表格自带 `style="width: auto"` 这类内联锁,只堵粘贴这一个口 * 挡不住它(详见该函数的注释)。 */ const COMMENTS = //g /** 成对出现的标签整体删除(含内容) */ const BLOCK_TAGS = /<(script|style|meta|link)\b[^>]*>[\s\S]*?<\/\1>/gi /** 自闭合标签:``、``、`` */ const VOID_TAGS = /<(script|meta|link)\b[^>]*\/?>/gi /** 会造成截断的样式声明:绝对宽度、固定布局与内容裁剪 */ const LAYOUT_LOCK_STYLES = new Set([ 'width', 'min-width', 'max-width', 'height', 'table-layout', 'white-space', 'overflow', 'overflow-x', 'overflow-y', ]) /** 与样式等价的 HTML 属性,Word 会同时输出两者 */ const LAYOUT_LOCK_ATTRIBUTES = ['width', 'height', 'nowrap'] function sanitizeStyleAttribute(style: string): string { return style .split(';') .map((declaration) => declaration.trim()) .filter(Boolean) .filter((declaration) => { const property = (declaration.split(':')[0] ?? '').trim().toLowerCase() if (!property || property.startsWith('mso-')) { return false } return !LAYOUT_LOCK_STYLES.has(property) }) .join('; ') } /** * 解除表格上的「布局锁定」:绝对宽度、固定行高、固定布局、不换行、内容裁剪。 * 宽度交回渲染端 CSS(`.doc-paper table { width: 100% }` 那一套)。 * * **两个边界都要做,少一个就会出现"编辑器里与渲染出来不一样"**: * * - **粘贴时**(本模块的 normalizePastedHtml):Word / WPS 的表格带 pt/px 绝对宽度、 * `nowrap` 与 `overflow: hidden`; * - **渲染时**(utils/signing-document 的 buildSigningDocumentHtml):WangEditor 的表格 * 序列化会把宽度写成**内联样式** —— 它导出的每张表都是 * `