@portone/docx-editor 0.4.0 → 0.5.1

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 (180) hide show
  1. package/CHANGELOG.md +201 -0
  2. package/CONTRIBUTING.md +2 -0
  3. package/assets/editor.png +0 -0
  4. package/dist/DocxEditor.d.ts +1 -1
  5. package/dist/DocxEditor.js +44 -25
  6. package/dist/docx/cloning.js +4 -9
  7. package/dist/docx/commentOnlyChange.d.ts +5 -3
  8. package/dist/docx/comments/grammar.d.ts +27 -10
  9. package/dist/docx/comments/grammar.js +18 -67
  10. package/dist/docx/comments/model.d.ts +5 -6
  11. package/dist/docx/comments/model.js +0 -9
  12. package/dist/docx/comments/parts.d.ts +16 -10
  13. package/dist/docx/comments/parts.js +65 -13
  14. package/dist/docx/comments/people.d.ts +11 -3
  15. package/dist/docx/comments/people.js +20 -6
  16. package/dist/docx/comments/policy.js +7 -1
  17. package/dist/docx/comments/reading.d.ts +4 -2
  18. package/dist/docx/comments/reading.js +1 -14
  19. package/dist/docx/comments/writing.js +65 -28
  20. package/dist/docx/exportDocx.js +10 -14
  21. package/dist/docx/exportRefs.d.ts +8 -3
  22. package/dist/docx/exportRefs.js +2 -1
  23. package/dist/docx/fidelity.js +24 -10
  24. package/dist/docx/fields.d.ts +42 -0
  25. package/dist/docx/fields.js +76 -0
  26. package/dist/docx/formatting/styles.d.ts +0 -2
  27. package/dist/docx/formatting/styles.js +2 -15
  28. package/dist/docx/headersFooters.d.ts +89 -20
  29. package/dist/docx/headersFooters.js +163 -172
  30. package/dist/docx/identities.js +17 -26
  31. package/dist/docx/importDocx.d.ts +1 -1
  32. package/dist/docx/importDocx.js +100 -48
  33. package/dist/docx/importParagraph.d.ts +18 -5
  34. package/dist/docx/importParagraph.js +75 -128
  35. package/dist/docx/importPolicy.d.ts +70 -0
  36. package/dist/docx/importPolicy.js +195 -0
  37. package/dist/docx/importPreserved.d.ts +30 -0
  38. package/dist/docx/importPreserved.js +54 -0
  39. package/dist/docx/importTable.js +56 -12
  40. package/dist/docx/invariants.js +16 -18
  41. package/dist/docx/notes.d.ts +6 -1
  42. package/dist/docx/notes.js +6 -16
  43. package/dist/docx/pageGeometry.d.ts +5 -14
  44. package/dist/docx/pageGeometry.js +0 -12
  45. package/dist/docx/protectionPolicy.d.ts +13 -5
  46. package/dist/docx/protectionPolicy.js +32 -22
  47. package/dist/docx/scan.d.ts +18 -8
  48. package/dist/docx/scan.js +17 -11
  49. package/dist/docx/sections.d.ts +126 -0
  50. package/dist/docx/sections.js +207 -0
  51. package/dist/docx/serializeBlock.d.ts +13 -4
  52. package/dist/docx/serializeBlock.js +16 -18
  53. package/dist/docx/serializeParagraph.d.ts +9 -4
  54. package/dist/docx/serializeParagraph.js +23 -58
  55. package/dist/docx/serializePreserved.d.ts +14 -0
  56. package/dist/docx/serializePreserved.js +24 -0
  57. package/dist/docx/serializeStory.d.ts +17 -0
  58. package/dist/docx/serializeStory.js +17 -0
  59. package/dist/docx/serializeTable.js +10 -13
  60. package/dist/docx/session.d.ts +23 -6
  61. package/dist/docx/session.js +26 -5
  62. package/dist/docx/story.d.ts +140 -0
  63. package/dist/docx/story.js +237 -0
  64. package/dist/docx/storyProjection.js +6 -1
  65. package/dist/docx/tableTemplate.d.ts +25 -0
  66. package/dist/docx/tableTemplate.js +30 -16
  67. package/dist/docx/wrappers.d.ts +67 -0
  68. package/dist/docx/wrappers.js +117 -0
  69. package/dist/editor/clipboard/blockReaders.d.ts +74 -0
  70. package/dist/editor/clipboard/blockReaders.js +193 -0
  71. package/dist/editor/clipboard/htmlReader.d.ts +26 -0
  72. package/dist/editor/clipboard/htmlReader.js +376 -0
  73. package/dist/editor/clipboard/inlineFormatting.d.ts +0 -7
  74. package/dist/editor/clipboard/inlineFormatting.js +1 -7
  75. package/dist/editor/clipboard/internalChannel.d.ts +57 -0
  76. package/dist/editor/clipboard/internalChannel.js +58 -0
  77. package/dist/editor/clipboard/normalizers.d.ts +99 -0
  78. package/dist/editor/clipboard/normalizers.js +199 -0
  79. package/dist/editor/clipboard/parser.d.ts +34 -0
  80. package/dist/editor/clipboard/parser.js +58 -0
  81. package/dist/editor/clipboard/plugin.d.ts +21 -0
  82. package/dist/editor/clipboard/plugin.js +188 -0
  83. package/dist/editor/clipboard/readContext.d.ts +34 -0
  84. package/dist/editor/clipboard/readContext.js +25 -0
  85. package/dist/editor/clipboard/readers.d.ts +33 -0
  86. package/dist/editor/clipboard/readers.js +37 -0
  87. package/dist/editor/clipboard/source.d.ts +12 -0
  88. package/dist/editor/clipboard/source.js +21 -0
  89. package/dist/editor/commands/comments/editing.d.ts +26 -6
  90. package/dist/editor/commands/comments/editing.js +177 -106
  91. package/dist/editor/commands/comments/model.d.ts +34 -17
  92. package/dist/editor/commands/comments/model.js +11 -0
  93. package/dist/editor/commands/comments/reading.d.ts +5 -3
  94. package/dist/editor/commands/comments/reading.js +8 -58
  95. package/dist/editor/commands/index.d.ts +2 -2
  96. package/dist/editor/commands/index.js +2 -0
  97. package/dist/editor/commands/linkCommands.js +20 -5
  98. package/dist/editor/commands/listCommands.d.ts +6 -0
  99. package/dist/editor/commands/listCommands.js +3 -2
  100. package/dist/editor/commands/lockCommands.js +59 -16
  101. package/dist/editor/commands/noteQueries.d.ts +22 -5
  102. package/dist/editor/commands/noteQueries.js +34 -6
  103. package/dist/editor/commands/paragraphCommands.js +2 -2
  104. package/dist/editor/createEditor.js +13 -3
  105. package/dist/editor/documentStyles.d.ts +26 -4
  106. package/dist/editor/documentStyles.js +9 -4
  107. package/dist/editor/imageFiles.d.ts +2 -2
  108. package/dist/editor/imageFiles.js +2 -0
  109. package/dist/editor/insertTable.d.ts +1 -1
  110. package/dist/editor/insertTable.js +2 -2
  111. package/dist/editor/plainText.d.ts +12 -0
  112. package/dist/editor/plainText.js +2 -1
  113. package/dist/editor/plugins/columnResize.js +6 -3
  114. package/dist/editor/plugins/commentComposer.d.ts +28 -0
  115. package/dist/editor/plugins/commentComposer.js +46 -0
  116. package/dist/editor/plugins/commentDecorations.d.ts +29 -2
  117. package/dist/editor/plugins/commentDecorations.js +89 -15
  118. package/dist/editor/plugins/documentProjection.d.ts +31 -0
  119. package/dist/editor/plugins/documentProjection.js +22 -0
  120. package/dist/editor/plugins/imagePaste.js +15 -8
  121. package/dist/editor/plugins/linkPanel.d.ts +7 -3
  122. package/dist/editor/plugins/linkPanel.js +13 -27
  123. package/dist/editor/plugins/panelState.d.ts +67 -0
  124. package/dist/editor/plugins/panelState.js +54 -0
  125. package/dist/editor/plugins/tableContextMenu.d.ts +1 -1
  126. package/dist/editor/plugins/tableContextMenu.js +30 -47
  127. package/dist/editor/plugins/textContextMenu.d.ts +1 -1
  128. package/dist/editor/plugins/textContextMenu.js +30 -47
  129. package/dist/ooxml/fragment.d.ts +11 -0
  130. package/dist/ooxml/fragment.js +14 -4
  131. package/dist/ooxml/image.d.ts +3 -4
  132. package/dist/ooxml/image.js +50 -5
  133. package/dist/ooxml/names.d.ts +6 -0
  134. package/dist/ooxml/names.js +2 -0
  135. package/dist/ooxml/props.d.ts +10 -0
  136. package/dist/ooxml/props.js +28 -4
  137. package/dist/ooxml/rangeMarkers.d.ts +5 -0
  138. package/dist/ooxml/rangeMarkers.js +24 -0
  139. package/dist/page/PageGuides.d.ts +7 -3
  140. package/dist/page/PageGuides.js +13 -24
  141. package/dist/page/pageLayout.d.ts +64 -5
  142. package/dist/page/pageLayout.js +90 -29
  143. package/dist/page/usePageLayout.d.ts +14 -4
  144. package/dist/page/usePageLayout.js +19 -20
  145. package/dist/schema/attrRoles.js +46 -23
  146. package/dist/schema/clipboard.d.ts +72 -0
  147. package/dist/schema/clipboard.js +288 -0
  148. package/dist/schema/docxSchema.d.ts +9 -1
  149. package/dist/schema/docxSchema.js +217 -165
  150. package/dist/schema/editGuard.d.ts +1 -1
  151. package/dist/schema/guards.js +2 -2
  152. package/dist/schema/index.d.ts +1 -0
  153. package/dist/schema/locks.d.ts +3 -0
  154. package/dist/schema/locks.js +29 -12
  155. package/dist/schema/preservedFragments.d.ts +12 -0
  156. package/dist/schema/preservedFragments.js +38 -0
  157. package/dist/schema/preservedGuards.d.ts +9 -7
  158. package/dist/schema/preservedGuards.js +112 -11
  159. package/dist/schema/protection.d.ts +34 -5
  160. package/dist/schema/protection.js +42 -14
  161. package/dist/schema/rendering.d.ts +14 -0
  162. package/dist/schema/rendering.js +27 -12
  163. package/dist/schema/stories.d.ts +49 -0
  164. package/dist/schema/stories.js +78 -0
  165. package/dist/schema/wrappers.d.ts +58 -0
  166. package/dist/schema/wrappers.js +77 -0
  167. package/dist/styles/classNames.d.ts +3 -5
  168. package/dist/styles/classNames.js +3 -5
  169. package/dist/styles.css +74 -12
  170. package/dist/table/resize.d.ts +5 -3
  171. package/dist/ui/CommentsPanel.d.ts +1 -3
  172. package/dist/ui/CommentsPanel.js +24 -15
  173. package/dist/ui/NotesPanel.js +2 -2
  174. package/dist/ui/TextMenu.d.ts +1 -3
  175. package/dist/ui/TextMenu.js +10 -6
  176. package/dist/ui/comments/CommentComposer.d.ts +6 -1
  177. package/dist/ui/comments/CommentComposer.js +26 -3
  178. package/package.json +5 -4
  179. package/dist/editor/externalClipboard.d.ts +0 -22
  180. package/dist/editor/externalClipboard.js +0 -486
