@cj-tech-master/excelts 9.6.1 → 10.0.0

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 (207) hide show
  1. package/README.md +18 -3
  2. package/README_zh.md +18 -3
  3. package/dist/browser/modules/excel/cell.d.ts +4 -0
  4. package/dist/browser/modules/excel/note.js +5 -1
  5. package/dist/browser/modules/excel/row.js +35 -2
  6. package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +8 -1
  7. package/dist/browser/modules/excel/stream/workbook-writer.browser.js +22 -2
  8. package/dist/browser/modules/excel/types.d.ts +81 -0
  9. package/dist/browser/modules/excel/utils/drawing-utils.d.ts +8 -0
  10. package/dist/browser/modules/excel/utils/drawing-utils.js +19 -2
  11. package/dist/browser/modules/excel/workbook.browser.d.ts +16 -0
  12. package/dist/browser/modules/excel/workbook.browser.js +32 -2
  13. package/dist/browser/modules/excel/worksheet.d.ts +31 -1
  14. package/dist/browser/modules/excel/worksheet.js +83 -0
  15. package/dist/browser/modules/excel/xlsx/xform/comment/vml-shape-xform.d.ts +7 -0
  16. package/dist/browser/modules/excel/xlsx/xform/comment/vml-shape-xform.js +42 -8
  17. package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +3 -1
  18. package/dist/browser/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +5 -0
  19. package/dist/browser/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +18 -1
  20. package/dist/browser/modules/excel/xlsx/xform/drawing/blip-xform.d.ts +6 -0
  21. package/dist/browser/modules/excel/xlsx/xform/drawing/blip-xform.js +38 -11
  22. package/dist/browser/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.d.ts +1 -0
  23. package/dist/browser/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +5 -0
  24. package/dist/browser/modules/excel/xlsx/xform/drawing/pic-xform.d.ts +2 -0
  25. package/dist/browser/modules/excel/xlsx/xform/drawing/pic-xform.js +2 -1
  26. package/dist/browser/modules/excel/xlsx/xform/drawing/shape-xform.d.ts +47 -0
  27. package/dist/browser/modules/excel/xlsx/xform/drawing/shape-xform.js +109 -0
  28. package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +10 -1
  29. package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +64 -1
  30. package/dist/browser/modules/pdf/builder/document-builder.js +22 -49
  31. package/dist/browser/modules/pdf/builder/pdf-editor.js +1 -1
  32. package/dist/browser/modules/pdf/core/pdf-stream.d.ts +28 -1
  33. package/dist/browser/modules/pdf/core/pdf-stream.js +38 -2
  34. package/dist/browser/modules/pdf/font/font-manager.d.ts +26 -0
  35. package/dist/browser/modules/pdf/font/font-manager.js +35 -18
  36. package/dist/browser/modules/pdf/render/page-renderer.d.ts +51 -3
  37. package/dist/browser/modules/pdf/render/page-renderer.js +111 -18
  38. package/dist/browser/modules/word/advanced/field-engine.js +45 -20
  39. package/dist/browser/modules/word/advanced/glossary.d.ts +10 -36
  40. package/dist/browser/modules/word/advanced/glossary.js +8 -9
  41. package/dist/browser/modules/word/advanced/math-convert.js +94 -12
  42. package/dist/browser/modules/word/advanced/ole-objects.d.ts +28 -0
  43. package/dist/browser/modules/word/advanced/ole-objects.js +122 -19
  44. package/dist/browser/modules/word/advanced/style-map.js +31 -10
  45. package/dist/browser/modules/word/builder/run-builders.d.ts +7 -1
  46. package/dist/browser/modules/word/builder/run-builders.js +7 -1
  47. package/dist/browser/modules/word/constants.d.ts +4 -0
  48. package/dist/browser/modules/word/constants.js +5 -1
  49. package/dist/browser/modules/word/convert/docx-to-semantic.d.ts +2 -1
  50. package/dist/browser/modules/word/convert/docx-to-semantic.js +135 -1
  51. package/dist/browser/modules/word/convert/html/html-import.d.ts +32 -1
  52. package/dist/browser/modules/word/convert/html/html-import.js +167 -14
  53. package/dist/browser/modules/word/convert/html/html.d.ts +2 -2
  54. package/dist/browser/modules/word/convert/html/html.js +1 -1
  55. package/dist/browser/modules/word/convert/markdown/markdown-import.d.ts +48 -18
  56. package/dist/browser/modules/word/convert/markdown/markdown-import.js +279 -69
  57. package/dist/browser/modules/word/convert/markdown/markdown.d.ts +1 -1
  58. package/dist/browser/modules/word/convert/odt/odt.js +407 -56
  59. package/dist/browser/modules/word/html.d.ts +2 -2
  60. package/dist/browser/modules/word/html.js +1 -1
  61. package/dist/browser/modules/word/index.base.d.ts +3 -3
  62. package/dist/browser/modules/word/index.base.js +1 -1
  63. package/dist/browser/modules/word/layout/layout-full.js +326 -19
  64. package/dist/browser/modules/word/layout/render-page.js +35 -8
  65. package/dist/browser/modules/word/markdown.d.ts +1 -1
  66. package/dist/browser/modules/word/query/compat.d.ts +10 -2
  67. package/dist/browser/modules/word/query/compat.js +29 -21
  68. package/dist/browser/modules/word/reader/docx-reader.js +105 -2
  69. package/dist/browser/modules/word/reader/math-parser.js +8 -2
  70. package/dist/browser/modules/word/security/cfb-reader.js +5 -5
  71. package/dist/browser/modules/word/types.d.ts +96 -1
  72. package/dist/browser/modules/word/writer/docx-packager.js +108 -2
  73. package/dist/browser/modules/word/writer/glossary-writer.d.ts +28 -0
  74. package/dist/browser/modules/word/writer/glossary-writer.js +121 -0
  75. package/dist/browser/modules/word/writer/header-footer-writer.js +105 -20
  76. package/dist/browser/modules/word/writer/math-writer.js +7 -2
  77. package/dist/browser/utils/font-metrics.d.ts +8 -0
  78. package/dist/browser/utils/font-metrics.js +43 -0
  79. package/dist/browser/utils/theme-colors.js +4 -1
  80. package/dist/cjs/modules/excel/note.js +5 -1
  81. package/dist/cjs/modules/excel/row.js +35 -2
  82. package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +22 -2
  83. package/dist/cjs/modules/excel/utils/drawing-utils.js +19 -2
  84. package/dist/cjs/modules/excel/workbook.browser.js +31 -1
  85. package/dist/cjs/modules/excel/worksheet.js +83 -0
  86. package/dist/cjs/modules/excel/xlsx/xform/comment/vml-shape-xform.js +42 -8
  87. package/dist/cjs/modules/excel/xlsx/xform/core/content-types-xform.js +3 -1
  88. package/dist/cjs/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +5 -0
  89. package/dist/cjs/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +18 -1
  90. package/dist/cjs/modules/excel/xlsx/xform/drawing/blip-xform.js +38 -11
  91. package/dist/cjs/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +5 -0
  92. package/dist/cjs/modules/excel/xlsx/xform/drawing/pic-xform.js +2 -1
  93. package/dist/cjs/modules/excel/xlsx/xform/drawing/shape-xform.js +112 -0
  94. package/dist/cjs/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +10 -1
  95. package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +64 -1
  96. package/dist/cjs/modules/pdf/builder/document-builder.js +21 -48
  97. package/dist/cjs/modules/pdf/builder/pdf-editor.js +1 -1
  98. package/dist/cjs/modules/pdf/core/pdf-stream.js +38 -2
  99. package/dist/cjs/modules/pdf/font/font-manager.js +35 -18
  100. package/dist/cjs/modules/pdf/render/page-renderer.js +112 -18
  101. package/dist/cjs/modules/word/advanced/field-engine.js +45 -20
  102. package/dist/cjs/modules/word/advanced/glossary.js +8 -9
  103. package/dist/cjs/modules/word/advanced/math-convert.js +94 -12
  104. package/dist/cjs/modules/word/advanced/ole-objects.js +123 -19
  105. package/dist/cjs/modules/word/advanced/style-map.js +31 -10
  106. package/dist/cjs/modules/word/builder/run-builders.js +7 -1
  107. package/dist/cjs/modules/word/constants.js +5 -1
  108. package/dist/cjs/modules/word/convert/docx-to-semantic.js +135 -1
  109. package/dist/cjs/modules/word/convert/html/html-import.js +168 -14
  110. package/dist/cjs/modules/word/convert/html/html.js +2 -1
  111. package/dist/cjs/modules/word/convert/markdown/markdown-import.js +279 -69
  112. package/dist/cjs/modules/word/convert/odt/odt.js +407 -56
  113. package/dist/cjs/modules/word/html.js +2 -1
  114. package/dist/cjs/modules/word/index.base.js +4 -3
  115. package/dist/cjs/modules/word/layout/layout-full.js +325 -18
  116. package/dist/cjs/modules/word/layout/render-page.js +35 -8
  117. package/dist/cjs/modules/word/query/compat.js +29 -21
  118. package/dist/cjs/modules/word/reader/docx-reader.js +104 -1
  119. package/dist/cjs/modules/word/reader/math-parser.js +8 -2
  120. package/dist/cjs/modules/word/security/cfb-reader.js +5 -5
  121. package/dist/cjs/modules/word/writer/docx-packager.js +108 -2
  122. package/dist/cjs/modules/word/writer/glossary-writer.js +124 -0
  123. package/dist/cjs/modules/word/writer/header-footer-writer.js +105 -20
  124. package/dist/cjs/modules/word/writer/math-writer.js +7 -2
  125. package/dist/cjs/utils/font-metrics.js +44 -0
  126. package/dist/cjs/utils/theme-colors.js +4 -1
  127. package/dist/esm/modules/excel/note.js +5 -1
  128. package/dist/esm/modules/excel/row.js +35 -2
  129. package/dist/esm/modules/excel/stream/workbook-writer.browser.js +22 -2
  130. package/dist/esm/modules/excel/utils/drawing-utils.js +19 -2
  131. package/dist/esm/modules/excel/workbook.browser.js +32 -2
  132. package/dist/esm/modules/excel/worksheet.js +83 -0
  133. package/dist/esm/modules/excel/xlsx/xform/comment/vml-shape-xform.js +42 -8
  134. package/dist/esm/modules/excel/xlsx/xform/core/content-types-xform.js +3 -1
  135. package/dist/esm/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +5 -0
  136. package/dist/esm/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +18 -1
  137. package/dist/esm/modules/excel/xlsx/xform/drawing/blip-xform.js +38 -11
  138. package/dist/esm/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +5 -0
  139. package/dist/esm/modules/excel/xlsx/xform/drawing/pic-xform.js +2 -1
  140. package/dist/esm/modules/excel/xlsx/xform/drawing/shape-xform.js +109 -0
  141. package/dist/esm/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +10 -1
  142. package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +64 -1
  143. package/dist/esm/modules/pdf/builder/document-builder.js +22 -49
  144. package/dist/esm/modules/pdf/builder/pdf-editor.js +1 -1
  145. package/dist/esm/modules/pdf/core/pdf-stream.js +38 -2
  146. package/dist/esm/modules/pdf/font/font-manager.js +35 -18
  147. package/dist/esm/modules/pdf/render/page-renderer.js +111 -18
  148. package/dist/esm/modules/word/advanced/field-engine.js +45 -20
  149. package/dist/esm/modules/word/advanced/glossary.js +8 -9
  150. package/dist/esm/modules/word/advanced/math-convert.js +94 -12
  151. package/dist/esm/modules/word/advanced/ole-objects.js +122 -19
  152. package/dist/esm/modules/word/advanced/style-map.js +31 -10
  153. package/dist/esm/modules/word/builder/run-builders.js +7 -1
  154. package/dist/esm/modules/word/constants.js +5 -1
  155. package/dist/esm/modules/word/convert/docx-to-semantic.js +135 -1
  156. package/dist/esm/modules/word/convert/html/html-import.js +167 -14
  157. package/dist/esm/modules/word/convert/html/html.js +1 -1
  158. package/dist/esm/modules/word/convert/markdown/markdown-import.js +279 -69
  159. package/dist/esm/modules/word/convert/odt/odt.js +407 -56
  160. package/dist/esm/modules/word/html.js +1 -1
  161. package/dist/esm/modules/word/index.base.js +1 -1
  162. package/dist/esm/modules/word/layout/layout-full.js +326 -19
  163. package/dist/esm/modules/word/layout/render-page.js +35 -8
  164. package/dist/esm/modules/word/query/compat.js +29 -21
  165. package/dist/esm/modules/word/reader/docx-reader.js +105 -2
  166. package/dist/esm/modules/word/reader/math-parser.js +8 -2
  167. package/dist/esm/modules/word/security/cfb-reader.js +5 -5
  168. package/dist/esm/modules/word/writer/docx-packager.js +108 -2
  169. package/dist/esm/modules/word/writer/glossary-writer.js +121 -0
  170. package/dist/esm/modules/word/writer/header-footer-writer.js +105 -20
  171. package/dist/esm/modules/word/writer/math-writer.js +7 -2
  172. package/dist/esm/utils/font-metrics.js +43 -0
  173. package/dist/esm/utils/theme-colors.js +4 -1
  174. package/dist/iife/excelts.iife.js +496 -59
  175. package/dist/iife/excelts.iife.js.map +1 -1
  176. package/dist/iife/excelts.iife.min.js +39 -39
  177. package/dist/types/modules/excel/cell.d.ts +4 -0
  178. package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +8 -1
  179. package/dist/types/modules/excel/types.d.ts +81 -0
  180. package/dist/types/modules/excel/utils/drawing-utils.d.ts +8 -0
  181. package/dist/types/modules/excel/workbook.browser.d.ts +16 -0
  182. package/dist/types/modules/excel/worksheet.d.ts +31 -1
  183. package/dist/types/modules/excel/xlsx/xform/comment/vml-shape-xform.d.ts +7 -0
  184. package/dist/types/modules/excel/xlsx/xform/drawing/blip-xform.d.ts +6 -0
  185. package/dist/types/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.d.ts +1 -0
  186. package/dist/types/modules/excel/xlsx/xform/drawing/pic-xform.d.ts +2 -0
  187. package/dist/types/modules/excel/xlsx/xform/drawing/shape-xform.d.ts +47 -0
  188. package/dist/types/modules/pdf/core/pdf-stream.d.ts +28 -1
  189. package/dist/types/modules/pdf/font/font-manager.d.ts +26 -0
  190. package/dist/types/modules/pdf/render/page-renderer.d.ts +51 -3
  191. package/dist/types/modules/word/advanced/glossary.d.ts +10 -36
  192. package/dist/types/modules/word/advanced/ole-objects.d.ts +28 -0
  193. package/dist/types/modules/word/builder/run-builders.d.ts +7 -1
  194. package/dist/types/modules/word/constants.d.ts +4 -0
  195. package/dist/types/modules/word/convert/docx-to-semantic.d.ts +2 -1
  196. package/dist/types/modules/word/convert/html/html-import.d.ts +32 -1
  197. package/dist/types/modules/word/convert/html/html.d.ts +2 -2
  198. package/dist/types/modules/word/convert/markdown/markdown-import.d.ts +48 -18
  199. package/dist/types/modules/word/convert/markdown/markdown.d.ts +1 -1
  200. package/dist/types/modules/word/html.d.ts +2 -2
  201. package/dist/types/modules/word/index.base.d.ts +3 -3
  202. package/dist/types/modules/word/markdown.d.ts +1 -1
  203. package/dist/types/modules/word/query/compat.d.ts +10 -2
  204. package/dist/types/modules/word/types.d.ts +96 -1
  205. package/dist/types/modules/word/writer/glossary-writer.d.ts +28 -0
  206. package/dist/types/utils/font-metrics.d.ts +8 -0
  207. package/package.json +3 -1
