@spacecorexdev/core 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/package.json +19 -3
  2. package/public/cmaps/78-EUC-H.bcmap +0 -0
  3. package/public/cmaps/78-EUC-V.bcmap +0 -0
  4. package/public/cmaps/78-H.bcmap +0 -0
  5. package/public/cmaps/78-RKSJ-H.bcmap +0 -0
  6. package/public/cmaps/78-RKSJ-V.bcmap +0 -0
  7. package/public/cmaps/78-V.bcmap +0 -0
  8. package/public/cmaps/78ms-RKSJ-H.bcmap +0 -0
  9. package/public/cmaps/78ms-RKSJ-V.bcmap +0 -0
  10. package/public/cmaps/83pv-RKSJ-H.bcmap +0 -0
  11. package/public/cmaps/90ms-RKSJ-H.bcmap +0 -0
  12. package/public/cmaps/90ms-RKSJ-V.bcmap +0 -0
  13. package/public/cmaps/90msp-RKSJ-H.bcmap +0 -0
  14. package/public/cmaps/90msp-RKSJ-V.bcmap +0 -0
  15. package/public/cmaps/90pv-RKSJ-H.bcmap +0 -0
  16. package/public/cmaps/90pv-RKSJ-V.bcmap +0 -0
  17. package/public/cmaps/Add-H.bcmap +0 -0
  18. package/public/cmaps/Add-RKSJ-H.bcmap +0 -0
  19. package/public/cmaps/Add-RKSJ-V.bcmap +0 -0
  20. package/public/cmaps/Add-V.bcmap +0 -0
  21. package/public/cmaps/Adobe-CNS1-0.bcmap +0 -0
  22. package/public/cmaps/Adobe-CNS1-1.bcmap +0 -0
  23. package/public/cmaps/Adobe-CNS1-2.bcmap +0 -0
  24. package/public/cmaps/Adobe-CNS1-3.bcmap +0 -0
  25. package/public/cmaps/Adobe-CNS1-4.bcmap +0 -0
  26. package/public/cmaps/Adobe-CNS1-5.bcmap +0 -0
  27. package/public/cmaps/Adobe-CNS1-6.bcmap +0 -0
  28. package/public/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  29. package/public/cmaps/Adobe-GB1-0.bcmap +0 -0
  30. package/public/cmaps/Adobe-GB1-1.bcmap +0 -0
  31. package/public/cmaps/Adobe-GB1-2.bcmap +0 -0
  32. package/public/cmaps/Adobe-GB1-3.bcmap +0 -0
  33. package/public/cmaps/Adobe-GB1-4.bcmap +0 -0
  34. package/public/cmaps/Adobe-GB1-5.bcmap +0 -0
  35. package/public/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  36. package/public/cmaps/Adobe-Japan1-0.bcmap +0 -0
  37. package/public/cmaps/Adobe-Japan1-1.bcmap +0 -0
  38. package/public/cmaps/Adobe-Japan1-2.bcmap +0 -0
  39. package/public/cmaps/Adobe-Japan1-3.bcmap +0 -0
  40. package/public/cmaps/Adobe-Japan1-4.bcmap +0 -0
  41. package/public/cmaps/Adobe-Japan1-5.bcmap +0 -0
  42. package/public/cmaps/Adobe-Japan1-6.bcmap +0 -0
  43. package/public/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  44. package/public/cmaps/Adobe-Korea1-0.bcmap +0 -0
  45. package/public/cmaps/Adobe-Korea1-1.bcmap +0 -0
  46. package/public/cmaps/Adobe-Korea1-2.bcmap +0 -0
  47. package/public/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  48. package/public/cmaps/B5-H.bcmap +0 -0
  49. package/public/cmaps/B5-V.bcmap +0 -0
  50. package/public/cmaps/B5pc-H.bcmap +0 -0
  51. package/public/cmaps/B5pc-V.bcmap +0 -0
  52. package/public/cmaps/CNS-EUC-H.bcmap +0 -0
  53. package/public/cmaps/CNS-EUC-V.bcmap +0 -0
  54. package/public/cmaps/CNS1-H.bcmap +0 -0
  55. package/public/cmaps/CNS1-V.bcmap +0 -0
  56. package/public/cmaps/CNS2-H.bcmap +0 -0
  57. package/public/cmaps/CNS2-V.bcmap +3 -0
  58. package/public/cmaps/ETHK-B5-H.bcmap +0 -0
  59. package/public/cmaps/ETHK-B5-V.bcmap +0 -0
  60. package/public/cmaps/ETen-B5-H.bcmap +0 -0
  61. package/public/cmaps/ETen-B5-V.bcmap +0 -0
  62. package/public/cmaps/ETenms-B5-H.bcmap +3 -0
  63. package/public/cmaps/ETenms-B5-V.bcmap +0 -0
  64. package/public/cmaps/EUC-H.bcmap +0 -0
  65. package/public/cmaps/EUC-V.bcmap +0 -0
  66. package/public/cmaps/Ext-H.bcmap +0 -0
  67. package/public/cmaps/Ext-RKSJ-H.bcmap +0 -0
  68. package/public/cmaps/Ext-RKSJ-V.bcmap +0 -0
  69. package/public/cmaps/Ext-V.bcmap +0 -0
  70. package/public/cmaps/GB-EUC-H.bcmap +0 -0
  71. package/public/cmaps/GB-EUC-V.bcmap +0 -0
  72. package/public/cmaps/GB-H.bcmap +4 -0
  73. package/public/cmaps/GB-V.bcmap +0 -0
  74. package/public/cmaps/GBK-EUC-H.bcmap +0 -0
  75. package/public/cmaps/GBK-EUC-V.bcmap +0 -0
  76. package/public/cmaps/GBK2K-H.bcmap +0 -0
  77. package/public/cmaps/GBK2K-V.bcmap +0 -0
  78. package/public/cmaps/GBKp-EUC-H.bcmap +0 -0
  79. package/public/cmaps/GBKp-EUC-V.bcmap +0 -0
  80. package/public/cmaps/GBT-EUC-H.bcmap +0 -0
  81. package/public/cmaps/GBT-EUC-V.bcmap +0 -0
  82. package/public/cmaps/GBT-H.bcmap +0 -0
  83. package/public/cmaps/GBT-V.bcmap +0 -0
  84. package/public/cmaps/GBTpc-EUC-H.bcmap +0 -0
  85. package/public/cmaps/GBTpc-EUC-V.bcmap +0 -0
  86. package/public/cmaps/GBpc-EUC-H.bcmap +0 -0
  87. package/public/cmaps/GBpc-EUC-V.bcmap +0 -0
  88. package/public/cmaps/H.bcmap +0 -0
  89. package/public/cmaps/HKdla-B5-H.bcmap +0 -0
  90. package/public/cmaps/HKdla-B5-V.bcmap +0 -0
  91. package/public/cmaps/HKdlb-B5-H.bcmap +0 -0
  92. package/public/cmaps/HKdlb-B5-V.bcmap +0 -0
  93. package/public/cmaps/HKgccs-B5-H.bcmap +0 -0
  94. package/public/cmaps/HKgccs-B5-V.bcmap +0 -0
  95. package/public/cmaps/HKm314-B5-H.bcmap +0 -0
  96. package/public/cmaps/HKm314-B5-V.bcmap +0 -0
  97. package/public/cmaps/HKm471-B5-H.bcmap +0 -0
  98. package/public/cmaps/HKm471-B5-V.bcmap +0 -0
  99. package/public/cmaps/HKscs-B5-H.bcmap +0 -0
  100. package/public/cmaps/HKscs-B5-V.bcmap +0 -0
  101. package/public/cmaps/Hankaku.bcmap +0 -0
  102. package/public/cmaps/Hiragana.bcmap +0 -0
  103. package/public/cmaps/KSC-EUC-H.bcmap +0 -0
  104. package/public/cmaps/KSC-EUC-V.bcmap +0 -0
  105. package/public/cmaps/KSC-H.bcmap +0 -0
  106. package/public/cmaps/KSC-Johab-H.bcmap +0 -0
  107. package/public/cmaps/KSC-Johab-V.bcmap +0 -0
  108. package/public/cmaps/KSC-V.bcmap +0 -0
  109. package/public/cmaps/KSCms-UHC-H.bcmap +0 -0
  110. package/public/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  111. package/public/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  112. package/public/cmaps/KSCms-UHC-V.bcmap +0 -0
  113. package/public/cmaps/KSCpc-EUC-H.bcmap +0 -0
  114. package/public/cmaps/KSCpc-EUC-V.bcmap +0 -0
  115. package/public/cmaps/Katakana.bcmap +0 -0
  116. package/public/cmaps/LICENSE +36 -0
  117. package/public/cmaps/NWP-H.bcmap +0 -0
  118. package/public/cmaps/NWP-V.bcmap +0 -0
  119. package/public/cmaps/RKSJ-H.bcmap +0 -0
  120. package/public/cmaps/RKSJ-V.bcmap +0 -0
  121. package/public/cmaps/Roman.bcmap +0 -0
  122. package/public/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  123. package/public/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  124. package/public/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  125. package/public/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  126. package/public/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  127. package/public/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  128. package/public/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  129. package/public/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  130. package/public/cmaps/UniGB-UCS2-H.bcmap +0 -0
  131. package/public/cmaps/UniGB-UCS2-V.bcmap +0 -0
  132. package/public/cmaps/UniGB-UTF16-H.bcmap +0 -0
  133. package/public/cmaps/UniGB-UTF16-V.bcmap +0 -0
  134. package/public/cmaps/UniGB-UTF32-H.bcmap +0 -0
  135. package/public/cmaps/UniGB-UTF32-V.bcmap +0 -0
  136. package/public/cmaps/UniGB-UTF8-H.bcmap +0 -0
  137. package/public/cmaps/UniGB-UTF8-V.bcmap +0 -0
  138. package/public/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  139. package/public/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  140. package/public/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  141. package/public/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  142. package/public/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  143. package/public/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  144. package/public/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  145. package/public/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  146. package/public/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  147. package/public/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  148. package/public/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  149. package/public/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  150. package/public/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  151. package/public/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  152. package/public/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  153. package/public/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  154. package/public/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  155. package/public/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  156. package/public/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  157. package/public/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  158. package/public/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  159. package/public/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  160. package/public/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  161. package/public/cmaps/UniKS-UCS2-H.bcmap +0 -0
  162. package/public/cmaps/UniKS-UCS2-V.bcmap +0 -0
  163. package/public/cmaps/UniKS-UTF16-H.bcmap +0 -0
  164. package/public/cmaps/UniKS-UTF16-V.bcmap +0 -0
  165. package/public/cmaps/UniKS-UTF32-H.bcmap +0 -0
  166. package/public/cmaps/UniKS-UTF32-V.bcmap +0 -0
  167. package/public/cmaps/UniKS-UTF8-H.bcmap +0 -0
  168. package/public/cmaps/UniKS-UTF8-V.bcmap +0 -0
  169. package/public/cmaps/V.bcmap +0 -0
  170. package/public/cmaps/WP-Symbol.bcmap +0 -0
  171. package/public/polyfills/polyfills.js +802 -0
  172. package/public/vendor/docx/docx.worker.js +5 -0
  173. package/public/vendor/docx/jszip.min.js +13 -0
  174. package/public/vendor/libarchive/libarchive.wasm +0 -0
  175. package/public/vendor/libarchive/worker-bundle.js +6 -0
  176. package/public/vendor/pptx/pptx.worker.js +26 -0
  177. package/public/wasm/cad/0.8.2/dwfv-render.wasm +0 -0
  178. package/public/wasm/cad/0.8.2/dwg-worker.js +24 -0
  179. package/public/wasm/cad/0.8.2/dwg-worker.js.map +1 -0
  180. package/public/wasm/cad/0.8.2/libredwg-web.js +2 -0
  181. package/public/wasm/cad/0.8.2/libredwg-web.wasm +0 -0
  182. package/public/wasm/cad/dwfv-render.wasm +0 -0
  183. package/public/wasm/cad/dwg-worker.js +24 -0
  184. package/public/wasm/cad/dwg-worker.js.map +1 -0
  185. package/public/wasm/cad/libredwg-web.js +2 -0
  186. package/public/wasm/cad/libredwg-web.wasm +0 -0
  187. package/public/wasm/data/sql-wasm.wasm +0 -0
  188. package/public/wasm/hdiff.wasm +0 -0
  189. package/public/wasm/model/LICENSE.occt-import-js.txt +504 -0
  190. package/public/wasm/model/LICENSE.occt.txt +502 -0
  191. package/public/wasm/model/occt-import-js.js +19 -0
  192. package/public/wasm/model/occt-import-js.wasm +0 -0
  193. package/public/wasm/model/occt-worker.js +83 -0
  194. package/public/wasm/typst/fonts/DejaVuSansMono-Bold.ttf +0 -0
  195. package/public/wasm/typst/fonts/DejaVuSansMono-BoldOblique.ttf +0 -0
  196. package/public/wasm/typst/fonts/DejaVuSansMono-Oblique.ttf +0 -0
  197. package/public/wasm/typst/fonts/DejaVuSansMono.ttf +0 -0
  198. package/public/wasm/typst/fonts/LibertinusSerif-Bold.otf +0 -0
  199. package/public/wasm/typst/fonts/LibertinusSerif-BoldItalic.otf +0 -0
  200. package/public/wasm/typst/fonts/LibertinusSerif-Italic.otf +0 -0
  201. package/public/wasm/typst/fonts/LibertinusSerif-Regular.otf +0 -0
  202. package/public/wasm/typst/fonts/LibertinusSerif-Semibold.otf +0 -0
  203. package/public/wasm/typst/fonts/LibertinusSerif-SemiboldItalic.otf +0 -0
  204. package/public/wasm/typst/fonts/NewCM10-Bold.otf +0 -0
  205. package/public/wasm/typst/fonts/NewCM10-BoldItalic.otf +0 -0
  206. package/public/wasm/typst/fonts/NewCM10-Italic.otf +0 -0
  207. package/public/wasm/typst/fonts/NewCM10-Regular.otf +0 -0
  208. package/public/wasm/typst/fonts/NewCMMath-Bold.otf +0 -0
  209. package/public/wasm/typst/fonts/NewCMMath-Book.otf +0 -0
  210. package/public/wasm/typst/fonts/NewCMMath-Regular.otf +0 -0
  211. package/public/wasm/typst/fonts/README.md +7 -0
  212. package/public/wasm/typst/typst_ts_renderer_bg.wasm +0 -0
  213. package/public/wasm/typst/typst_ts_web_compiler_bg.wasm +0 -0
  214. package/scripts/patch-docx-grid.cjs +412 -0
