@portone/docx-editor 0.3.0 → 0.5.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 (217) hide show
  1. package/CHANGELOG.md +205 -0
  2. package/assets/editor.png +0 -0
  3. package/dist/DocxEditor.d.ts +1 -1
  4. package/dist/DocxEditor.js +45 -25
  5. package/dist/core.d.ts +1 -1
  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 +78 -35
  20. package/dist/docx/exportDocx.js +30 -18
  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/attrs.d.ts +20 -2
  27. package/dist/docx/formatting/attrs.js +57 -2
  28. package/dist/docx/formatting/context.d.ts +10 -2
  29. package/dist/docx/formatting/context.js +23 -5
  30. package/dist/docx/formatting/resolve.d.ts +10 -4
  31. package/dist/docx/formatting/resolve.js +31 -11
  32. package/dist/docx/formatting/styles.d.ts +25 -2
  33. package/dist/docx/formatting/styles.js +84 -3
  34. package/dist/docx/headersFooters.d.ts +89 -20
  35. package/dist/docx/headersFooters.js +163 -172
  36. package/dist/docx/hyperlink.d.ts +14 -4
  37. package/dist/docx/hyperlink.js +4 -1
  38. package/dist/docx/importDocx.d.ts +1 -1
  39. package/dist/docx/importDocx.js +135 -74
  40. package/dist/docx/importParagraph.d.ts +16 -4
  41. package/dist/docx/importParagraph.js +87 -93
  42. package/dist/docx/importPolicy.d.ts +70 -0
  43. package/dist/docx/importPolicy.js +190 -0
  44. package/dist/docx/importPreserved.d.ts +30 -0
  45. package/dist/docx/importPreserved.js +54 -0
  46. package/dist/docx/importTable.d.ts +2 -2
  47. package/dist/docx/importTable.js +107 -66
  48. package/dist/docx/invariants.js +42 -31
  49. package/dist/docx/newLists.d.ts +30 -0
  50. package/dist/docx/newLists.js +24 -1
  51. package/dist/docx/notes.d.ts +6 -1
  52. package/dist/docx/notes.js +6 -16
  53. package/dist/docx/numberingPlanner.d.ts +6 -3
  54. package/dist/docx/numberingPlanner.js +38 -7
  55. package/dist/docx/pageGeometry.d.ts +5 -14
  56. package/dist/docx/pageGeometry.js +0 -12
  57. package/dist/docx/protectionPolicy.d.ts +13 -5
  58. package/dist/docx/protectionPolicy.js +32 -22
  59. package/dist/docx/scan.d.ts +18 -8
  60. package/dist/docx/scan.js +17 -11
  61. package/dist/docx/sections.d.ts +126 -0
  62. package/dist/docx/sections.js +207 -0
  63. package/dist/docx/serializeBlock.d.ts +13 -4
  64. package/dist/docx/serializeBlock.js +16 -18
  65. package/dist/docx/serializeParagraph.d.ts +4 -0
  66. package/dist/docx/serializeParagraph.js +1 -0
  67. package/dist/docx/serializePreserved.d.ts +14 -0
  68. package/dist/docx/serializePreserved.js +24 -0
  69. package/dist/docx/serializeStory.d.ts +17 -0
  70. package/dist/docx/serializeStory.js +17 -0
  71. package/dist/docx/serializeTable.js +10 -13
  72. package/dist/docx/session.d.ts +24 -7
  73. package/dist/docx/session.js +37 -6
  74. package/dist/docx/story.d.ts +140 -0
  75. package/dist/docx/story.js +237 -0
  76. package/dist/docx/storyProjection.js +6 -1
  77. package/dist/docx/tableFormatting/conditions.d.ts +76 -0
  78. package/dist/docx/tableFormatting/conditions.js +196 -0
  79. package/dist/docx/tableFormatting/editing.d.ts +7 -3
  80. package/dist/docx/tableFormatting/editing.js +4 -5
  81. package/dist/docx/tableFormatting/reading.d.ts +49 -19
  82. package/dist/docx/tableFormatting/reading.js +109 -35
  83. package/dist/docx/tableFormatting.d.ts +1 -0
  84. package/dist/docx/tableFormatting.js +1 -0
  85. package/dist/docx/tableTemplate.js +12 -12
  86. package/dist/editor/clipboard/htmlReader.d.ts +30 -0
  87. package/dist/editor/clipboard/htmlReader.js +302 -0
  88. package/dist/editor/clipboard/internalChannel.d.ts +57 -0
  89. package/dist/editor/clipboard/internalChannel.js +58 -0
  90. package/dist/editor/clipboard/normalizers.d.ts +99 -0
  91. package/dist/editor/clipboard/normalizers.js +199 -0
  92. package/dist/editor/clipboard/parser.d.ts +34 -0
  93. package/dist/editor/clipboard/parser.js +58 -0
  94. package/dist/editor/clipboard/plugin.d.ts +21 -0
  95. package/dist/editor/clipboard/plugin.js +320 -0
  96. package/dist/editor/clipboard/readContext.d.ts +24 -0
  97. package/dist/editor/clipboard/readContext.js +19 -0
  98. package/dist/editor/clipboard/readers.d.ts +33 -0
  99. package/dist/editor/clipboard/readers.js +37 -0
  100. package/dist/editor/commands/comments/editing.d.ts +26 -6
  101. package/dist/editor/commands/comments/editing.js +175 -105
  102. package/dist/editor/commands/comments/model.d.ts +34 -17
  103. package/dist/editor/commands/comments/model.js +11 -0
  104. package/dist/editor/commands/comments/reading.d.ts +5 -3
  105. package/dist/editor/commands/comments/reading.js +8 -58
  106. package/dist/editor/commands/formatting/propertyCommands.js +6 -1
  107. package/dist/editor/commands/index.d.ts +2 -2
  108. package/dist/editor/commands/index.js +2 -0
  109. package/dist/editor/commands/listCommands.d.ts +12 -3
  110. package/dist/editor/commands/listCommands.js +76 -30
  111. package/dist/editor/commands/noteQueries.d.ts +22 -5
  112. package/dist/editor/commands/noteQueries.js +34 -6
  113. package/dist/editor/commands/paragraphCommands.js +6 -1
  114. package/dist/editor/createEditor.js +14 -4
  115. package/dist/editor/documentStyles.d.ts +26 -4
  116. package/dist/editor/documentStyles.js +9 -4
  117. package/dist/editor/editorDocument.d.ts +7 -6
  118. package/dist/editor/editorDocument.js +18 -6
  119. package/dist/editor/imageFiles.d.ts +2 -2
  120. package/dist/editor/imageFiles.js +2 -0
  121. package/dist/editor/insertTable.d.ts +1 -1
  122. package/dist/editor/insertTable.js +2 -2
  123. package/dist/editor/paragraphEdits.d.ts +16 -1
  124. package/dist/editor/paragraphEdits.js +13 -5
  125. package/dist/editor/paragraphPlacement.d.ts +11 -0
  126. package/dist/editor/paragraphPlacement.js +18 -0
  127. package/dist/editor/plainText.d.ts +12 -0
  128. package/dist/editor/plainText.js +2 -1
  129. package/dist/editor/plugins/columnResize.js +6 -3
  130. package/dist/editor/plugins/commentComposer.d.ts +28 -0
  131. package/dist/editor/plugins/commentComposer.js +46 -0
  132. package/dist/editor/plugins/commentDecorations.d.ts +29 -2
  133. package/dist/editor/plugins/commentDecorations.js +89 -15
  134. package/dist/editor/plugins/documentProjection.d.ts +31 -0
  135. package/dist/editor/plugins/documentProjection.js +22 -0
  136. package/dist/editor/plugins/imagePaste.js +20 -10
  137. package/dist/editor/plugins/linkPanel.d.ts +7 -3
  138. package/dist/editor/plugins/linkPanel.js +13 -27
  139. package/dist/editor/plugins/numberingDecorations.d.ts +10 -4
  140. package/dist/editor/plugins/numberingDecorations.js +43 -2
  141. package/dist/editor/plugins/panelState.d.ts +67 -0
  142. package/dist/editor/plugins/panelState.js +54 -0
  143. package/dist/editor/plugins/paragraphDisplay.js +9 -3
  144. package/dist/editor/plugins/tableContextMenu.d.ts +1 -1
  145. package/dist/editor/plugins/tableContextMenu.js +30 -47
  146. package/dist/editor/plugins/tableDisplay.js +19 -5
  147. package/dist/editor/plugins/textContextMenu.d.ts +1 -1
  148. package/dist/editor/plugins/textContextMenu.js +30 -47
  149. package/dist/model/format.d.ts +50 -0
  150. package/dist/model/format.js +65 -0
  151. package/dist/numbering/listRegistry.d.ts +37 -0
  152. package/dist/numbering/listRegistry.js +112 -0
  153. package/dist/numbering/listTemplate.d.ts +26 -17
  154. package/dist/numbering/listTemplate.js +66 -20
  155. package/dist/numbering/markers.d.ts +15 -6
  156. package/dist/numbering/markers.js +26 -59
  157. package/dist/numbering/parseNumbering.d.ts +70 -5
  158. package/dist/numbering/parseNumbering.js +100 -26
  159. package/dist/numbering/spellers.d.ts +15 -0
  160. package/dist/numbering/spellers.js +96 -0
  161. package/dist/numbering/writeNumbering.d.ts +5 -3
  162. package/dist/numbering/writeNumbering.js +15 -15
  163. package/dist/ooxml/conformance.d.ts +28 -0
  164. package/dist/ooxml/conformance.js +20 -0
  165. package/dist/ooxml/errors.d.ts +5 -5
  166. package/dist/ooxml/fragment.d.ts +11 -0
  167. package/dist/ooxml/fragment.js +14 -4
  168. package/dist/ooxml/image.d.ts +3 -4
  169. package/dist/ooxml/image.js +50 -5
  170. package/dist/ooxml/names.d.ts +15 -0
  171. package/dist/ooxml/names.js +10 -1
  172. package/dist/ooxml/partSplice.d.ts +1 -1
  173. package/dist/ooxml/partSplice.js +10 -3
  174. package/dist/ooxml/props.d.ts +8 -0
  175. package/dist/ooxml/props.js +14 -4
  176. package/dist/ooxml/rangeMarkers.d.ts +5 -0
  177. package/dist/ooxml/rangeMarkers.js +24 -0
  178. package/dist/ooxml/xml.d.ts +8 -9
  179. package/dist/ooxml/xml.js +6 -6
  180. package/dist/page/PageGuides.d.ts +8 -4
  181. package/dist/page/PageGuides.js +13 -37
  182. package/dist/page/pageLayout.d.ts +62 -13
  183. package/dist/page/pageLayout.js +91 -37
  184. package/dist/page/usePageLayout.d.ts +14 -11
  185. package/dist/page/usePageLayout.js +21 -29
  186. package/dist/schema/attrRoles.js +44 -19
  187. package/dist/schema/docxSchema.d.ts +9 -1
  188. package/dist/schema/docxSchema.js +220 -139
  189. package/dist/schema/editGuard.d.ts +1 -1
  190. package/dist/schema/guards.js +2 -2
  191. package/dist/schema/index.d.ts +1 -0
  192. package/dist/schema/preservedFragments.d.ts +12 -0
  193. package/dist/schema/preservedFragments.js +38 -0
  194. package/dist/schema/preservedGuards.d.ts +9 -7
  195. package/dist/schema/preservedGuards.js +112 -11
  196. package/dist/schema/protection.d.ts +34 -5
  197. package/dist/schema/protection.js +42 -14
  198. package/dist/schema/rendering.js +3 -1
  199. package/dist/schema/stories.d.ts +49 -0
  200. package/dist/schema/stories.js +78 -0
  201. package/dist/styles/classNames.d.ts +16 -7
  202. package/dist/styles/classNames.js +16 -7
  203. package/dist/styles.css +90 -30
  204. package/dist/table/cellFormatting.js +1 -2
  205. package/dist/table/gridBorders.d.ts +11 -15
  206. package/dist/table/gridBorders.js +32 -18
  207. package/dist/table/resize.d.ts +5 -3
  208. package/dist/ui/CommentsPanel.d.ts +1 -3
  209. package/dist/ui/CommentsPanel.js +24 -15
  210. package/dist/ui/NotesPanel.js +2 -2
  211. package/dist/ui/TextMenu.d.ts +1 -3
  212. package/dist/ui/TextMenu.js +10 -6
  213. package/dist/ui/comments/CommentComposer.d.ts +6 -1
  214. package/dist/ui/comments/CommentComposer.js +26 -3
  215. package/package.json +1 -1
  216. package/dist/editor/externalClipboard.d.ts +0 -11
  217. package/dist/editor/externalClipboard.js +0 -456