@@ -0,0 +1,195 @@
1
+ // src/docx/importPolicy.ts
2
+ import { M_NS, W_NS } from "../ooxml/names.js";
3
+ import {
4
+ COMMENT_RANGE_MARKERS,
5
+ PERMISSION_MARKERS,
6
+ RANGE_MARKERS
7
+ } from "../ooxml/rangeMarkers.js";
8
+ import { WRAPPER_KINDS } from "./wrappers.js";
9
+ var MODEL = { tier: "model" };
10
+ var HIDDEN_MARKER = {
11
+ tier: "marker",
12
+ display: "hidden",
13
+ guarded: true
14
+ };
15
+ var IGNORABLE = {
16
+ tier: "ignorable",
17
+ display: "hidden",
18
+ guarded: false
19
+ };
20
+ function chip(tier) {
21
+ return { tier, display: "chip", guarded: false };
22
+ }
23
+ var RUN_CHIP = chip("runContent");
24
+ var INLINE_CHIP = chip("inline");
25
+ var BLOCK_CHIP = chip("block");
26
+ var FIELD_PIECE = {
27
+ tier: "runContent",
28
+ display: "chip",
29
+ guarded: true
30
+ };
31
+ function clarkName(el) {
32
+ return `{${el.namespaceURI ?? ""}}${el.localName}`;
33
+ }
34
+ function wml(localName) {
35
+ return `{${W_NS}}${localName}`;
36
+ }
37
+ function rules(entries) {
38
+ return new Map(
39
+ entries.flatMap(
40
+ ([names, policy]) => names.map((name) => [wml(name), policy])
41
+ )
42
+ );
43
+ }
44
+ var REVISION_CONTAINERS = ["ins", "del", "moveFrom", "moveTo"];
45
+ var MATH = [`{${M_NS}}oMath`, `{${M_NS}}oMathPara`];
46
+ var RUN_LEVEL = rules([
47
+ [["rPr", "t", "br", "tab", "drawing"], MODEL],
48
+ [["commentReference", "footnoteReference", "endnoteReference"], MODEL],
49
+ [["lastRenderedPageBreak"], IGNORABLE],
50
+ [["softHyphen"], { tier: "runContent", display: "hidden", guarded: false }],
51
+ [
52
+ ["noBreakHyphen"],
53
+ { tier: "runContent", display: "text", text: "\u2011", guarded: false }
54
+ ],
55
+ [["cr"], { tier: "runContent", display: "break", guarded: false }],
56
+ // §17.16.18: a complex field is the begin, the instruction and the end read in order, so a
57
+ // piece taken away leaves the rest saying something the file never said
58
+ [["fldChar", "instrText", "delInstrText"], FIELD_PIECE],
59
+ [
60
+ [
61
+ "sym",
62
+ "ptab",
63
+ "pgNum",
64
+ "pict",
65
+ "object",
66
+ "ruby",
67
+ "contentPart",
68
+ "annotationRef",
69
+ "footnoteRef",
70
+ "endnoteRef",
71
+ "separator",
72
+ "continuationSeparator",
73
+ "delText",
74
+ "dayShort",
75
+ "monthShort",
76
+ "yearShort",
77
+ "dayLong",
78
+ "monthLong",
79
+ "yearLong"
80
+ ],
81
+ RUN_CHIP
82
+ ]
83
+ ]);
84
+ var PARAGRAPH_CHILDREN = [
85
+ [RANGE_MARKERS, HIDDEN_MARKER],
86
+ [PERMISSION_MARKERS, HIDDEN_MARKER],
87
+ [["proofErr"], IGNORABLE],
88
+ [REVISION_CONTAINERS, INLINE_CHIP],
89
+ [["fldSimple", "smartTag", "customXml", "dir", "bdo", "subDoc"], INLINE_CHIP]
90
+ ];
91
+ var WRAPPER_ELEMENTS = WRAPPER_KINDS.map(
92
+ (kind) => kind.element
93
+ );
94
+ var PARAGRAPH_LEVEL = new Map([
95
+ ...rules([
96
+ [["pPr", "r"], MODEL],
97
+ [COMMENT_RANGE_MARKERS, MODEL],
98
+ ...PARAGRAPH_CHILDREN,
99
+ [WRAPPER_ELEMENTS, MODEL]
100
+ ]),
101
+ ...MATH.map((name) => [name, INLINE_CHIP])
102
+ ]);
103
+ var WRAPPER_LEVEL = new Map([
104
+ ...rules([
105
+ [["r"], MODEL],
106
+ [COMMENT_RANGE_MARKERS, MODEL],
107
+ ...PARAGRAPH_CHILDREN,
108
+ [WRAPPER_ELEMENTS, MODEL]
109
+ ]),
110
+ ...MATH.map((name) => [name, INLINE_CHIP])
111
+ ]);
112
+ var BLOCK_CHILDREN = [
113
+ [["p", "tbl"], MODEL],
114
+ [RANGE_MARKERS, HIDDEN_MARKER],
115
+ [COMMENT_RANGE_MARKERS, HIDDEN_MARKER],
116
+ [PERMISSION_MARKERS, HIDDEN_MARKER],
117
+ [["proofErr"], IGNORABLE],
118
+ [REVISION_CONTAINERS, BLOCK_CHIP],
119
+ [["sdt", "customXml", "altChunk"], BLOCK_CHIP]
120
+ ];
121
+ var BODY_LEVEL = new Map([
122
+ ...rules([...BLOCK_CHILDREN, [["sectPr"], BLOCK_CHIP]]),
123
+ ...MATH.map((name) => [name, BLOCK_CHIP])
124
+ ]);
125
+ var CELL_LEVEL = new Map([
126
+ ...rules([...BLOCK_CHILDREN, [["tcPr"], MODEL]]),
127
+ ...MATH.map((name) => [name, BLOCK_CHIP])
128
+ ]);
129
+ var TABLE_LEVEL = rules([
130
+ [["tblPr", "tblGrid", "tr"], MODEL],
131
+ [RANGE_MARKERS, HIDDEN_MARKER],
132
+ [COMMENT_RANGE_MARKERS, HIDDEN_MARKER],
133
+ [PERMISSION_MARKERS, HIDDEN_MARKER],
134
+ [["proofErr"], IGNORABLE]
135
+ ]);
136
+ var ROW_LEVEL = rules([
137
+ [["tblPrEx", "trPr", "tc", "sdt"], MODEL],
138
+ [RANGE_MARKERS, HIDDEN_MARKER],
139
+ [COMMENT_RANGE_MARKERS, HIDDEN_MARKER],
140
+ [PERMISSION_MARKERS, HIDDEN_MARKER],
141
+ [["proofErr"], IGNORABLE]
142
+ ]);
143
+ var WML_POLICY = {
144
+ r: RUN_LEVEL,
145
+ p: PARAGRAPH_LEVEL,
146
+ wrapper: WRAPPER_LEVEL,
147
+ body: BODY_LEVEL,
148
+ tc: CELL_LEVEL,
149
+ tbl: TABLE_LEVEL,
150
+ tr: ROW_LEVEL
151
+ };
152
+ var LEVEL_PRESERVATION = {
153
+ r: RUN_CHIP,
154
+ p: INLINE_CHIP,
155
+ wrapper: INLINE_CHIP,
156
+ body: BLOCK_CHIP,
157
+ tc: BLOCK_CHIP
158
+ };
159
+ function defaultPreservation(level) {
160
+ return LEVEL_PRESERVATION[level];
161
+ }
162
+ var LEVEL_DEFAULTS = {
163
+ ...LEVEL_PRESERVATION,
164
+ tbl: { tier: "demote" },
165
+ tr: { tier: "demote" }
166
+ };
167
+ function policyFor(el, level) {
168
+ return WML_POLICY[level].get(clarkName(el)) ?? LEVEL_DEFAULTS[level];
169
+ }
170
+ function runContentText(el) {
171
+ const policy = policyFor(el, "r");
172
+ if (policy.tier === "model") {
173
+ switch (el.localName) {
174
+ case "t":
175
+ return el.textContent ?? "";
176
+ case "tab":
177
+ return " ";
178
+ case "br":
179
+ return "\n";
180
+ // A drawing and the three annotation references draw something that is not text
181
+ default:
182
+ return null;
183
+ }
184
+ }
185
+ if (policy.tier === "demote") return null;
186
+ if (policy.display === "break") return "\n";
187
+ return policy.display === "text" ? policy.text ?? null : null;
188
+ }
189
+ export {
190
+ WML_POLICY,
191
+ clarkName,
192
+ defaultPreservation,
193
+ policyFor,
194
+ runContentText
195
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * One element kept exactly as it came, at whatever level of the document it stood.
3
+ *
4
+ * `./importPolicy` says what an element is worth keeping as; this is where that answer becomes a
5
+ * node. Every level has a node of its own - inside a run, beside the runs of a paragraph, and in
6
+ * the place of a block - so the three readers build them the same way and cannot drift apart in
7
+ * what a chip shows or which fragments a guard answers for.
8
+ */
9
+ import type { Mark, Node as PMNode } from "prosemirror-model";
10
+ import { type DemotionPolicy, type ElementPolicy, type PreservationRule, type PreservingLevel } from "./importPolicy";
11
+ /**
12
+ * The rule an element is kept under.
13
+ *
14
+ * The level's own narrowest preservation stands in wherever the table said `model` and the reader
15
+ * could not read the element after all, so a structure it could not take apart costs that element
16
+ * and no more.
17
+ */
18
+ export declare function preservationOf(policy: ElementPolicy | DemotionPolicy, level: PreservingLevel): PreservationRule;
19
+ /** One child of a run kept as it came, wearing the run mark so it goes back inside that run */
20
+ export declare function buildPreservedRunContent(el: Element, marks: readonly Mark[], rule: PreservationRule): PMNode;
21
+ /** One child of a paragraph, or of a wrapper inside it, kept as it came */
22
+ export declare function buildPreservedInline(el: Element, wrappers: readonly Mark[], rule: PreservationRule): PMNode;
23
+ /**
24
+ * One block kept as it came, standing where it stood.
25
+ *
26
+ * A body block is one of the fragments the session holds, so it names that fragment and the bytes
27
+ * it arrived as go back out untouched. A block inside a cell was never a fragment of its own, so
28
+ * it carries its XML along with it.
29
+ */
30
+ export declare function buildPreservedBlock(el: Element, srcId: string | null, level: "body" | "tc"): PMNode;
@@ -0,0 +1,54 @@
1
+ // src/docx/importPreserved.ts
2
+ import { serializeXml } from "../ooxml/xml.js";
3
+ import { docxSchema } from "../schema/index.js";
4
+ import {
5
+ defaultPreservation,
6
+ policyFor
7
+ } from "./importPolicy.js";
8
+ function preservedText(el, rule) {
9
+ if (rule.display === "text") return rule.text ?? null;
10
+ if (rule.display !== "chip") return null;
11
+ return el.textContent === "" ? null : el.textContent ?? null;
12
+ }
13
+ function preservedAttrs(el, rule) {
14
+ return {
15
+ xml: serializeXml(el),
16
+ element: el.localName,
17
+ display: rule.display,
18
+ text: preservedText(el, rule),
19
+ guarded: rule.guarded
20
+ };
21
+ }
22
+ function preservationOf(policy, level) {
23
+ return policy.tier === "model" || policy.tier === "demote" ? defaultPreservation(level) : policy;
24
+ }
25
+ function buildPreservedRunContent(el, marks, rule) {
26
+ return docxSchema.nodes.rawRunContent.create(
27
+ preservedAttrs(el, rule),
28
+ null,
29
+ marks
30
+ );
31
+ }
32
+ function buildPreservedInline(el, wrappers, rule) {
33
+ return docxSchema.nodes.rawInline.create(
34
+ preservedAttrs(el, rule),
35
+ null,
36
+ wrappers
37
+ );
38
+ }
39
+ function buildPreservedBlock(el, srcId, level) {
40
+ const rule = preservationOf(policyFor(el, level), level);
41
+ return docxSchema.nodes.rawBlock.create({
42
+ xml: srcId === null ? serializeXml(el) : null,
43
+ srcId,
44
+ name: el.nodeName,
45
+ display: rule.display,
46
+ guarded: rule.guarded
47
+ });
48
+ }
49
+ export {
50
+ buildPreservedBlock,
51
+ buildPreservedInline,
52
+ buildPreservedRunContent,
53
+ preservationOf
54
+ };
@@ -18,6 +18,8 @@ import {
18
18
  buildParagraph,
19
19
  NO_IMPORT_SOURCES
20
20
  } from "./importParagraph.js";
21
+ import { policyFor } from "./importPolicy.js";
22
+ import { buildPreservedBlock } from "./importPreserved.js";
21
23
  import { readSdtWrapper } from "./sdt.js";
22
24
  import {
23
25
  cellConditionsOf,
@@ -39,6 +41,13 @@ import {
39
41
  readTableWidth,
40
42
  tblStyleIdOf
41
43
  } from "./tableFormatting.js";
44
+ function isTransparent(el, level) {
45
+ const tier = policyFor(el, level).tier;
46
+ return tier === "marker" || tier === "ignorable";
47
+ }
48
+ function takeGathered(gathered) {
49
+ return gathered.length === 0 ? null : gathered.splice(0).join("");
50
+ }
42
51
  function readGridSpan(tcPr) {
43
52
  const value = tcPr ? childValue(tcPr, "gridSpan") : null;
44
53
  const parsed = value === null ? null : Number.parseInt(value, 10);
@@ -67,27 +76,45 @@ function readSdtCell(el) {
67
76
  }
68
77
  };
69
78
  }
79
+ function trailCell(cells, gathered) {
80
+ const xml = takeGathered(gathered);
81
+ if (xml === null) return true;
82
+ const last = cells.at(-1);
83
+ if (!last || last.vMerge === "continue") return false;
84
+ last.trailingXml = (last.trailingXml ?? "") + xml;
85
+ return true;
86
+ }
70
87
  function readRow(el) {
71
88
  const cells = [];
89
+ const gathered = [];
72
90
  let tblPrEx = null;
91
+ let leadingXml = null;
73
92
  for (const child of elementChildren(el)) {
74
93
  if (child.localName === "trPr") continue;
75
94
  if (child.localName === "tblPrEx") {
76
95
  tblPrEx = child;
77
96
  continue;
78
97
  }
98
+ if (isTransparent(child, "tr")) {
99
+ gathered.push(serializeXml(child));
100
+ continue;
101
+ }
79
102
  const sdt = child.localName === "sdt" ? readSdtCell(child) : null;
80
103
  if (!sdt && child.localName !== "tc") return null;
104
+ if (cells.length === 0) leadingXml = takeGathered(gathered);
105
+ else if (!trailCell(cells, gathered)) return null;
81
106
  const tc = sdt ? sdt.el : child;
82
107
  const tcPr = childByLocalName(tc, "tcPr");
83
108
  cells.push({
84
109
  el: tc,
85
110
  gridSpan: readGridSpan(tcPr),
86
111
  vMerge: readVerticalMerge(tcPr),
87
- control: sdt ? sdt.control : null
112
+ control: sdt ? sdt.control : null,
113
+ trailingXml: null
88
114
  });
89
115
  }
90
- return cells.length > 0 ? { el, tblPrEx, cells } : null;
116
+ if (cells.length === 0 || !trailCell(cells, gathered)) return null;
117
+ return { el, tblPrEx, cells, leadingXml, trailingXml: null };
91
118
  }
92
119
  function gridRevisionXml(grid) {
93
120
  const revision = childByLocalName(grid, "tblGridChange");
@@ -107,6 +134,8 @@ function readTableParts(el) {
107
134
  let tblGrid = null;
108
135
  let gridChange = null;
109
136
  const rows = [];
137
+ const gathered = [];
138
+ let leadingXml = null;
110
139
  for (const child of elementChildren(el)) {
111
140
  if (child.localName === "tblPr") {
112
141
  tblPr = child;
@@ -117,12 +146,22 @@ function readTableParts(el) {
117
146
  gridChange = gridRevisionXml(child);
118
147
  continue;
119
148
  }
149
+ if (isTransparent(child, "tbl")) {
150
+ gathered.push(serializeXml(child));
151
+ continue;
152
+ }
120
153
  if (child.localName !== "tr") return null;
121
154
  const row = readRow(child);
122
155
  if (!row) return null;
156
+ const previous = rows.at(-1);
157
+ if (previous) previous.trailingXml = takeGathered(gathered);
158
+ else leadingXml = takeGathered(gathered);
123
159
  rows.push(row);
124
160
  }
125
- return rows.length > 0 ? { tblPr, tblGrid, gridChange, rows } : null;
161
+ const last = rows.at(-1);
162
+ if (!last) return null;
163
+ last.trailingXml = takeGathered(gathered);
164
+ return { tblPr, tblGrid, gridChange, rows, leadingXml };
126
165
  }
127
166
  function resolveVerticalMerges(rows, width) {
128
167
  const drafts = [];
@@ -144,7 +183,8 @@ function resolveVerticalMerges(rows, width) {
144
183
  col,
145
184
  colspan: cell.gridSpan,
146
185
  rowspan: 1,
147
- control: cell.control
186
+ control: cell.control,
187
+ trailingXml: cell.trailingXml
148
188
  };
149
189
  rowDrafts.push(draft);
150
190
  if (cell.vMerge === "restart") next.set(col, draft);
@@ -167,13 +207,13 @@ function gridWidthOf(rows) {
167
207
  }
168
208
  function buildCellBlock(el, sources, context, placement) {
169
209
  if (el.localName === "p") {
170
- const paragraph = buildParagraph(el, null, sources);
171
- if (paragraph) return styledParagraph(paragraph, context, placement);
210
+ return styledParagraph(
211
+ buildParagraph(el, null, sources),
212
+ context,
213
+ placement
214
+ );
172
215
  }
173
- return docxSchema.nodes.rawBlock.create({
174
- xml: serializeXml(el),
175
- name: el.nodeName
176
- });
216
+ return buildPreservedBlock(el, null, "tc");
177
217
  }
178
218
  function cellRect(draft) {
179
219
  return {
@@ -203,7 +243,8 @@ function buildCell(draft, table, sources, context) {
203
243
  format: readCellFormat(tcPr, defaults),
204
244
  sdtPrefix: draft.control?.prefix ?? null,
205
245
  sdtContentsLocked: draft.control?.contentsLocked ?? false,
206
- sdtDeletionLocked: draft.control?.deletionLocked ?? false
246
+ sdtDeletionLocked: draft.control?.deletionLocked ?? false,
247
+ trailingXml: draft.trailingXml
207
248
  },
208
249
  blocks
209
250
  );
@@ -221,7 +262,9 @@ function buildRow(row, drafts, table, sources, context) {
221
262
  trAttrs: attrString(row.el),
222
263
  tblPrEx: row.tblPrEx ? serializeXml(row.tblPrEx) : null,
223
264
  trPr: trPr ? serializeXml(trPr) : null,
224
- format: readRowFormat(trPr)
265
+ format: readRowFormat(trPr),
266
+ leadingXml: row.leadingXml,
267
+ trailingXml: row.trailingXml
225
268
  },
226
269
  cells
227
270
  );
@@ -278,6 +321,7 @@ function buildTable(el, srcId, sources = NO_IMPORT_SOURCES, context = NO_FORMATT
278
321
  tblW: readTableWidth(parts.tblPr, "tblW"),
279
322
  gridCols,
280
323
  gridChange: parts.gridChange,
324
+ leadingXml: parts.leadingXml,
281
325
  ...tableStyleAttrs(parts.tblPr, context)
282
326
  },
283
327
  rows
@@ -6,6 +6,8 @@ import {
6
6
  W_NS,
7
7
  withXmlParser
8
8
  } from "../ooxml/xml.js";
9
+ import { visitPreservedFragments } from "../schema/preservedFragments.js";
10
+ import { unattributedCommentAuthors } from "../schema/protection.js";
9
11
  import {
10
12
  commentReferencesIn,
11
13
  commentsChanged,
@@ -24,30 +26,21 @@ import { identityProblems } from "./identities.js";
24
26
  import { insertedImageSrcs } from "./media.js";
25
27
  import { canDefineNewList, newNumIds, startedLists } from "./newLists.js";
26
28
  import { CONTENT_TYPES_PATH } from "./packageParts.js";
27
- import { lostOriginal } from "./serializeBlock.js";
29
+ import { lostOriginal } from "./serializePreserved.js";
28
30
  import {
29
31
  originalBlock,
30
32
  sessionOf
31
33
  } from "./session.js";
32
- function markerSourceOf(node, session) {
33
- if (node.type.name === "rawInline" || node.type.name === "rawBlock") {
34
- return typeof node.attrs.xml === "string" ? node.attrs.xml : null;
35
- }
36
- if (node.type.isInGroup("preserved")) {
37
- return originalBlock(node, session)?.xml ?? null;
38
- }
39
- return null;
40
- }
41
34
  var bookmarkPairs = {
42
35
  name: "bookmarkPairs",
43
36
  check(doc, session) {
44
37
  const problems = [];
45
38
  const open = /* @__PURE__ */ new Map();
46
39
  const used = /* @__PURE__ */ new Set();
47
- doc.descendants((node, pos) => {
48
- const source = markerSourceOf(node, session);
49
- if (source === null) return true;
50
- if (!source.includes("bookmark")) return true;
40
+ visitPreservedFragments(doc, (node, pos, xml) => {
41
+ const source = xml ?? originalBlock(node, session)?.xml ?? null;
42
+ if (source === null) return;
43
+ if (!source.includes("bookmark")) return;
51
44
  let root;
52
45
  try {
53
46
  root = parseXml(
@@ -59,7 +52,7 @@ var bookmarkPairs = {
59
52
  message: "preserved bookmark XML could not be parsed",
60
53
  pos
61
54
  });
62
- return true;
55
+ return;
63
56
  }
64
57
  for (const marker of Array.from(root.getElementsByTagName("*"))) {
65
58
  if (marker.namespaceURI !== W_NS || marker.localName !== "bookmarkStart" && marker.localName !== "bookmarkEnd")
@@ -91,7 +84,6 @@ var bookmarkPairs = {
91
84
  });
92
85
  }
93
86
  }
94
- return true;
95
87
  });
96
88
  for (const [id, pos] of open) {
97
89
  problems.push({
@@ -132,11 +124,16 @@ var tableGrids = {
132
124
  return problems;
133
125
  }
134
126
  };
127
+ var CARRIES_ITS_XML = /* @__PURE__ */ new Set([
128
+ "rawInline",
129
+ "rawRunContent"
130
+ ]);
135
131
  function lostOriginalOf(node, session) {
136
- if (node.type.name === "rawInline" || node.type.name === "rawBlock") {
132
+ if (CARRIES_ITS_XML.has(node.type.name)) {
137
133
  return typeof node.attrs.xml === "string" ? null : "a preserved element has lost its original XML";
138
134
  }
139
135
  if (node.type.isInGroup("preserved")) {
136
+ if (typeof node.attrs.xml === "string") return null;
140
137
  return originalBlock(node, session) ? null : lostOriginal(node, session);
141
138
  }
142
139
  return null;
@@ -191,7 +188,8 @@ function addsCommentsPart(doc, session) {
191
188
  return true;
192
189
  return bodyChanged && (peoplePart.pathIn(session) === null || session.comments.people.xml === null) && unrecordedAuthors(
193
190
  currentCommentBodies(references).values(),
194
- session.comments.people
191
+ session.comments.people,
192
+ unattributedCommentAuthors(session.comments.ordered)
195
193
  ).size > 0;
196
194
  }
197
195
  var mediaContentTypes = {
@@ -1,14 +1,19 @@
1
1
  /** Reads footnote and endnote bodies related from the main document story. */
2
2
  export type NoteKind = "footnote" | "endnote";
3
+ /**
4
+ * One entry of a notes part as it arrived. What the note says is a story of its own, held on the
5
+ * document node under `footnote:<id>` or `endnote:<id>` (`docx/story`).
6
+ */
3
7
  export interface ImportedNote {
4
8
  kind: NoteKind;
5
9
  id: string;
6
10
  label: string;
7
- text: string;
8
11
  type: string | null;
9
12
  }
10
13
  export interface ImportedNotePart {
11
14
  partPath: string | null;
15
+ /** The raw text of the part, which is what the note stories are sliced out of. null for none */
16
+ xml: string | null;
12
17
  ordered: readonly ImportedNote[];
13
18
  byId: ReadonlyMap<string, ImportedNote>;
14
19
  }
@@ -4,12 +4,12 @@ import {
4
4
  decodeUtf8,
5
5
  elementChildren,
6
6
  parseXml,
7
- R_NS,
8
- W_NS
7
+ R_NS
9
8
  } from "../ooxml/xml.js";
10
9
  import { relatedPartPath } from "./packageParts.js";
11
10
  var EMPTY_PART = {
12
11
  partPath: null,
12
+ xml: null,
13
13
  ordered: [],
14
14
  byId: /* @__PURE__ */ new Map()
15
15
  };
@@ -17,23 +17,13 @@ var NO_NOTES = {
17
17
  footnotes: EMPTY_PART,
18
18
  endnotes: EMPTY_PART
19
19
  };
20
- function inlineText(node) {
21
- if (node.localName === "t") return node.textContent ?? "";
22
- if (node.localName === "tab") return " ";
23
- if (node.localName === "br" || node.localName === "cr") return "\n";
24
- if (node.localName === "noBreakHyphen") return "\u2011";
25
- if (node.localName === "softHyphen") return "\xAD";
26
- return elementChildren(node).map(inlineText).join("");
27
- }
28
- function noteText(el) {
29
- return Array.from(el.getElementsByTagNameNS(W_NS, "p")).map(inlineText).join("\n");
30
- }
31
20
  function notePart(parts, mainPartPath, kind) {
32
21
  const partPath = relatedPartPath(parts, mainPartPath, `${R_NS}/${kind}s`);
33
22
  if (partPath === null) return EMPTY_PART;
34
23
  const bytes = parts.get(partPath);
35
24
  if (!bytes) return { ...EMPTY_PART, partPath };
36
- const root = parseXml(decodeUtf8(bytes).text).documentElement;
25
+ const xml = decodeUtf8(bytes).text;
26
+ const root = parseXml(xml).documentElement;
37
27
  const elements = elementChildren(root).filter((el) => el.localName === kind);
38
28
  const ordered = elements.flatMap((el) => {
39
29
  const id = attributeByLocalName(el, "id");
@@ -41,13 +31,13 @@ function notePart(parts, mainPartPath, kind) {
41
31
  const type = attributeByLocalName(el, "type");
42
32
  const regular = type === null || type === "normal";
43
33
  const label = regular ? "?" : "";
44
- return [{ kind, id, label, text: noteText(el), type }];
34
+ return [{ kind, id, label, type }];
45
35
  });
46
36
  const byId = /* @__PURE__ */ new Map();
47
37
  for (const note of ordered) {
48
38
  if (!byId.has(note.id)) byId.set(note.id, note);
49
39
  }
50
- return { partPath, ordered, byId };
40
+ return { partPath, xml, ordered, byId };
51
41
  }
52
42
  function readNotes(parts, mainPartPath) {
53
43
  return {
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * The paper a document is written on: its size and its margins.
3
3
  *
4
- * A document says so in the `w:sectPr` at the end of its body. The values are read for the screen
5
- * only: the `w:sectPr` itself rides out with the rest of the preserved tail, so what a document
4
+ * A document says so in a `w:sectPr`, one per section (`./sections`). The values are read for the
5
+ * screen only: the `w:sectPr` itself rides out as the text it arrived as, so what a document
6
6
  * declares is never rewritten from these numbers.
7
7
  *
8
8
  * Everything here is in twips (1/1440 inch), the unit `w:pgSz` and `w:pgMar` are written in.
@@ -35,6 +35,9 @@ export declare const A4_PORTRAIT: PageGeometry;
35
35
  /**
36
36
  * The geometry a `w:sectPr` element lays down, with anything it leaves unsaid taken from A4.
37
37
  *
38
+ * The reading is deliberately forgiving: it runs against a document already opened, and a
39
+ * `w:sectPr` that cannot be read is a reason to draw A4, never a reason to refuse the file.
40
+ *
38
41
  * `w:orient` is not applied on top of the size: Word writes the width and the height already
39
42
  * swapped for a landscape section, so honouring both would turn the paper back upright.
40
43
  */
@@ -63,15 +66,3 @@ export declare function bodyWidth(geometry: PageGeometry): BodyWidth;
63
66
  * It is what a caller with no document to ask still gets: 11906 - 1247 * 2 = 9412 dxa.
64
67
  */
65
68
  export declare const A4_BODY_WIDTH: BodyWidth;
66
- /**
67
- * The geometry of the first section of an already parsed body.
68
- *
69
- * A document may hold a `w:sectPr` per section, each with a paper of its own. The screen draws
70
- * one paper for the whole document, so the first section decides it; the rest ride out
71
- * untouched in their preserved blocks and are drawn on the first section's paper.
72
- * `site/content/docs/features.mdx` records that limit.
73
- *
74
- * The reading is deliberately forgiving: this runs against a document already opened, and a
75
- * `w:sectPr` we cannot read is a reason to draw A4, never a reason to refuse the file.
76
- */
77
- export declare function readBodyGeometry(body: Element): PageGeometry;
@@ -73,17 +73,6 @@ function bodyWidth(geometry) {
73
73
  return { twips, px: twipsToPx(twips) };
74
74
  }
75
75
  var A4_BODY_WIDTH = bodyWidth(A4_PORTRAIT);
76
- function readBodyGeometry(body) {
77
- return readPageGeometry(firstSectPrIn(body));
78
- }
79
- function firstSectPrIn(root) {
80
- const found = root.getElementsByTagName("w:sectPr").item(0);
81
- if (found) return found;
82
- for (const el of root.getElementsByTagName("*")) {
83
- if (el.localName === "sectPr") return el;
84
- }
85
- return null;
86
- }
87
76
  export {
88
77
  A4_BODY_WIDTH,
89
78
  A4_PORTRAIT,
@@ -91,7 +80,6 @@ export {
91
80
  bodyHeightTwips,
92
81
  bodyWidth,
93
82
  bodyWidthTwips,
94
- readBodyGeometry,
95
83
  readPageGeometry,
96
84
  twipsToPx
97
85
  };