@@ -2460,6 +2460,107 @@ async function _readDocxInner(buffer, policy) {
2460
2460
  break;
2461
2461
  }
2462
2462
  }
2463
+ // Extract OLE embedded objects wired on document.xml.rels. We surface
2464
+ // them as structured `oleObjects` so callers can query/round-trip them
2465
+ // (getOleObjectData/extractOleObjects) without depending on the part's
2466
+ // own .rels (OLE binaries carry no .rels — their relationship lives on
2467
+ // document.xml.rels). The body still references each object through an
2468
+ // opaqueDrawing carrying the same r:id. Honours `preserveOleObjects`.
2469
+ let oleObjects;
2470
+ if (policy.preserveOleObjects) {
2471
+ const collected = [];
2472
+ // progId may be recoverable from the body's <o:OLEObject ProgID="…">.
2473
+ // The <w:object> markup is preserved either as a body-level opaqueDrawing
2474
+ // or (more commonly) as a run-level opaqueRun inside a paragraph. Collect
2475
+ // raw XML from both so the ProgID round-trips.
2476
+ const progIdByRId = new Map();
2477
+ const scanOleMarkup = (rawXml) => {
2478
+ // Match ProgID + r:id from within the same <o:OLEObject> element so a
2479
+ // preview <v:imagedata r:id="…"> earlier in the markup is not mistaken
2480
+ // for the OLE binary's relationship id.
2481
+ const oleTagRe = /<o:OLEObject\b[^>]*>/gi;
2482
+ let m;
2483
+ while ((m = oleTagRe.exec(rawXml)) !== null) {
2484
+ const tag = m[0];
2485
+ const progMatch = tag.match(/ProgID="([^"]+)"/i);
2486
+ const ridMatch = tag.match(/r:id="([^"]+)"/i);
2487
+ if (progMatch && ridMatch) {
2488
+ progIdByRId.set(ridMatch[1], progMatch[1]);
2489
+ }
2490
+ }
2491
+ };
2492
+ for (const item of body) {
2493
+ if (item.type === "opaqueDrawing") {
2494
+ scanOleMarkup(item.rawXml);
2495
+ }
2496
+ else if (item.type === "paragraph") {
2497
+ for (const child of item.children) {
2498
+ if ((0, text_utils_1.isRun)(child)) {
2499
+ for (const rc of child.content) {
2500
+ if (rc.type === "opaqueRun") {
2501
+ scanOleMarkup(rc.rawXml);
2502
+ }
2503
+ }
2504
+ }
2505
+ }
2506
+ }
2507
+ }
2508
+ for (const rel of docRels) {
2509
+ if (rel.type !== constants_1.RelType.Package) {
2510
+ continue;
2511
+ }
2512
+ const olePath = (0, parse_utils_1.resolvePartPath)(documentPartPath, rel.target);
2513
+ if (!olePath.startsWith("word/embeddings/")) {
2514
+ continue;
2515
+ }
2516
+ const oleData = entries.get(olePath);
2517
+ if (!oleData) {
2518
+ continue;
2519
+ }
2520
+ consumedPaths.add(olePath);
2521
+ collected.push({
2522
+ path: olePath,
2523
+ data: oleData,
2524
+ rId: rel.id,
2525
+ progId: progIdByRId.get(rel.id),
2526
+ contentType: constants_1.ContentType.OleObject
2527
+ });
2528
+ }
2529
+ if (collected.length > 0) {
2530
+ oleObjects = collected;
2531
+ }
2532
+ }
2533
+ // Glossary document (Building Blocks). The glossary is a self-contained
2534
+ // sub-document: word/glossary/document.xml plus its own companion parts
2535
+ // (styles/settings/webSettings/fontTable) referenced from
2536
+ // word/glossary/_rels/document.xml.rels. We carry document.xml verbatim as
2537
+ // `rawXml` and ALL sibling glossary parts (including the .rels) verbatim in
2538
+ // `rawParts`, so a read→write round-trip re-emits a complete, Word-valid
2539
+ // glossary rather than dropping it (opaqueParts would lose both the
2540
+ // glossaryDocument relationship and the companion .rels). The structured
2541
+ // `blocks` are not reverse-parsed.
2542
+ let glossary;
2543
+ for (const rel of docRels) {
2544
+ if (rel.type !== constants_1.RelType.Glossary) {
2545
+ continue;
2546
+ }
2547
+ const glossaryPath = (0, parse_utils_1.resolvePartPath)(documentPartPath, rel.target);
2548
+ const glossaryData = entries.get(glossaryPath);
2549
+ if (glossaryData) {
2550
+ // Collect every word/glossary/** part (document.xml, its .rels and all
2551
+ // companions) verbatim, and mark them consumed so they are not also
2552
+ // emitted via opaqueParts.
2553
+ const rawParts = new Map();
2554
+ for (const [path, data] of entries) {
2555
+ if (path.startsWith("word/glossary/")) {
2556
+ rawParts.set(path, data);
2557
+ consumedPaths.add(path);
2558
+ }
2559
+ }
2560
+ glossary = { blocks: [], rawXml: decoder.decode(glossaryData), rawParts };
2561
+ }
2562
+ break;
2563
+ }
2463
2564
  // Resolve altChunk data: body elements of type "altChunk" reference a rId.