@@ -0,0 +1,412 @@
1
+ /**
2
+ * Patch @file-viewer/docx renderer: fix document grid (docGrid) line-height.
3
+ *
4
+ * Bug: when a section declares <w:docGrid w:type="lines" w:linePitch="N"/> and a
5
+ * paragraph has no explicit line-height, applyDocumentGridLinePitch() only sets
6
+ * min-height (no effect on inline text stacking) and never sets line-height, so
7
+ * paragraphs ignore the Word document grid entirely.
8
+ *
9
+ * Fix (Word/WPS "snap to grid" semantics):
10
+ * Each text line occupies an integer number of grid units:
11
+ * units = ceil(fontNaturalHeight / linePitch)
12
+ * line-height = units * linePitch
13
+ * Word font line metrics (winAscent + winDescent) for the legacy CJK fonts
14
+ * (宋体/SimSun, 新宋体/NSimSun, 仿宋/FangSong, 楷体/KaiTi, 黑体/SimHei, …)
15
+ * equal 1.32em, so 12pt text has a natural height of 15.84pt and snaps to
16
+ * 2 grid units when linePitch is 15.6pt (linePitch=312 twips); other fonts
17
+ * use a 1.2em fallback factor.
18
+ *
19
+ * Affected files (different build paths load different bundles):
20
+ * - dist/docx-preview.js (CJS, "main" / "require")
21
+ * - dist/docx-preview.mjs (ESM, "module" / "import" — used by esbuild/vite)
22
+ * - dist/docx-preview.worker.js (worker 产物,vite-plugin 会复制覆盖 public worker)
23
+ * - public/vendor/docx/docx.worker.js (standalone worker deployment)
24
+ *
25
+ * 除 docGrid 行距外,本脚本还包含制表位页码、分页容量边界、页眉页脚锚定等补丁。
26
+ */
27
+
28
+ const fs = require('fs');
29
+ const path = require('path');
30
+
31
+ const PKG_DIR = path.join(__dirname, '..', 'node_modules', '@file-viewer', 'docx');
32
+ const WORKER_PATH = path.join(__dirname, '..', 'public', 'vendor', 'docx', 'docx.worker.js');
33
+
34
+ // Original (buggy) function as shipped in @file-viewer/docx 0.3.33
35
+ const ORIGINAL =
36
+ 'applyDocumentGridLinePitch(e,t,r){if(!this.paragraphUsesDocumentGrid(e,t))return;' +
37
+ 'const a=this.currentSectionProps.docGrid.linePitch,' +
38
+ 'n=this.effectiveParagraphCssValue(e,t,"line-height"),' +
39
+ 's=e.lineSpacing??t?.paragraphProps?.lineSpacing;' +
40
+ 'if(n){if("exact"==s?.lineRule||"exactly"==s?.lineRule)return;' +
41
+ 'const o=/^-?\\d+(?:\\.\\d+)?$/.test(n)?`calc(${n} * 1em)`:n;' +
42
+ 'return this.setCssStyle(r,"line-height",`max(${o}, ${a})`),' +
43
+ 'void this.applyDocumentGridMinimumHeight(e,t,r,a)}' +
44
+ 'this.applyDocumentGridMinimumHeight(e,t,r,a)}';
45
+
46
+ // Earlier intermediate patch (1 grid unit, unconditional) — also accepted so
47
+ // installs made with the previous postinstall version upgrade cleanly.
48
+ const LEGACY_ONE_GRID_TAIL =
49
+ '}this.setCssStyle(r,"line-height",a),this.applyDocumentGridMinimumHeight(e,t,r,a)}';
50
+
51
+ // Patched implementation: integer grid units based on natural font height.
52
+ const PATCHED =
53
+ 'documentGridLineHeight(e,t,r,a){' +
54
+ 'const pitch=parseFloat(a);let fs=0,fam="";' +
55
+ 'const note=el=>{if(!el.style)return;const v=el.style.fontSize;' +
56
+ 'if(v){const m=/^([\\d.]+)pt$/.exec(v);m&&(fs=Math.max(fs,parseFloat(m[1])))}' +
57
+ 'const f=el.style.fontFamily;f&&(fam+=" "+f)};' +
58
+ 'note(r);if(r.querySelectorAll)r.querySelectorAll("[style]").forEach(note);' +
59
+ 'if(!fs){const ps=this.effectiveParagraphCssValue(e,t,"font-size");' +
60
+ 'if(ps){const m=/^([\\d.]+)pt$/.exec(ps);m&&(fs=parseFloat(m[1]))}}' +
61
+ 'fs||(fs=12);' +
62
+ 'const cjk=/simsun|nsimsun|fangsong|kaiti|simhei|microsoft yahei|dengxian|' +
63
+ '宋体|新宋|仿宋|楷体|黑体|雅黑|等线|mingliu|pmingliu|microsoft jhenghei/i.test(fam);' +
64
+ 'const units=Math.max(1,Math.ceil(fs*(cjk?1.32:1.2)/pitch-1e-6));' +
65
+ 'return(units*pitch).toFixed(2)+"pt"}' +
66
+ 'applyDocumentGridLinePitch(e,t,r){if(!this.paragraphUsesDocumentGrid(e,t))return;' +
67
+ 'const a=this.currentSectionProps.docGrid.linePitch,' +
68
+ 'l=this.documentGridLineHeight(e,t,r,a),' +
69
+ 'n=this.effectiveParagraphCssValue(e,t,"line-height"),' +
70
+ 's=e.lineSpacing??t?.paragraphProps?.lineSpacing;' +
71
+ 'if(n){if("exact"==s?.lineRule||"exactly"==s?.lineRule)return;' +
72
+ 'const o=/^-?\\d+(?:\\.\\d+)?$/.test(n)?`calc(${n} * 1em)`:n;' +
73
+ 'return this.setCssStyle(r,"line-height",`max(${o}, ${l})`),' +
74
+ 'void this.applyDocumentGridMinimumHeight(e,t,r,l)}' +
75
+ 'this.setCssStyle(r,"line-height",l),this.applyDocumentGridMinimumHeight(e,t,r,l)}';
76
+
77
+ // ---------------------------------------------------------------------------
78
+ // 补丁 2:制表位(tab stop)布局被 experimental 开关关闭
79
+ //
80
+ // 现象:页脚中「居中制表位 + Tab + PAGE 域」生成的页码,在编辑器/WPS 中跳到
81
+ // 页心居中,导出 PDF 时却停在左边距处(renderTab 只渲染固定 14px 的 span)。
82
+ // 根因:制表位宽度计算 updateTabStop 已实现,但收集与刷新两处都被
83
+ // this.options.experimental(默认 false)门控,从未执行。
84
+ // 方案:去掉两处门控;刷新时除原有 500ms 延迟刷新外,立即同步刷新一次,
85
+ // 使制表位宽度在动态分页开始前确定(避免分页稳定后正文再回流)。
86
+ // ---------------------------------------------------------------------------
87
+ const TAB_COLLECT_ORIGINAL =
88
+ 'this.options.experimental&&this.currentTabs.push({stops:r,span:i})';
89
+ const TAB_COLLECT_PATCHED =
90
+ 'this.currentTabs.push({stops:r,span:i})';
91
+
92
+ const TAB_REFRESH_ORIGINAL =
93
+ 'refreshTabStops(){this.options.experimental&&setTimeout(()=>{' +
94
+ 'const e=(0,o.computePixelToPoint)();for(let t of this.currentTabs)' +
95
+ '(0,o.updateTabStop)(t.span,t.stops,this.defaultTabSize,e)},500)}';
96
+ // 上一版补丁(仅立即+500ms 刷新)——存在缺陷:动态分页在渲染结束后才执行,
97
+ // 分页会搬移/克隆节点(含页脚),中途量出的几何失真会把制表位宽度算成 0pt。
98
+ // 保留它以便已打旧补丁的环境可以升级到新版。
99
+ const TAB_REFRESH_PATCHED_V1 =
100
+ 'refreshTabStops(){' +
101
+ 'const run=()=>{let e=.75;try{e=(0,o.computePixelToPoint)()}catch(t){}' +
102
+ 'for(let t of this.currentTabs)try{(0,o.updateTabStop)(t.span,t.stops,this.defaultTabSize,e)}catch(t){}};' +
103
+ 'run();setTimeout(run,500)}';
104
+
105
+ const TAB_REFRESH_PATCHED =
106
+ 'refreshTabStops(){' +
107
+ // 制表位布局:立即执行一次(分页前),并保留延迟刷新兜底(晚到字体等)
108
+ 'const run=()=>{let e=.75;try{e=(0,o.computePixelToPoint)()}catch(t){}' +
109
+ 'for(let t of this.currentTabs)try{(0,o.updateTabStop)(t.span,t.stops,this.defaultTabSize,e)}catch(t){}};' +
110
+ 'run();setTimeout(run,500);' +
111
+ // 动态分页在渲染结束后异步执行且会搬移/克隆节点,必须等分页稳定后再刷新,
112
+ // 否则中途失真几何会把制表位宽度算错(如页码居中被算成 0pt)
113
+ 'let n=0,readyHits=0;' +
114
+ 'const iv=setInterval(()=>{n++;let ready=1;' +
115
+ 'for(const t of this.currentTabs){const w=t.span.closest&&t.span.closest(".docx-wrapper");' +
116
+ 'if(w&&(w.dataset.docxPaginated!=="true"||w.dataset.docxPaginating||w.dataset.docxPaginationScheduled)){ready=0;break}}' +
117
+ 'if(ready){run();if(++readyHits>=2){clearInterval(iv);return}}else readyHits=0;' +
118
+ 'if(n>150)clearInterval(iv)},200)}';
119
+
120
+ // ---------------------------------------------------------------------------
121
+ // 补丁 3:分页溢出判定把页脚区算进正文容量,导致每页多排约一行
122
+ //
123
+ // 现象:isPageOverflowing 以纸张底边 r.bottom 为界,并把 header/footer 的
124
+ // bottom 也计入最大内容高度;页脚用负 margin 从普通流拉入页边区后,正文
125
+ // 实际可排到页脚位置(比正文 padding 底边多约 68px≈1.6 行)。
126
+ // 方案:分页(breakPages,即 visualPagination)时只统计 article 内节点,
127
+ // 容量边界改为正文 padding 底边(r.bottom - paddingBottom)。
128
+ // ---------------------------------------------------------------------------
129
+ const OVERFLOW_ORIGINAL =
130
+ 'isPageOverflowing(e){const t=this.options.paginationTolerance??2;if(e.clientHeight<=0)return!1;' +
131
+ 'const r=e.getBoundingClientRect();let a=r.top;' +
132
+ 'for(const t of Array.from(e.children)){const e=t.getBoundingClientRect();' +
133
+ 'if(a=Math.max(a,e.bottom),"article"==t.tagName.toLowerCase())' +
134
+ 'for(const e of Array.from(t.children)){const t=e.getBoundingClientRect();a=Math.max(a,t.bottom)}}' +
135
+ 'return a>r.bottom+t}';
136
+ const OVERFLOW_PATCHED =
137
+ 'isPageOverflowing(e){const t=this.options.paginationTolerance??2;if(e.clientHeight<=0)return!1;' +
138
+ 'const r=e.getBoundingClientRect();let a=r.top;' +
139
+ // 分页模式下页眉/页脚绝对定位于页边区,不占正文容量;以正文 padding 底边为界
140
+ 'const pb=this.options.breakPages?parseFloat(getComputedStyle(e).paddingBottom)||0:0;' +
141
+ 'const b=r.bottom-pb;' +
142
+ 'for(const n of Array.from(e.children))if("article"==n.tagName.toLowerCase())' +
143
+ 'for(const ch of Array.from(n.children)){const bx=ch.getBoundingClientRect();a=Math.max(a,bx.bottom)}' +
144
+ 'return a>b+t}';
145
+
146
+ // ---------------------------------------------------------------------------
147
+ // 补丁 4:固定分页模式下页眉/页脚改为相对纸张绝对定位
148
+ //
149
+ // 现象:页脚连续流写法(marginBottom 负值 + minHeight)在固定高度分页中
150
+ // 垂直位置偏低约 21pt(导出 PDF 页码距纸底约 30pt,编辑器/WPS 约 57pt;
151
+ // Word 语义下页脚底边距纸底 = footerDistance)。
152
+ // 方案:breakPages(visualPagination)时,header 以 top=headerDistance、
153
+ // footer 以 bottom=footerDistance、左右以左右页边距绝对锚定到纸张;
154
+ // 连续预览(breakPages=false)保持原有流式写法不变。
155
+ // ---------------------------------------------------------------------------
156
+ const HEADER_FOOTER_ORIGINAL =
157
+ 't?.pageMargins&&(c.rootElement.type===n.DomType.Header?' +
158
+ '(e.style.marginTop=`calc(${t.pageMargins.header} - ${t.pageMargins.top})`,' +
159
+ 'e.style.minHeight=`calc(${t.pageMargins.top} - ${t.pageMargins.header})`):' +
160
+ 'c.rootElement.type===n.DomType.Footer&&' +
161
+ '(e.style.marginBottom=`calc(${t.pageMargins.footer} - ${t.pageMargins.bottom})`,' +
162
+ 'e.style.minHeight=`calc(${t.pageMargins.bottom} - ${t.pageMargins.footer})`))';
163
+ const HEADER_FOOTER_PATCHED =
164
+ 't?.pageMargins&&(this.options.breakPages?' +
165
+ // 固定分页:页眉/页脚按 Word 边距绝对锚定到纸张(section.docx 为定位包含块)
166
+ '(c.rootElement.type===n.DomType.Header?' +
167
+ '(e.style.position="absolute",e.style.left=t.pageMargins.left,e.style.right=t.pageMargins.right,' +
168
+ 'e.style.top=t.pageMargins.header):' +
169
+ 'c.rootElement.type===n.DomType.Footer&&' +
170
+ '(e.style.position="absolute",e.style.left=t.pageMargins.left,e.style.right=t.pageMargins.right,' +
171
+ 'e.style.bottom=t.pageMargins.footer)):' +
172
+ // 连续预览:保持原有负 margin 流式写法
173
+ '(c.rootElement.type===n.DomType.Header?' +
174
+ '(e.style.marginTop=`calc(${t.pageMargins.header} - ${t.pageMargins.top})`,' +
175
+ 'e.style.minHeight=`calc(${t.pageMargins.top} - ${t.pageMargins.header})`):' +
176
+ 'c.rootElement.type===n.DomType.Footer&&' +
177
+ '(e.style.marginBottom=`calc(${t.pageMargins.footer} - ${t.pageMargins.bottom})`,' +
178
+ 'e.style.minHeight=`calc(${t.pageMargins.bottom} - ${t.pageMargins.footer})`)))';
179
+
180
+ // ---------------------------------------------------------------------------
181
+ // 补丁 5:updateTabStop 居中/右对齐制表位公式不自洽(非幂等)
182
+ //
183
+ // 现象:首次计算正确(页码居中),但重复执行时把 tab span 自身的当前宽度
184
+ // 也算进了 o(内容偏移),导致第二次执行算出负数→被 clamp 到 0pt。
185
+ // 根因:o = range.left + n*range.width - paragraphLeft,其中 range.left
186
+ // 包含了 tab span 的当前宽度 d.width。正确做法是减去 d.width,使 o 只反映
187
+ // 内容本身的位置,与 tab span 当前宽度无关。
188
+ // 方案:o 计算中减去 d.width,使公式幂等。
189
+ // 注意:worker bundle 与 CJS/MJS bundle 的 minified 变量名不同
190
+ // worker: T = paragraph content left
191
+ // CJS/MJS: w = paragraph content left
192
+ // 两者的 span rect 变量都是 d。
193
+ // ---------------------------------------------------------------------------
194
+ const TAB_FORMULA_ORIGINAL_WORKER =
195
+ 'o=s.left+n*s.width-T;C=S.pos-o*l';
196
+ const TAB_FORMULA_PATCHED_WORKER =
197
+ 'o=s.left+n*s.width-T-d.width;C=S.pos-o*l';
198
+ const TAB_FORMULA_ORIGINAL_CJS =
199
+ 'o=s.left+n*s.width-w;C=S.pos-o*l';
200
+ const TAB_FORMULA_PATCHED_CJS =
201
+ 'o=s.left+n*s.width-w-d.width;C=S.pos-o*l';
202
+
203
+ // ---------------------------------------------------------------------------
204
+ // 补丁 6:浮动对象(<wp:anchor wrapNone/>)水平/垂直 align 未转成 CSS 定位
205
+ //
206
+ // 现象:真实合同页码放在浮动文本框里:
207
+ // <wp:positionH relativeFrom="margin"><wp:align>center</wp:align></wp:positionH>
208
+ // worker 解析了 align(anchorPosition.horizontal.align,M=true),但 wrapNone
209
+ // 绝对定位分支只在存在 posOffset 时设置 left/top,align 被完全忽略,文本框
210
+ // 以默认 left:0 贴在左侧(页码无法居中;right/bottom/center 同样失效)。
211
+ // 方案:当 XML 提供的是 align 而非 posOffset 时(M/N=true),映射为 CSS:
212
+ // horizontal: center -> left:50% + translateX(-50%);right -> right:0;left -> left:0
213
+ // vertical: center -> top:50% + translateY(-50%);bottom -> bottom:0;top -> top:0
214
+ // 绝对定位包含块为锚定段落(position:relative),其宽度即正文/页脚的 margin
215
+ // 内容区宽度,左右页边距对称时其 50% 点就是纸张水平中心,与 Word 语义一致。
216
+ // posOffset 路径(M/N=false)保持原逻辑不变。
217
+ // ---------------------------------------------------------------------------
218
+ const FLOAT_ALIGN_ORIGINAL =
219
+ '"wrapNone"==x?(f.cssStyle.display="block",f.cssStyle.position=g?"absolute":"relative",' +
220
+ 'C.offset&&(f.cssStyle.left=C.offset),A.offset&&(f.cssStyle.top=A.offset))';
221
+ const FLOAT_ALIGN_PATCHED =
222
+ '"wrapNone"==x?(f.cssStyle.display="block",f.cssStyle.position=g?"absolute":"relative",' +
223
+ 'M?("center"==C.align?(f.cssStyle.left="50%",f.cssStyle.transform="translateX(-50%)"):' +
224
+ '"right"==C.align?f.cssStyle.right="0":' +
225
+ '"left"==C.align&&(f.cssStyle.left="0")):C.offset&&(f.cssStyle.left=C.offset),' +
226
+ 'N?("center"==A.align?(f.cssStyle.top="50%",' +
227
+ 'f.cssStyle.transform=(f.cssStyle.transform?f.cssStyle.transform+" ":"")+"translateY(-50%)"):' +
228
+ '"bottom"==A.align?f.cssStyle.bottom="0":' +
229
+ '"top"==A.align&&(f.cssStyle.top="0")):A.offset&&(f.cssStyle.top=A.offset))';
230
+
231
+ // ---------------------------------------------------------------------------
232
+ // 补丁 7:文本框 spAutoFit(形状随文字收缩)未实现,导致页脚浮动文本框里的
233
+ // 页码不能随 align=center 居中
234
+ //
235
+ // 真实合同页脚:浮动文本框 <wp:extent 144pt> + <wps:bodyPr><a:spAutoFit/></wps:bodyPr>
236
+ // (VML 兜底 mso-fit-shape-to-text:t)。Word/WPS 打开时文本框会收缩到与文字
237
+ // 等宽,再按 positionH align=center 居中;渲染器无视 spAutoFit,始终用 extent
238
+ // 的 144pt 固定宽,框虽居中,左对齐的页码停在框左缘(整体偏左约 70pt)。
239
+ // 三处修改:
240
+ // 7a parseDmlTextBoxProperties:解析 spAutoFit 标志到 dmlShapeAutoFit;
241
+ // 7b parseWordprocessingShape:文本框形状自适应时宽高改 auto(收缩到内容);
242
+ // 7c parseDrawingWrapper:外层锚定框内含自适应文本框时宽高也改 auto,
243
+ // 使绝对定位 shrink-to-fit,配合补丁 6 的 left:50% 实现真正居中。
244
+ // ---------------------------------------------------------------------------
245
+ const AUTOFIT_FLAG_ORIGINAL =
246
+ 'parseDmlTextBoxProperties(e){const t={};return this.applyDmlTextInsets(e,t),' +
247
+ '{dmlTextBox:!0,textInsets:t,textVerticalAlign:this.dmlVerticalAlign(e)}}';
248
+ const AUTOFIT_FLAG_PATCHED =
249
+ 'parseDmlTextBoxProperties(e){const t={};return this.applyDmlTextInsets(e,t),' +
250
+ '{dmlTextBox:!0,textInsets:t,textVerticalAlign:this.dmlVerticalAlign(e),' +
251
+ 'dmlShapeAutoFit:!!i.default.element(e,"spAutoFit")}}';
252
+
253
+ const SHAPE_AUTOSIZE_ORIGINAL =
254
+ 'return s&&(t.props={...t.props??{},...this.parseDmlTextBoxProperties(a)}),t}';
255
+ const SHAPE_AUTOSIZE_PATCHED =
256
+ 'if(s){const tp=this.parseDmlTextBoxProperties(a);t.props={...t.props??{},...tp};' +
257
+ 'tp.dmlShapeAutoFit&&(t.cssStyle.width="auto",t.cssStyle.height="auto")}return t}';
258
+
259
+ const WRAPPER_AUTOSIZE_ORIGINAL = 'f.cssStyle.float=C.align,f}';
260
+ const WRAPPER_AUTOSIZE_PATCHED =
261
+ 'f.cssStyle.float=C.align,' +
262
+ '(f.children?.some?.(ch=>ch?.props?.dmlShapeAutoFit))&&' +
263
+ '(f.cssStyle.width="auto",f.cssStyle.height="auto"),f}';
264
+
265
+ // 追加的 1:1 字符串替换补丁(每个补丁在单文件中必须且只能出现一次)
266
+ const EXTRA_PATCHES = [
267
+ {
268
+ id: 'tab-collect',
269
+ original: TAB_COLLECT_ORIGINAL,
270
+ patched: TAB_COLLECT_PATCHED,
271
+ },
272
+ {
273
+ id: 'tab-refresh',
274
+ original: TAB_REFRESH_ORIGINAL,
275
+ patched: TAB_REFRESH_PATCHED,
276
+ // 兼容已打旧版补丁的环境:同样替换为新版
277
+ legacy: [TAB_REFRESH_PATCHED_V1],
278
+ },
279
+ {
280
+ id: 'overflow-body-bound',
281
+ original: OVERFLOW_ORIGINAL,
282
+ patched: OVERFLOW_PATCHED,
283
+ },
284
+ {
285
+ id: 'header-footer-anchor',
286
+ original: HEADER_FOOTER_ORIGINAL,
287
+ patched: HEADER_FOOTER_PATCHED,
288
+ },
289
+ {
290
+ id: 'float-align',
291
+ original: FLOAT_ALIGN_ORIGINAL,
292
+ patched: FLOAT_ALIGN_PATCHED,
293
+ },
294
+ {
295
+ id: 'autofit-flag',
296
+ original: AUTOFIT_FLAG_ORIGINAL,
297
+ patched: AUTOFIT_FLAG_PATCHED,
298
+ },
299
+ {
300
+ id: 'shape-autosize',
301
+ original: SHAPE_AUTOSIZE_ORIGINAL,
302
+ patched: SHAPE_AUTOSIZE_PATCHED,
303
+ },
304
+ {
305
+ id: 'wrapper-autosize',
306
+ original: WRAPPER_AUTOSIZE_ORIGINAL,
307
+ patched: WRAPPER_AUTOSIZE_PATCHED,
308
+ },
309
+ ];
310
+
311
+ // 补丁 5 需要按文件变体选择不同锚点
312
+ const TAB_FORMULA_VARIANTS = {
313
+ 'docx.worker.js': { original: TAB_FORMULA_ORIGINAL_WORKER, patched: TAB_FORMULA_PATCHED_WORKER },
314
+ 'docx-preview.js': { original: TAB_FORMULA_ORIGINAL_CJS, patched: TAB_FORMULA_PATCHED_CJS },
315
+ 'docx-preview.mjs': { original: TAB_FORMULA_ORIGINAL_CJS, patched: TAB_FORMULA_PATCHED_CJS },
316
+ // 包内 worker 产物:@file-viewer/vite-plugin 每次 dev/build 会把它复制覆盖
317
+ // public/vendor/docx/docx.worker.js,必须一并补丁,否则重启后修复被冲掉
318
+ 'docx-preview.worker.js': { original: TAB_FORMULA_ORIGINAL_CJS, patched: TAB_FORMULA_PATCHED_CJS },
319
+ };
320
+
321
+ const targets = [
322
+ path.join(PKG_DIR, 'dist', 'docx-preview.js'),
323
+ path.join(PKG_DIR, 'dist', 'docx-preview.mjs'),
324
+ path.join(PKG_DIR, 'dist', 'docx-preview.worker.js'),
325
+ WORKER_PATH,
326
+ ];
327
+
328
+ let ok = 0;
329
+ for (const file of targets) {
330
+ if (!fs.existsSync(file)) {
331
+ console.warn(`[patch-docx-grid] SKIP (not found): ${file}`);
332
+ continue;
333
+ }
334
+ let content = fs.readFileSync(file, 'utf8');
335
+ const base = path.basename(file);
336
+
337
+ // 追加补丁(在 docGrid 补丁判断之前执行;各补丁自带幂等检测)
338
+ for (const patch of EXTRA_PATCHES) {
339
+ // 注意:patched 可能是 original 的子串,必须同时确认 original 已不存在才算已补丁
340
+ if (content.includes(patch.patched) && !content.includes(patch.original)) {
341
+ console.log(`[patch-docx-grid] ${base}: ${patch.id} ALREADY PATCHED`);
342
+ continue;
343
+ }
344
+ // 兼容旧版补丁:如果当前文件已被 legacy 版本打过,直接替换为新版
345
+ let replaced = false;
346
+ for (const legacy of (patch.legacy || [])) {
347
+ if (content.includes(legacy)) {
348
+ content = content.replace(legacy, patch.patched);
349
+ console.log(`[patch-docx-grid] ${base}: ${patch.id} UPGRADED (legacy -> new)`);
350
+ replaced = true;
351
+ break;
352
+ }
353
+ }
354
+ if (replaced) continue;
355
+ const count = content.split(patch.original).length - 1;
356
+ if (count !== 1) {
357
+ console.error(`[patch-docx-grid] ERROR: ${patch.id} expected 1 anchor in ${base}, found ${count}`);
358
+ process.exitCode = 1;
359
+ continue;
360
+ }
361
+ content = content.replace(patch.original, patch.patched);
362
+ console.log(`[patch-docx-grid] ${base}: ${patch.id} PATCHED`);
363
+ }
364
+
365
+ // 补丁 5:制表位公式幂等修复(按文件名选择变量名变体)
366
+ const tabFormula = TAB_FORMULA_VARIANTS[base];
367
+ if (tabFormula) {
368
+ if (content.includes(tabFormula.patched) && !content.includes(tabFormula.original)) {
369
+ console.log(`[patch-docx-grid] ${base}: tab-formula ALREADY PATCHED`);
370
+ } else {
371
+ const count = content.split(tabFormula.original).length - 1;
372
+ if (count !== 1) {
373
+ console.error(`[patch-docx-grid] ERROR: tab-formula expected 1 anchor in ${base}, found ${count}`);
374
+ process.exitCode = 1;
375
+ } else {
376
+ content = content.replace(tabFormula.original, tabFormula.patched);
377
+ console.log(`[patch-docx-grid] ${base}: tab-formula PATCHED`);
378
+ }
379
+ }
380
+ }
381
+
382
+ if (content.includes(PATCHED)) {
383
+ if (content !== fs.readFileSync(file, 'utf8')) {
384
+ fs.writeFileSync(file, content, 'utf8');
385
+ }
386
+ console.log(`[patch-docx-grid] docGrid: ${base} ALREADY PATCHED`);
387
+ ok++;
388
+ continue;
389
+ }
390
+
391
+ // Upgrade path from the previous one-grid patch: rewrite the whole function.
392
+ if (content.includes(LEGACY_ONE_GRID_TAIL) && content.includes(ORIGINAL.replace('this.applyDocumentGridMinimumHeight(e,t,r,a)}', LEGACY_ONE_GRID_TAIL))) {
393
+ const legacyFull = ORIGINAL.replace('this.applyDocumentGridMinimumHeight(e,t,r,a)}', LEGACY_ONE_GRID_TAIL);
394
+ content = content.replace(legacyFull, PATCHED);
395
+ } else {
396
+ const count = content.split(ORIGINAL).length - 1;
397
+ if (count !== 1) {
398
+ console.error(`[patch-docx-grid] ERROR: expected 1 original function in ${base}, found ${count}`);
399
+ process.exitCode = 1;
400
+ continue;
401
+ }
402
+ content = content.replace(ORIGINAL, PATCHED);
403
+ }
404
+
405
+ fs.writeFileSync(file, content, 'utf8');
406
+ console.log(`[patch-docx-grid] PATCHED: ${base}`);
407
+ ok++;
408
+ }
409
+
410
+ if (ok === targets.length && process.exitCode !== 1) {
411
+ console.log('[patch-docx-grid] All files patched successfully.');
412
+ }