@@ -1,7 +1,10 @@
1
1
  // src/schema/docxSchema.ts
2
- import { Schema } from "prosemirror-model";
2
+ import {
3
+ Schema
4
+ } from "prosemirror-model";
3
5
  import {
4
6
  spanCount,
7
+ toBandSizes,
5
8
  toCellFormat,
6
9
  toCellMargins,
7
10
  toColWidth,
@@ -11,10 +14,12 @@ import {
11
14
  toRowFormat,
12
15
  toRunFormat,
13
16
  toTableFormat,
17
+ toTableStyleConditions,
14
18
  toTableWidth
15
19
  } from "../model/format.js";
16
20
  import {
17
21
  ANY_ELEMENT,
22
+ ANY_ELEMENTS,
18
23
  ATTRIBUTES,
19
24
  acceptRawXml,
20
25
  ELEMENT
@@ -31,6 +36,7 @@ import {
31
36
  } from "../styles/inlineStyle.js";
32
37
  import { imageNodeSpec, runMarkSpec } from "./rendering.js";
33
38
  import { imageNodeSpec as imageNodeSpec2, runMarkSpec as runMarkSpec2 } from "./rendering.js";
39
+ var NO_STORIES = Object.freeze({});
34
40
  function isRecord(value) {
35
41
  return typeof value === "object" && value !== null;
36
42
  }
@@ -76,7 +82,7 @@ function repliesHoldTheirXml(value) {
76
82
  const replies = value;
77
83
  return replies.every((reply) => {
78
84
  if (!isRecord(reply)) return true;
79
- return acceptRawXml(ELEMENT("comment"), text(reply.commentXml) ?? null) !== false && acceptRawXml(ANY_ELEMENT, text(reply.extensionXml) ?? null) !== false;
85
+ return acceptRawXml(ANY_ELEMENT, text(reply.extensionXml) ?? null) !== false;
80
86
  });
81
87
  }
82
88
  var SDT_PREFIX = {
@@ -94,25 +100,90 @@ var LINK_PREFIX = {
94
100
  function rawXml(dom, attribute, shape) {
95
101
  return acceptRawXml(shape, dom.getAttribute(attribute));
96
102
  }
103
+ function preservedDisplayOf(value) {
104
+ switch (value) {
105
+ case "text":
106
+ return "text";
107
+ case "break":
108
+ return "break";
109
+ case "chip":
110
+ return "chip";
111
+ default:
112
+ return "hidden";
113
+ }
114
+ }
115
+ function preservedAttributes(node, className) {
116
+ return {
117
+ class: className,
118
+ "data-xml": text(node.attrs.xml),
119
+ "data-element": text(node.attrs.element),
120
+ "data-display": preservedDisplayOf(node.attrs.display),
121
+ "data-text": text(node.attrs.text),
122
+ "data-guarded": node.attrs.guarded === true ? "1" : void 0
123
+ };
124
+ }
125
+ function preservedDom(node, className) {
126
+ const attributes = preservedAttributes(node, className);
127
+ const display = preservedDisplayOf(node.attrs.display);
128
+ const preview = text(node.attrs.text);
129
+ const element = text(node.attrs.element);
130
+ if (display === "break") return ["span", attributes, ["br"]];
131
+ if (display === "text") return ["span", attributes, preview ?? ""];
132
+ if (display === "chip") {
133
+ return [
134
+ "span",
135
+ { ...attributes, title: element ?? UNKNOWN_PLACEHOLDER },
136
+ preview !== void 0 && preview !== "" ? preview : element ?? "?"
137
+ ];
138
+ }
139
+ return ["span", attributes];
140
+ }
141
+ function preservedAttrs(dom) {
142
+ const xml = rawXml(dom, "data-xml", ANY_ELEMENT);
143
+ if (xml === false) return false;
144
+ return {
145
+ xml,
146
+ element: dom.getAttribute("data-element"),
147
+ display: preservedDisplayOf(dom.getAttribute("data-display")),
148
+ text: dom.getAttribute("data-text"),
149
+ guarded: dom.getAttribute("data-guarded") === "1"
150
+ };
151
+ }
97
152
  var TABLE_PLACEHOLDER = "Table (unsupported layout, original is preserved)";
98
153
  var UNKNOWN_PLACEHOLDER = "Unsupported content (not editable, original is preserved)";
99
154
  var TABLE_NAMES = ["w:tbl", "tbl"];
100
- function rawBlockDom(name) {
101
- if (name !== void 0 && TABLE_NAMES.includes(name)) {
102
- return {
103
- className: editorClassNames.tablePlaceholder,
104
- label: TABLE_PLACEHOLDER
105
- };
106
- }
107
- return { className: editorClassNames.rawBlock, label: UNKNOWN_PLACEHOLDER };
155
+ function placeholderLabel(name) {
156
+ return name !== void 0 && TABLE_NAMES.includes(name) ? TABLE_PLACEHOLDER : UNKNOWN_PLACEHOLDER;
157
+ }
158
+ function preservedNameOf(dom) {
159
+ const name = dom.getAttribute("data-name");
160
+ return name === null || name === "" ? null : name;
108
161
  }
109
- var DOCX_RAW_SELECTOR = [
110
- editorClassNames.rawBlock,
111
- editorClassNames.tablePlaceholder
112
- ].map((className) => `div[data-src].${className}`).join(", ");
113
162
  var docxSchema = new Schema({
114
163
  nodes: {
115
- doc: { content: "block+" },
164
+ doc: {
165
+ content: "block+",
166
+ attrs: {
167
+ /**
168
+ * The definitions of the lists started while editing, which the export writes into
169
+ * numbering.xml. Read back through `numbering/listRegistry`.
170
+ */
171
+ newLists: { default: null },
172
+ /**
173
+ * The section properties that close the body: the paper the document's last section is
174
+ * written on, its headers and its page numbering (§17.6.18). Held as the fragment the
175
+ * document wrote, so an untouched document goes back out as the bytes it arrived as.
176
+ * Read through `docx/sections`.
177
+ */
178
+ sectPr: { default: null },
179
+ /**
180
+ * What each side story - a comment's body, a footnote's - currently says, under the key
181
+ * naming it (`./stories`). Read and written through `docx/story`; it never reaches the
182
+ * DOM, so a copy out of the editor carries none of it.
183
+ */
184
+ stories: { default: NO_STORIES }
185
+ }
186
+ },
116
187
  paragraph: {
117
188
  group: "block modelled",
118
189
  content: "inline*",
@@ -202,7 +273,21 @@ var docxSchema = new Schema({
202
273
  /** The lines between cells the table style laid down, so an edit can derive them again */
203
274
  styleInside: { default: null },
204
275
  /** The cell margins the table style laid down, carried along for the same reason */
205
- styleCellMargins: { default: null }
276
+ styleCellMargins: { default: null },
277
+ /**
278
+ * What the table style dresses each part of a table with (`w:tblStylePr`), by the part it
279
+ * covers. Which of them a cell takes is worked out from where it sits and the table's own
280
+ * `w:tblLook`, so an edit that moves the grid derives them again
281
+ */
282
+ styleConditions: { default: null },
283
+ /** How many rows and columns one band of the table style is made of */
284
+ styleBands: { default: null },
285
+ /**
286
+ * The markers that stood between this table's rows: the ones ahead of the first row
287
+ * (`docx/importTable`). They are invisible and belong to no row, so they ride along on
288
+ * the table and go back where they stood
289
+ */
290
+ leadingXml: { default: null }
206
291
  },
207
292
  toDOM(node) {
208
293
  const format = toTableFormat(node.attrs.format);
@@ -223,7 +308,12 @@ var docxSchema = new Schema({
223
308
  ),
224
309
  "data-style-margins": formatJson(
225
310
  toCellMargins(node.attrs.styleCellMargins)
226
- )
311
+ ),
312
+ "data-style-conditions": formatJson(
313
+ toTableStyleConditions(node.attrs.styleConditions)
314
+ ),
315
+ "data-style-bands": formatJson(toBandSizes(node.attrs.styleBands)),
316
+ "data-leading": text(node.attrs.leadingXml)
227
317
  };
228
318
  const body = ["tbody", 0];
229
319
  if (gridCols.length === 0) return ["table", attrs, body];
@@ -246,7 +336,8 @@ var docxSchema = new Schema({
246
336
  "data-gridchange",
247
337
  ELEMENT("tblGridChange")
248
338
  );
249
- if (tblAttrs === false || tblPr === false || gridChange === false) {
339
+ const leadingXml = rawXml(dom, "data-leading", ANY_ELEMENTS);
340
+ if (tblAttrs === false || tblPr === false || gridChange === false || leadingXml === false) {
250
341
  return false;
251
342
  }
252
343
  return {
@@ -262,7 +353,14 @@ var docxSchema = new Schema({
262
353
  ),
263
354
  styleCellMargins: toCellMargins(
264
355
  parseJson(dom.getAttribute("data-style-margins"))
265
- )
356
+ ),
357
+ styleConditions: toTableStyleConditions(
358
+ parseJson(dom.getAttribute("data-style-conditions"))
359
+ ),
360
+ styleBands: toBandSizes(
361
+ parseJson(dom.getAttribute("data-style-bands"))
362
+ ),
363
+ leadingXml
266
364
  };
267
365
  }
268
366
  }
@@ -278,7 +376,11 @@ var docxSchema = new Schema({
278
376
  tblPrEx: { default: null },
279
377
  /** The whole `<w:trPr>...</w:trPr>` XML */
280
378
  trPr: { default: null },
281
- format: { default: null }
379
+ format: { default: null },
380
+ /** The markers that stood ahead of this row's first cell (`docx/importTable`) */
381
+ leadingXml: { default: null },
382
+ /** The markers that stood between this row and the next one, under the table */
383
+ trailingXml: { default: null }
282
384
  },
283
385
  toDOM(node) {
284
386
  const format = toRowFormat(node.attrs.format);
@@ -290,7 +392,9 @@ var docxSchema = new Schema({
290
392
  "data-trattrs": text(node.attrs.trAttrs),
291
393
  "data-tblprex": text(node.attrs.tblPrEx),
292
394
  "data-trpr": text(node.attrs.trPr),
293
- "data-fmt": formatJson(format)
395
+ "data-fmt": formatJson(format),
396
+ "data-leading": text(node.attrs.leadingXml),
397
+ "data-trailing": text(node.attrs.trailingXml)
294
398
  },
295
399
  0
296
400
  ];
@@ -302,14 +406,18 @@ var docxSchema = new Schema({
302
406
  const trAttrs = rawXml(dom, "data-trattrs", ATTRIBUTES);
303
407
  const tblPrEx = rawXml(dom, "data-tblprex", ELEMENT("tblPrEx"));
304
408
  const trPr = rawXml(dom, "data-trpr", ELEMENT("trPr"));
305
- if (trAttrs === false || tblPrEx === false || trPr === false) {
409
+ const leadingXml = rawXml(dom, "data-leading", ANY_ELEMENTS);
410
+ const trailingXml = rawXml(dom, "data-trailing", ANY_ELEMENTS);
411
+ if (trAttrs === false || tblPrEx === false || trPr === false || leadingXml === false || trailingXml === false) {
306
412
  return false;
307
413
  }
308
414
  return {
309
415
  trAttrs,
310
416
  tblPrEx,
311
417
  trPr,
312
- format: toRowFormat(parseJson(dom.getAttribute("data-fmt")))
418
+ format: toRowFormat(parseJson(dom.getAttribute("data-fmt"))),
419
+ leadingXml,
420
+ trailingXml
313
421
  };
314
422
  }
315
423
  }
@@ -343,7 +451,9 @@ var docxSchema = new Schema({
343
451
  * the lock lives inside that very XML.
344
452
  */
345
453
  sdtContentsLocked: { default: false },
346
- sdtDeletionLocked: { default: false }
454
+ sdtDeletionLocked: { default: false },
455
+ /** The markers that stood between this cell and the next one, under the row */
456
+ trailingXml: { default: null }
347
457
  },
348
458
  toDOM(node) {
349
459
  const format = toCellFormat(node.attrs.format);
@@ -365,7 +475,8 @@ var docxSchema = new Schema({
365
475
  "data-fmt": formatJson(format),
366
476
  "data-sdt-prefix": text(node.attrs.sdtPrefix),
367
477
  "data-sdt-contents-locked": locked ? "1" : void 0,
368
- "data-sdt-deletion-locked": node.attrs.sdtDeletionLocked === true ? "1" : void 0
478
+ "data-sdt-deletion-locked": node.attrs.sdtDeletionLocked === true ? "1" : void 0,
479
+ "data-trailing": text(node.attrs.trailingXml)
369
480
  },
370
481
  0
371
482
  ];
@@ -377,7 +488,8 @@ var docxSchema = new Schema({
377
488
  const tcAttrs = rawXml(dom, "data-tcattrs", ATTRIBUTES);
378
489
  const tcPr = rawXml(dom, "data-tcpr", ELEMENT("tcPr"));
379
490
  const sdtPrefix = rawXml(dom, "data-sdt-prefix", SDT_PREFIX);
380
- if (tcAttrs === false || tcPr === false || sdtPrefix === false) {
491
+ const trailingXml = rawXml(dom, "data-trailing", ANY_ELEMENTS);
492
+ if (tcAttrs === false || tcPr === false || sdtPrefix === false || trailingXml === false) {
381
493
  return false;
382
494
  }
383
495
  return {
@@ -392,109 +504,68 @@ var docxSchema = new Schema({
392
504
  format: toCellFormat(parseJson(dom.getAttribute("data-fmt"))),
393
505
  sdtPrefix,
394
506
  sdtContentsLocked: dom.getAttribute("data-sdt-contents-locked") === "1",
395
- sdtDeletionLocked: dom.getAttribute("data-sdt-deletion-locked") === "1"
507
+ sdtDeletionLocked: dom.getAttribute("data-sdt-deletion-locked") === "1",
508
+ trailingXml
396
509
  };
397
510
  }
398
511
  }
399
512
  ]
400
513
  },
401
514
  /**
402
- * The node that carries, as original XML, a block inside a table cell that we do
403
- * not model (a nested table, for instance).
404
- * Unlike a body block it has no original fragment number, so it carries its own
405
- * XML around with it.
515
+ * The one node a block the editor has no model for stands as, wherever it stood: under the
516
+ * body, or inside a table cell.
517
+ *
518
+ * Which of the two it came from is what it carries the original as. A body block is one of the
519
+ * fragments the session holds, so it names that fragment and the bytes go back out untouched;
520
+ * a block inside a cell was never a fragment of its own, so it carries its XML with it.
521
+ *
522
+ * `display` says whether anything of it is on screen. A range marker draws nothing - it stands
523
+ * between blocks and marks a spot rather than holding content - while a table nobody could take
524
+ * apart draws a box saying so.
406
525
  */
407
526
  rawBlock: {
408
527
  group: "block preserved",
409
528
  atom: true,
410
529
  selectable: false,
411
530
  attrs: {
531
+ /** The element, verbatim, for a block the session holds no fragment of */
412
532
  xml: { default: null },
533
+ /** The fragment of the session this block was opened from */
534
+ srcId: { default: null },
413
535
  /** The original element name (for example `w:tbl`) */
414
- name: { default: null }
536
+ name: { default: null },
537
+ display: { default: "chip" },
538
+ /** Whether the deletion guard answers for this block (`./preservedGuards`) */
539
+ guarded: { default: false }
415
540
  },
416
541
  toDOM(node) {
417
- return [
418
- "div",
419
- {
420
- class: `${editorClassNames.rawBlock} ${editorClassNames.rawXmlBlock}`,
421
- "data-xml": text(node.attrs.xml),
422
- "data-name": text(node.attrs.name)
423
- },
424
- UNKNOWN_PLACEHOLDER
425
- ];
542
+ const name = text(node.attrs.name);
543
+ const display = preservedDisplayOf(node.attrs.display);
544
+ const attributes = {
545
+ class: editorClassNames.rawBlock,
546
+ "data-xml": text(node.attrs.xml),
547
+ "data-src": text(node.attrs.srcId) ?? "",
548
+ "data-name": name ?? "",
549
+ "data-display": display,
550
+ "data-guarded": node.attrs.guarded === true ? "1" : void 0
551
+ };
552
+ if (display !== "chip") return ["div", attributes];
553
+ return ["div", attributes, placeholderLabel(name)];
426
554
  },
427
555
  parseDOM: [
428
556
  {
429
- tag: `div.${editorClassNames.rawXmlBlock}`,
557
+ tag: `div.${editorClassNames.rawBlock}[data-name]`,
430
558
  getAttrs: (dom) => {
431
559
  const xml = rawXml(dom, "data-xml", ANY_ELEMENT);
432
560
  if (xml === false) return false;
433
- return { xml, name: dom.getAttribute("data-name") };
434
- }
435
- }
436
- ]
437
- },
438
- /** The node that carries a non-paragraph body block (a table we could not model, sectPr, an unknown element) exactly as it came */
439
- docxRaw: {
440
- group: "block preserved",
441
- atom: true,
442
- selectable: false,
443
- attrs: {
444
- srcId: { default: null },
445
- /** The original element name (for example `w:tbl`) */
446
- name: { default: null }
447
- },
448
- toDOM(node) {
449
- const { className, label } = rawBlockDom(text(node.attrs.name));
450
- return [
451
- "div",
452
- {
453
- class: className,
454
- "data-src": text(node.attrs.srcId) ?? "",
455
- "data-name": text(node.attrs.name)
456
- },
457
- label
458
- ];
459
- },
460
- parseDOM: [
461
- {
462
- tag: DOCX_RAW_SELECTOR,
463
- getAttrs: (dom) => ({
464
- srcId: srcIdOf(dom),
465
- name: dom.getAttribute("data-name")
466
- })
467
- }
468
- ]
469
- },
470
- /** A bookmark range marker that occurs directly under w:body rather than inside a paragraph */
471
- bookmarkBlock: {
472
- group: "block preserved",
473
- atom: true,
474
- isolating: true,
475
- selectable: false,
476
- attrs: {
477
- srcId: { default: null },
478
- name: { default: null }
479
- },
480
- toDOM(node) {
481
- return [
482
- "div",
483
- {
484
- class: editorClassNames.bookmarkBlock,
485
- "data-src": text(node.attrs.srcId) ?? "",
486
- "data-name": text(node.attrs.name),
487
- hidden: "hidden"
561
+ return {
562
+ xml,
563
+ srcId: srcIdOf(dom),
564
+ name: preservedNameOf(dom),
565
+ display: preservedDisplayOf(dom.getAttribute("data-display")),
566
+ guarded: dom.getAttribute("data-guarded") === "1"
567
+ };
488
568
  }
489
- ];
490
- },
491
- parseDOM: [
492
- {
493
- tag: `div.${editorClassNames.bookmarkBlock}`,
494
- getAttrs: (dom) => ({
495
- srcId: srcIdOf(dom),
496
- name: dom.getAttribute("data-name")
497
- })
498
569
  }
499
570
  ]
500
571
  },
@@ -643,9 +714,6 @@ var docxSchema = new Schema({
643
714
  authorId: { default: null },
644
715
  initials: { default: null },
645
716
  date: { default: null },
646
- text: { default: "" },
647
- commentXml: { default: null },
648
- imported: { default: false },
649
717
  paraId: { default: null },
650
718
  resolved: { default: false },
651
719
  extensionXml: { default: null },
@@ -664,9 +732,6 @@ var docxSchema = new Schema({
664
732
  "data-comment-author-id": text(node.attrs.authorId),
665
733
  "data-comment-initials": text(node.attrs.initials),
666
734
  "data-comment-date": text(node.attrs.date),
667
- "data-comment-text": text(node.attrs.text),
668
- "data-comment-xml": text(node.attrs.commentXml),
669
- "data-comment-imported": node.attrs.imported === true ? "1" : void 0,
670
735
  "data-comment-para-id": text(node.attrs.paraId),
671
736
  "data-comment-resolved": node.attrs.resolved === true ? "1" : void 0,
672
737
  "data-comment-extension-xml": text(node.attrs.extensionXml),
@@ -684,18 +749,13 @@ var docxSchema = new Schema({
684
749
  "data-reference-xml",
685
750
  ELEMENT("commentReference")
686
751
  );
687
- const commentXml = rawXml(
688
- dom,
689
- "data-comment-xml",
690
- ELEMENT("comment")
691
- );
692
752
  const extensionXml = rawXml(
693
753
  dom,
694
754
  "data-comment-extension-xml",
695
755
  ANY_ELEMENT
696
756
  );
697
757
  const replies = parseJson(dom.getAttribute("data-comment-replies")) ?? [];
698
- if (referenceXml === false || commentXml === false || extensionXml === false || !repliesHoldTheirXml(replies)) {
758
+ if (referenceXml === false || extensionXml === false || !repliesHoldTheirXml(replies)) {
699
759
  return false;
700
760
  }
701
761
  return {
@@ -705,9 +765,6 @@ var docxSchema = new Schema({
705
765
  authorId: dom.getAttribute("data-comment-author-id"),
706
766
  initials: dom.getAttribute("data-comment-initials"),
707
767
  date: dom.getAttribute("data-comment-date"),
708
- text: dom.getAttribute("data-comment-text") ?? "",
709
- commentXml,
710
- imported: dom.getAttribute("data-comment-imported") === "1",
711
768
  paraId: dom.getAttribute("data-comment-para-id"),
712
769
  resolved: dom.getAttribute("data-comment-resolved") === "1",
713
770
  extensionXml,
@@ -728,14 +785,12 @@ var docxSchema = new Schema({
728
785
  kind: { default: "footnote" },
729
786
  id: { default: null },
730
787
  label: { default: "?" },
731
- text: { default: "" },
732
788
  customMarkFollows: { default: false },
733
789
  referenceXml: { default: null }
734
790
  },
735
791
  toDOM(node) {
736
792
  const kind = node.attrs.kind === "endnote" ? "Endnote" : "Footnote";
737
793
  const label = text(node.attrs.label) ?? "?";
738
- const body = text(node.attrs.text) ?? "";
739
794
  return [
740
795
  "sup",
741
796
  {
@@ -743,11 +798,9 @@ var docxSchema = new Schema({
743
798
  "data-note-kind": text(node.attrs.kind),
744
799
  "data-note-id": text(node.attrs.id),
745
800
  "data-note-label": label,
746
- "data-note-text": body,
747
801
  "data-custom-mark-follows": node.attrs.customMarkFollows === true ? "1" : void 0,
748
802
  "data-reference-xml": text(node.attrs.referenceXml),
749
- "aria-label": `${kind} ${label}`,
750
- title: body
803
+ "aria-label": `${kind} ${label}`
751
804
  },
752
805
  node.attrs.customMarkFollows === true ? "" : label
753
806
  ];
@@ -766,7 +819,6 @@ var docxSchema = new Schema({
766
819
  kind: dom.getAttribute("data-note-kind") === "endnote" ? "endnote" : "footnote",
767
820
  id: dom.getAttribute("data-note-id"),
768
821
  label: dom.getAttribute("data-note-label") ?? "?",
769
- text: dom.getAttribute("data-note-text") ?? "",
770
822
  customMarkFollows: dom.getAttribute("data-custom-mark-follows") === "1",
771
823
  referenceXml
772
824
  };
@@ -774,29 +826,58 @@ var docxSchema = new Schema({
774
826
  }
775
827
  ]
776
828
  },
829
+ /**
830
+ * One child of a run the editor has no node for, kept as the XML it came as.
831
+ *
832
+ * It wears the run mark, so it is written back inside the same `<w:r>` as the text beside it,
833
+ * which is where `EG_RunInnerContent` says it may stand.
834
+ */
835
+ rawRunContent: {
836
+ group: "inline",
837
+ inline: true,
838
+ atom: true,
839
+ marks: "run sdt link",
840
+ attrs: {
841
+ xml: { default: null },
842
+ /** The local name of the element, for example `fldChar` */
843
+ element: { default: null },
844
+ display: { default: "hidden" },
845
+ /** What a `text` display draws, and the preview a chip shows */
846
+ text: { default: null },
847
+ /** Whether the deletion guard answers for this fragment (`schema/preservedGuards`) */
848
+ guarded: { default: false }
849
+ },
850
+ toDOM(node) {
851
+ return preservedDom(node, editorClassNames.rawRunContent);
852
+ },
853
+ parseDOM: [
854
+ {
855
+ tag: `span.${editorClassNames.rawRunContent}`,
856
+ getAttrs: preservedAttrs
857
+ }
858
+ ]
859
+ },
777
860
  /** The node that carries a non-run element inside a paragraph (a bookmark, for instance) exactly as it came */
778
861
  rawInline: {
779
862
  group: "inline",
780
863
  inline: true,
781
864
  atom: true,
782
865
  marks: "sdt link",
783
- attrs: { xml: { default: null } },
866
+ attrs: {
867
+ xml: { default: null },
868
+ /** The local name of the element; `r` for a run with no content, kept whole */
869
+ element: { default: null },
870
+ display: { default: "hidden" },
871
+ text: { default: null },
872
+ guarded: { default: false }
873
+ },
784
874
  toDOM(node) {
785
- return [
786
- "span",
787
- {
788
- class: editorClassNames.rawInline,
789
- "data-xml": text(node.attrs.xml)
790
- }
791
- ];
875
+ return preservedDom(node, editorClassNames.rawInline);
792
876
  },
793
877
  parseDOM: [
794
878
  {
795
879
  tag: `span.${editorClassNames.rawInline}`,
796
- getAttrs: (dom) => {
797
- const xml = rawXml(dom, "data-xml", ANY_ELEMENT);
798
- return xml === false ? false : { xml };
799
- }
880
+ getAttrs: preservedAttrs
800
881
  }
801
882
  ]
802
883
  },
@@ -46,7 +46,7 @@ export type EditIntent =
46
46
  * against the places it puts that guard to the test, and a place naming a guard that no longer
47
47
  * stands has to be a mistake the compiler catches rather than an annotation answering for nothing.
48
48
  */
49
- export type EditGuardName = "protection" | "lock" | "bookmark" | "note" | "section";
49
+ export type EditGuardName = "protection" | "lock" | "preserved" | "note" | "section";
50
50
  /** What every guard answers, whichever of the two judgements it is written as */
51
51
  interface GuardCommon {
52
52
  readonly name: EditGuardName;
@@ -4,7 +4,7 @@ import {
4
4
  transactionReaches
5
5
  } from "./editGuard.js";
6
6
  import { lockGuard } from "./locks.js";
7
- import { bookmarkGuard, noteGuard, sectionGuard } from "./preservedGuards.js";
7
+ import { noteGuard, preservedGuard, sectionGuard } from "./preservedGuards.js";
8
8
  import {
9
9
  isCommentNode,
10
10
  protectionAllows
@@ -36,7 +36,7 @@ var protectionGuard = {
36
36
  var EDIT_GUARDS = [
37
37
  protectionGuard,
38
38
  lockGuard,
39
- bookmarkGuard,
39
+ preservedGuard,
40
40
  noteGuard,
41
41
  sectionGuard
42
42
  ];
@@ -1,4 +1,5 @@
1
1
  export type { AttrClass } from "./attrRoles";
2
2
  export { attrsOfClass } from "./attrRoles";
3
+ export type { PreservedDisplay } from "./docxSchema";
3
4
  export { docxSchema, isPageBreak } from "./docxSchema";
4
5
  export { imageNodeSpec, runMarkSpec } from "./rendering";
@@ -0,0 +1,12 @@
1
+ import type { Node as PMNode } from "prosemirror-model";
2
+ type MarkerAttr = "leadingXml" | "trailingXml";
3
+ /**
4
+ * Whether this node is content the editor keeps as it came rather than one it models.
5
+ *
6
+ * The block placeholder declares it as a group; the two inline ones cannot, since their group says
7
+ * where they may stand, so they are named here and asked for by name everywhere else.
8
+ */
9
+ export declare function isPreservedNode(node: PMNode): boolean;
10
+ /** Visit preserved XML in the order the writer places it around editable content. */
11
+ export declare function visitPreservedFragments(doc: PMNode, visit: (node: PMNode, pos: number, xml: string | null, attr?: MarkerAttr) => void): void;
12
+ export {};
@@ -0,0 +1,38 @@
1
+ // src/schema/preservedFragments.ts
2
+ function isPreservedNode(node) {
3
+ return node.type.name === "rawInline" || node.type.name === "rawRunContent" || node.type.isInGroup("preserved");
4
+ }
5
+ function visitPreservedFragments(doc, visit) {
6
+ const visitAttr = (node, pos, attr) => {
7
+ const xml = node.attrs[attr];
8
+ if (typeof xml === "string" && xml.length > 0) {
9
+ visit(node, pos, xml, attr);
10
+ }
11
+ };
12
+ const walk = (node, pos) => {
13
+ if (isPreservedNode(node)) {
14
+ visit(
15
+ node,
16
+ pos,
17
+ typeof node.attrs.xml === "string" ? node.attrs.xml : null
18
+ );
19
+ }
20
+ if (node.type.name === "table" || node.type.name === "tableRow") {
21
+ visitAttr(node, pos, "leadingXml");
22
+ }
23
+ node.forEach((child, offset) => {
24
+ walk(child, pos + 1 + offset);
25
+ });
26
+ if (node.type.name === "tableRow" || node.type.name === "tableCell") {
27
+ visitAttr(node, pos, "trailingXml");
28
+ }
29
+ };
30
+ doc.descendants((node, pos) => {
31
+ walk(node, pos);
32
+ return false;
33
+ });
34
+ }
35
+ export {
36
+ isPreservedNode,
37
+ visitPreservedFragments
38
+ };