2464
2565
  // The target file is stored in docRels + entries. We populate the altChunk
2465
2566
  // body item with its data here AND mark the target path as consumed so the
@@ -2578,6 +2679,8 @@ async function _readDocxInner(buffer, policy) {
2578
2679
  theme,
2579
2680
  watermark,
2580
2681
  opaqueParts: opaqueParts.length > 0 ? opaqueParts : undefined,
2581
- vbaProject
2682
+ vbaProject,
2683
+ oleObjects,
2684
+ glossary
2582
2685
  };
2583
2686
  }
@@ -125,8 +125,14 @@ function parseMathContent(el) {
125
125
  const v = (0, parse_utils_1.attrLocal)(el, "val");
126
126
  return v !== "0" && v !== "false";
127
127
  };
128
- if (boolAttr("show")) {
129
- ph.show = true;
128
+ // `show` is tri-state: it may be explicitly off (`m:val="0"`), which
129
+ // is what makes a phantom invisible, explicitly on, or absent
130
+ // (defaults to on). Preserve an explicit value so a round-trip keeps
131
+ // the invisibility, but leave it unset when the element is absent.
132
+ const showEl = (0, parse_utils_1.findChildLocal)(phantPrEl, "show");
133
+ if (showEl) {
134
+ const v = (0, parse_utils_1.attrLocal)(showEl, "val");
135
+ ph.show = v !== "0" && v !== "false";
130
136
  }
131
137
  if (boolAttr("zeroWid")) {
132
138
  ph.zeroWidth = true;
@@ -340,9 +340,8 @@ function writeCfb(entries) {
340
340
  const miniNodes = streamNodes.filter(n => n.size > 0 && n.size < MINI_STREAM_CUTOFF);
341
341
  const regularNodes = streamNodes.filter(n => n.size >= MINI_STREAM_CUTOFF);
342
342
  // Assemble the mini-stream and the mini-FAT.
343
- let miniStream = new Uint8Array(0);
344
343
  const miniFat = [];
345
- {
344
+ const miniStream = (() => {
346
345
  const parts = [];
347
346
  let miniSectorIdx = 0;
348
347
  let totalLen = 0;
@@ -358,13 +357,14 @@ function writeCfb(entries) {
358
357
  parts.push(padded);
359
358
  totalLen += padded.length;
360
359
  }
361
- miniStream = new Uint8Array(totalLen);
360
+ const stream = new Uint8Array(totalLen);
362
361
  let off = 0;
363
362
  for (const p of parts) {
364
- miniStream.set(p, off);
363
+ stream.set(p, off);
365
364
  off += p.length;
366
365
  }
367
- }
366
+ return stream;
367
+ })();
368
368
  root.size = miniStream.length;
369
369
  // ---------------------------------------------------------------------------
370
370
  // 4. Lay out regular sectors.
@@ -56,6 +56,7 @@ const comment_writer_1 = require("./comment-writer");
56
56
  const content_types_1 = require("./content-types");
57
57
  const document_writer_1 = require("./document-writer");
58
58
  const footnote_writer_1 = require("./footnote-writer");
59
+ const glossary_writer_1 = require("./glossary-writer");
59
60
  const header_footer_writer_1 = require("./header-footer-writer");
60
61
  const numbering_writer_1 = require("./numbering-writer");
61
62
  const parts_writer_1 = require("./parts-writer");
@@ -1119,7 +1120,13 @@ async function _packageDocxInner(doc, options) {
1119
1120
  // word/styles.xml
1120
1121
  archive.add(constants_1.PartPath.Styles, renderXml(xml => (0, styles_writer_1.renderStyles)(xml, doc.docDefaults, doc.styles)));
1121
1122
  // word/settings.xml
1122
- archive.add(constants_1.PartPath.Settings, renderXml(xml => (0, parts_writer_1.renderSettings)(xml, doc.settings, rawXmlPolicy)));
1123
+ // When the document defines a page background, Word only paints it if
1124
+ // <w:displayBackgroundShape/> is present in settings. Inject it
1125
+ // automatically so setBackground() actually shows up on screen.
1126
+ const settingsForRender = doc.background && !doc.settings?.displayBackgroundShape
1127
+ ? { ...(doc.settings ?? {}), displayBackgroundShape: true }
1128
+ : doc.settings;
1129
+ archive.add(constants_1.PartPath.Settings, renderXml(xml => (0, parts_writer_1.renderSettings)(xml, settingsForRender, rawXmlPolicy)));
1123
1130
  // word/fontTable.xml
1124
1131
  archive.add(constants_1.PartPath.FontTable, renderXml(xml => (0, parts_writer_1.renderFontTable)(xml, doc.fonts)));
1125
1132
  // word/fonts/*.odttf (embedded fonts)
@@ -1381,6 +1388,81 @@ async function _packageDocxInner(doc, options) {
1381
1388
  (0, relationships_1.addRelationship)(documentRels, constants_1.RelType.VbaProject, "vbaProject.bin");
1382
1389
  (0, content_types_1.addContentTypeOverride)(contentTypes, "/word/vbaProject.bin", constants_1.ContentType.VbaProject);
1383
1390
  }
1391
+ // OLE embedded objects (word/embeddings/*.bin + optional preview media).
1392
+ // Each object is registered with the *exact* rId referenced from the body
1393
+ // `<w:object r:id="…">` markup, so the reference always resolves. The
1394
+ // `preserveOleObjects` security policy can still strip the binaries below.
1395
+ if (doc.oleObjects && securityPolicy.preserveOleObjects) {
1396
+ for (const ole of doc.oleObjects) {
1397
+ archive.add(ole.path, ole.data);
1398
+ // Target is relative to word/ (document.xml lives in word/).
1399
+ const oleTarget = ole.path.replace(/^word\//, "");
1400
+ (0, relationships_1.addRelationshipWithId)(documentRels, ole.rId, constants_1.RelType.Package, oleTarget);
1401
+ (0, content_types_1.addContentTypeOverride)(contentTypes, `/${ole.path}`, ole.contentType ?? constants_1.ContentType.OleObject);
1402
+ if (ole.previewPath && ole.previewData && ole.previewRId) {
1403
+ archive.add(ole.previewPath, ole.previewData);
1404
+ (0, relationships_1.addRelationshipWithId)(documentRels, ole.previewRId, constants_1.RelType.Image, ole.previewPath.replace(/^word\//, ""));
1405
+ if (ole.previewContentType) {
1406
+ (0, content_types_1.addContentTypeOverride)(contentTypes, `/${ole.previewPath}`, ole.previewContentType);
1407
+ }
1408
+ else {
1409
+ const ext = (0, opc_paths_1.getFileExt)(ole.previewPath);
1410
+ const inferred = ext ? inferContentType(ext) : undefined;
1411
+ if (inferred) {
1412
+ (0, content_types_1.addContentTypeOverride)(contentTypes, `/${ole.previewPath}`, inferred);
1413
+ }
1414
+ }
1415
+ }
1416
+ }
1417
+ }
1418
+ // word/glossary/document.xml (Building Blocks / AutoText / Quick Parts).
1419
+ //
1420
+ // A glossary is a self-contained sub-document: Word expects it to carry its
1421
+ // own styles / settings / webSettings / fontTable parts (referenced from
1422
+ // word/glossary/_rels/document.xml.rels) rather than sharing the main
1423
+ // document's. Omitting them makes Word discard the whole glossary on open.
1424
+ //
1425
+ // - Round-tripped glossary (`rawParts` set): re-emit every captured
1426
+ // word/glossary/** part verbatim (document.xml, its .rels, companions).
1427
+ // - Freshly-built glossary: synthesise document.xml + the companion parts
1428
+ // + the glossary's own .rels, reusing the main document's styles/fonts so
1429
+ // block content (e.g. Heading1) resolves.
1430
+ if (doc.glossary && (doc.glossary.rawXml || doc.glossary.blocks.length > 0)) {
1431
+ (0, relationships_1.addRelationship)(documentRels, constants_1.RelType.Glossary, "glossary/document.xml");
1432
+ if (doc.glossary.rawParts && doc.glossary.rawParts.size > 0) {
1433
+ for (const [path, data] of doc.glossary.rawParts) {
1434
+ archive.add(path, data);
1435
+ if (path.endsWith(".rels")) {
1436
+ continue; // .rels parts are typed by the Default rels content type
1437
+ }
1438
+ const ct = path === "word/glossary/document.xml"
1439
+ ? constants_1.ContentType.Glossary
1440
+ : inferContentType((0, opc_paths_1.getFileExt)(path));
1441
+ if (ct) {
1442
+ (0, content_types_1.addContentTypeOverride)(contentTypes, `/${path}`, ct);
1443
+ }
1444
+ }
1445
+ }
1446
+ else {
1447
+ archive.add("word/glossary/document.xml", (0, glossary_writer_1.renderGlossaryDocument)(doc.glossary));
1448
+ (0, content_types_1.addContentTypeOverride)(contentTypes, "/word/glossary/document.xml", constants_1.ContentType.Glossary);
1449
+ // Synthesise the companion sub-document parts + the glossary's own rels.
1450
+ const glossaryRels = (0, relationships_1.createRelationships)();
1451
+ (0, relationships_1.addRelationshipWithId)(glossaryRels, "rId1", constants_1.RelType.Styles, "styles.xml");
1452
+ (0, relationships_1.addRelationshipWithId)(glossaryRels, "rId2", constants_1.RelType.Settings, "settings.xml");
1453
+ (0, relationships_1.addRelationshipWithId)(glossaryRels, "rId3", constants_1.RelType.WebSettings, "webSettings.xml");
1454
+ (0, relationships_1.addRelationshipWithId)(glossaryRels, "rId4", constants_1.RelType.FontTable, "fontTable.xml");
1455
+ archive.add("word/glossary/_rels/document.xml.rels", renderXml(xml => (0, relationships_1.renderRelationships)(glossaryRels, xml)));
1456
+ archive.add("word/glossary/styles.xml", renderXml(xml => (0, styles_writer_1.renderStyles)(xml, doc.docDefaults, doc.styles)));
1457
+ archive.add("word/glossary/settings.xml", renderXml(xml => (0, parts_writer_1.renderSettings)(xml, undefined, rawXmlPolicy)));
1458
+ archive.add("word/glossary/webSettings.xml", renderXml(xml => (0, parts_writer_1.renderWebSettings)(xml, undefined, rawXmlPolicy)));
1459
+ archive.add("word/glossary/fontTable.xml", renderXml(xml => (0, parts_writer_1.renderFontTable)(xml, doc.fonts)));
1460
+ (0, content_types_1.addContentTypeOverride)(contentTypes, "/word/glossary/styles.xml", constants_1.ContentType.Styles);
1461
+ (0, content_types_1.addContentTypeOverride)(contentTypes, "/word/glossary/settings.xml", constants_1.ContentType.Settings);
1462
+ (0, content_types_1.addContentTypeOverride)(contentTypes, "/word/glossary/webSettings.xml", constants_1.ContentType.WebSettings);
1463
+ (0, content_types_1.addContentTypeOverride)(contentTypes, "/word/glossary/fontTable.xml", constants_1.ContentType.FontTable);
1464
+ }
1465
+ }
1384
1466
  // Write opaque (unrecognized) parts for round-trip preservation.
1385
1467
  //
1386
1468
  // Opaque parts are written as-is into the ZIP. Their paths must not
@@ -1421,8 +1503,23 @@ async function _packageDocxInner(doc, options) {
1421
1503
  constants_1.PartPath.CustomProps,
1422
1504
  constants_1.PartPath.Thumbnail,
1423
1505
  "word/vbaProject.bin",
1424
- "word/_rels/vbaProject.bin.rels"
1506
+ "word/_rels/vbaProject.bin.rels",
1507
+ "word/glossary/document.xml",
1508
+ "word/glossary/_rels/document.xml.rels"
1425
1509
  ]);
1510
+ // Glossary sub-document parts (emitted either verbatim from rawParts or
1511
+ // synthesised); reserve them so opaqueParts can't collide.
1512
+ if (doc.glossary && (doc.glossary.rawXml || doc.glossary.blocks.length > 0)) {
1513
+ reservedExact.add("word/glossary/styles.xml");
1514
+ reservedExact.add("word/glossary/settings.xml");
1515
+ reservedExact.add("word/glossary/webSettings.xml");
1516
+ reservedExact.add("word/glossary/fontTable.xml");
1517
+ if (doc.glossary.rawParts) {
1518
+ for (const path of doc.glossary.rawParts.keys()) {
1519
+ reservedExact.add(path);
1520
+ }
1521
+ }
1522
+ }
1426
1523
  // Headers/footers we are emitting in this run.
1427
1524
  if (doc.headers) {
1428
1525
  let i = 1;
@@ -1466,6 +1563,15 @@ async function _packageDocxInner(doc, options) {
1466
1563
  }
1467
1564
  }
1468
1565
  }
1566
+ // OLE embedded objects emitted by this run.
1567
+ if (doc.oleObjects) {
1568
+ for (const ole of doc.oleObjects) {
1569
+ reservedExact.add(ole.path);
1570
+ if (ole.previewPath) {
1571
+ reservedExact.add(ole.previewPath);
1572
+ }
1573
+ }
1574
+ }
1469
1575
  for (const part of doc.opaqueParts) {
1470
1576
  if (reservedExact.has(part.path)) {
1471
1577
  throw new errors_1.DocxWriteError(`Opaque part path "${part.path}" conflicts with a part the packager ` +
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ /**
3
+ * DOCX Module — Glossary (Building Blocks) Part Writer
4
+ *
5
+ * Serialises a {@link GlossaryDocument} into the canonical
6
+ * `word/glossary/document.xml` OOXML form:
7
+ *
8
+ * ```xml
9
+ * <w:glossaryDocument>
10
+ * <w:docParts>
11
+ * <w:docPart>
12
+ * <w:docPartPr>
13
+ * <w:name w:val="…"/>
14
+ * <w:category><w:name w:val="…"/><w:gallery w:val="…"/></w:category>
15
+ * <w:behaviors><w:behavior w:val="content"/></w:behaviors>
16
+ * <w:guid w:val="{…}"/>
17
+ * </w:docPartPr>
18
+ * <w:docPartBody>… body content …</w:docPartBody>
19
+ * </w:docPart>
20
+ * </w:docParts>
21
+ * </w:glossaryDocument>
22
+ * ```
23
+ *
24
+ * Lives in the writer layer (not `advanced/`) so the packager can depend on
25
+ * it without creating a `advanced/ → writer/` import cycle.
26
+ */
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.renderGlossaryDocument = renderGlossaryDocument;
29
+ const writer_1 = require("../../xml/writer.js");
30
+ const constants_1 = require("../constants");
31
+ const document_writer_1 = require("./document-writer");
32
+ /**
33
+ * Map the friendly {@link BuildingBlockGallery} token to the OOXML
34
+ * `ST_DocPartGallery` value used in `<w:gallery w:val="…">` (ECMA-376
35
+ * §17.18.23). Values MUST be exact enum members — Word rejects (and silently
36
+ * discards) the entire glossary if it sees an out-of-enum gallery value.
37
+ * There is no plain "quickParts" value; Quick Parts map to "custQuickParts".
38
+ */
39
+ const GALLERY_TO_OOXML = {
40
+ autoText: "autoTxt",
41
+ quickParts: "custQuickParts",
42
+ coverPages: "coverPg",
43
+ tableOfContents: "tblOfContents",
44
+ headers: "hdrs",
45
+ footers: "ftrs",
46
+ pageNumbers: "pgNum",
47
+ tables: "tbls",
48
+ textBoxes: "txtBox",
49
+ watermarks: "watermarks",
50
+ equations: "eq",
51
+ bibliographies: "bib",
52
+ custom1: "custom1",
53
+ custom2: "custom2",
54
+ custom3: "custom3",
55
+ custom4: "custom4",
56
+ custom5: "custom5"
57
+ };
58
+ /** Render a {@link GlossaryDocument} to a `word/glossary/document.xml` string. */
59
+ function renderGlossaryDocument(glossary) {
60
+ // Byte-faithful round-trip: a glossary read from an existing document is
61
+ // carried as verbatim XML and re-emitted unchanged.
62
+ if (glossary.rawXml) {
63
+ return glossary.rawXml;
64
+ }
65
+ const writer = new writer_1.XmlWriter();
66
+ renderGlossary(writer, glossary);
67
+ return writer.xml;
68
+ }
69
+ function renderGlossary(xml, glossary) {
70
+ xml.openXml(constants_1.STD_DOC_ATTRIBUTES);
71
+ xml.openNode("w:glossaryDocument", constants_1.DOCUMENT_NAMESPACES);
72
+ xml.openNode("w:docParts");
73
+ for (const block of glossary.blocks) {
74
+ renderDocPart(xml, block);
75
+ }
76
+ xml.closeNode(); // w:docParts
77
+ xml.closeNode(); // w:glossaryDocument
78
+ }
79
+ function renderDocPart(xml, block) {
80
+ xml.openNode("w:docPart");
81
+ // CT_DocPartPr — child order is fixed by the schema (ECMA-376 §17.12.1):
82
+ // name → style → category → types → behaviors → description → guid.
83
+ // Emitting these out of order makes Word reject the package on open.
84
+ xml.openNode("w:docPartPr");
85
+ xml.leafNode("w:name", { "w:val": block.name });
86
+ xml.openNode("w:category");
87
+ xml.leafNode("w:name", { "w:val": block.category ?? "General" });
88
+ xml.leafNode("w:gallery", { "w:val": GALLERY_TO_OOXML[block.gallery] ?? "placeholder" });
89
+ xml.closeNode(); // w:category
90
+ // `<w:types>` is optional; we omit it so we never emit an out-of-enum
91
+ // ST_DocPartType value. A docPart placed in the body inserts its content.
92
+ xml.openNode("w:behaviors");
93
+ xml.leafNode("w:behavior", { "w:val": "content" });
94
+ xml.closeNode(); // w:behaviors
95
+ if (block.description) {
96
+ xml.leafNode("w:description", { "w:val": block.description });
97
+ }
98
+ if (block.guid) {
99
+ xml.leafNode("w:guid", { "w:val": normaliseGuid(block.guid) });
100
+ }
101
+ xml.closeNode(); // w:docPartPr
102
+ // docPartBody — reuse the main body renderer. A fresh render context keeps
103
+ // id counters local; building-block content here is plain text/tables so it
104
+ // does not need image/chart rId remapping.
105
+ xml.openNode("w:docPartBody");
106
+ for (const item of block.content) {
107
+ (0, document_writer_1.renderBodyContent)(xml, item);
108
+ }
109
+ // CT_Body must end with a paragraph; emit one if the block had no content.
110
+ if (block.content.length === 0) {
111
+ xml.openNode("w:p");
112
+ xml.closeNode();
113
+ }
114
+ xml.closeNode(); // w:docPartBody
115
+ xml.closeNode(); // w:docPart
116
+ }
117
+ /** Word expects the docPart guid wrapped in braces: `{XXXXXXXX-…}`. */
118
+ function normaliseGuid(guid) {
119
+ const trimmed = guid.trim();
120
+ if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
121
+ return trimmed;
122
+ }
123
+ return `{${trimmed}}`;
124
+ }
@@ -71,12 +71,17 @@ function renderWatermarkHeader(xml, watermark, imageRId) {
71
71
  "xmlns:o": constants_1.NS_O,
72
72
  "xmlns:w10": constants_1.NS_W10
73
73
  });
74
- // Watermark goes in a paragraph with a single pict run. Skip pPr
75
- // entirely emitting an empty <w:pStyle/> without @w:val is a hard
76
- // schema violation Word rejects, and the default style is good enough
77
- // for an auto-generated watermark header.
74
+ // Watermark lives in a paragraph styled as a Header, matching what
75
+ // Microsoft Word emits. The run carries <w:noProof/> so the WordArt
76
+ // text is not spell-checked.
78
77
  xml.openNode("w:p");
78
+ xml.openNode("w:pPr");
79
+ xml.leafNode("w:pStyle", { "w:val": "Header" });
80
+ xml.closeNode(); // pPr
79
81
  xml.openNode("w:r");
82
+ xml.openNode("w:rPr");
83
+ xml.leafNode("w:noProof");
84
+ xml.closeNode(); // rPr
80
85
  xml.openNode("w:pict");
81
86
  if (watermark.type === "text") {
82
87
  renderTextWatermarkVml(xml, watermark);
@@ -92,49 +97,130 @@ function renderWatermarkHeader(xml, watermark, imageRId) {
92
97
  function renderTextWatermarkVml(xml, wm) {
93
98
  const color = wm.color ?? "C0C0C0";
94
99
  const font = wm.font ?? "Calibri";
95
- const fontSize = wm.fontSize ?? 1; // half-points; Word uses pt string in style
96
- const fontPt = fontSize / 2;
97
100
  const rotation = wm.rotation ?? -45;
98
- const opacity = wm.semiTransparent !== false ? ".5" : "1";
99
- // VML shape for text watermark (PowerWash / WASHOUT style)
100
- xml.leafNode("v:shapetype", {
101
+ // Full WordArt shapetype definition (t136) exactly as Microsoft Word
102
+ // emits it. Word for Mac will NOT render the text path unless the
103
+ // shapetype carries the formula/path/textpath/handles/lock children —
104
+ // an empty <v:shapetype/> produces an invisible watermark.
105
+ xml.openNode("v:shapetype", {
101
106
  id: "_x0000_t136",
102
107
  coordsize: "21600,21600",
103
108
  "o:spt": "136",
109
+ adj: "10800",
104
110
  path: "m@7,l@8,m@5,21600l@6,21600e"
105
111
  });
112
+ xml.openNode("v:formulas");
113
+ for (const eqn of [
114
+ "sum #0 0 10800",
115
+ "prod #0 2 1",
116
+ "sum 21600 0 @1",
117
+ "sum 0 0 @2",
118
+ "sum 21600 0 @3",
119
+ "if @0 @3 0",
120
+ "if @0 21600 @1",
121
+ "if @0 0 @2",
122
+ "if @0 @4 21600",
123
+ "mid @5 @6",
124
+ "mid @8 @5",
125
+ "mid @7 @8",
126
+ "mid @6 @7",
127
+ "sum @6 0 @5"
128
+ ]) {
129
+ xml.leafNode("v:f", { eqn });
130
+ }
131
+ xml.closeNode(); // formulas
132
+ xml.leafNode("v:path", {
133
+ textpathok: "t",
134
+ "o:connecttype": "custom",
135
+ "o:connectlocs": "@9,0;@10,10800;@11,21600;@12,10800",
136
+ "o:connectangles": "270,180,90,0"
137
+ });
138
+ xml.leafNode("v:textpath", { on: "t", fitshape: "t" });
139
+ xml.openNode("v:handles");
140
+ xml.leafNode("v:h", { position: "#0,bottomRight", xrange: "6629,14971" });
141
+ xml.closeNode(); // handles
142
+ xml.leafNode("o:lock", { "v:ext": "edit", text: "t", shapetype: "t" });
143
+ xml.closeNode(); // shapetype
144
+ // The watermark shape itself. Word fixes font-size at 1pt and relies on
145
+ // fitshape="t" to scale the text to fill the shape box; rotation is
146
+ // applied on the shape via the style string.
106
147
  const style = `position:absolute;margin-left:0;margin-top:0;width:468pt;height:234pt;` +
107
- `rotation:${rotation};z-index:-251658752;mso-position-horizontal:center;` +
108
- `mso-position-horizontal-relative:margin;mso-position-vertical:center;` +
109
- `mso-position-vertical-relative:margin`;
148
+ `${rotation ? `rotation:${rotation};` : ""}z-index:-251658752;` +
149
+ `mso-position-horizontal:center;mso-position-horizontal-relative:margin;` +
150
+ `mso-position-vertical:center;mso-position-vertical-relative:margin`;
110
151
  xml.openNode("v:shape", {
111
152
  id: "PowerPlusWaterMarkObject",
112
153
  "o:spid": "_x0000_s2049",
113
154
  type: "#_x0000_t136",
155
+ alt: "",
114
156
  style,
115
157
  "o:allowincell": "f",
116
158
  fillcolor: `#${color}`,
117
159
  stroked: "f"
118
160
  });
119
- xml.leafNode("v:fill", { opacity });
161
+ if (wm.semiTransparent !== false) {
162
+ xml.leafNode("v:fill", { opacity: ".5" });
163
+ }
120
164
  xml.leafNode("v:textpath", {
121
- style: `font-family:&quot;${font}&quot;;font-size:${fontPt}pt`,
165
+ style: `font-family:"${font}";font-size:1pt`,
122
166
  string: wm.text
123
167
  });
124
- xml.leafNode("w10:wrap", { anchorx: "margin", anchory: "margin" });
125
168
  xml.closeNode(); // v:shape
126
169
  }
127
170
  function renderImageWatermarkVml(xml, wm, rId) {
128
- const scale = wm.scale ?? 100;
129
171
  const rid = rId ?? wm.rId;
130
- const style = `position:absolute;margin-left:0;margin-top:0;width:0;height:0;` +
172
+ // Default to a large area covering most of the body so the picture is
173
+ // actually visible. width:0;height:0 produces an invisible dot.
174
+ const widthPt = wm.widthPt ?? 415.2;
175
+ const heightPt = wm.heightPt ?? 233.5;
176
+ // Picture-frame shapetype (t75) as Microsoft Word emits it. Without a
177
+ // proper shapetype + non-zero size the image watermark will not render.
178
+ xml.openNode("v:shapetype", {
179
+ id: "_x0000_t75",
180
+ coordsize: "21600,21600",
181
+ "o:spt": "75",
182
+ "o:preferrelative": "t",
183
+ path: "m@4@5l@4@11@9@11@9@5xe",
184
+ filled: "f",
185
+ stroked: "f"
186
+ });
187
+ xml.openNode("v:stroke", { joinstyle: "miter" });
188
+ xml.closeNode();
189
+ xml.openNode("v:formulas");
190
+ for (const eqn of [
191
+ "if lineDrawn pixelLineWidth 0",
192
+ "sum @0 1 0",
193
+ "sum 0 0 @1",
194
+ "prod @2 1 2",
195
+ "prod @3 21600 pixelWidth",
196
+ "prod @3 21600 pixelHeight",
197
+ "sum @0 0 1",
198
+ "prod @6 1 2",
199
+ "prod @7 21600 pixelWidth",
200
+ "sum @8 21600 0",
201
+ "prod @7 21600 pixelHeight",
202
+ "sum @10 21600 0"
203
+ ]) {
204
+ xml.leafNode("v:f", { eqn });
205
+ }
206
+ xml.closeNode(); // formulas
207
+ xml.leafNode("v:path", {
208
+ "o:extrusionok": "f",
209
+ gradientshapeok: "t",
210
+ "o:connecttype": "rect"
211
+ });
212
+ xml.leafNode("o:lock", { "v:ext": "edit", aspectratio: "t" });
213
+ xml.closeNode(); // shapetype
214
+ const style = `position:absolute;margin-left:0;margin-top:0;` +
215
+ `width:${widthPt}pt;height:${heightPt}pt;` +
131
216
  `z-index:-251658752;mso-position-horizontal:center;` +
132
217
  `mso-position-horizontal-relative:margin;mso-position-vertical:center;` +
133
218
  `mso-position-vertical-relative:margin`;
134
219
  xml.openNode("v:shape", {
135
220
  id: "PowerPlusWaterMarkObject",
136
221
  "o:spid": "_x0000_s2050",
137
- type: "",
222
+ type: "#_x0000_t75",
223
+ alt: "",
138
224
  style,
139
225
  "o:allowincell": "f"
140
226
  });
@@ -144,8 +230,7 @@ function renderImageWatermarkVml(xml, wm, rId) {
144
230
  "r:id": rid,
145
231
  "o:title": "",
146
232
  gain,
147
- blacklevel,
148
- ...(scale !== 100 ? { "o:detectmouseclick": "t" } : {})
233
+ blacklevel
149
234
  });
150
235
  xml.leafNode("w10:wrap", { anchorx: "margin", anchory: "margin" });
151
236
  xml.closeNode(); // v:shape
@@ -178,8 +178,13 @@ function renderMathPhantom(xml, p) {
178
178
  p.transparent !== undefined;
179
179
  if (hasProps) {
180
180
  xml.openNode("m:phantPr");
181
- if (p.show) {
182
- xml.leafNode("m:show", { "m:val": "1" });
181
+ // `m:show` defaults to ON in OOXML (the phantom base is still drawn). To
182
+ // make a phantom "occupy space but stay invisible" the producer must
183
+ // emit `<m:show m:val="0"/>` explicitly — simply omitting it leaves the
184
+ // content visible. So serialize `show` whenever it is defined, mapping
185
+ // false → "0" and true → "1".
186
+ if (p.show !== undefined) {
187
+ xml.leafNode("m:show", { "m:val": p.show ? "1" : "0" });
183
188
  }
184
189
  if (p.zeroWidth) {
185
190
  xml.leafNode("m:zeroWid", { "m:val": "1" });