@portone/docx-editor 0.4.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.
- package/CHANGELOG.md +159 -0
- package/assets/editor.png +0 -0
- package/dist/DocxEditor.d.ts +1 -1
- package/dist/DocxEditor.js +44 -25
- package/dist/docx/cloning.js +4 -9
- package/dist/docx/commentOnlyChange.d.ts +5 -3
- package/dist/docx/comments/grammar.d.ts +27 -10
- package/dist/docx/comments/grammar.js +18 -67
- package/dist/docx/comments/model.d.ts +5 -6
- package/dist/docx/comments/model.js +0 -9
- package/dist/docx/comments/parts.d.ts +16 -10
- package/dist/docx/comments/parts.js +65 -13
- package/dist/docx/comments/people.d.ts +11 -3
- package/dist/docx/comments/people.js +20 -6
- package/dist/docx/comments/policy.js +7 -1
- package/dist/docx/comments/reading.d.ts +4 -2
- package/dist/docx/comments/reading.js +1 -14
- package/dist/docx/comments/writing.js +65 -28
- package/dist/docx/exportDocx.js +10 -14
- package/dist/docx/exportRefs.d.ts +8 -3
- package/dist/docx/exportRefs.js +2 -1
- package/dist/docx/fidelity.js +24 -10
- package/dist/docx/fields.d.ts +42 -0
- package/dist/docx/fields.js +76 -0
- package/dist/docx/headersFooters.d.ts +89 -20
- package/dist/docx/headersFooters.js +163 -172
- package/dist/docx/importDocx.d.ts +1 -1
- package/dist/docx/importDocx.js +100 -48
- package/dist/docx/importParagraph.d.ts +16 -4
- package/dist/docx/importParagraph.js +87 -93
- package/dist/docx/importPolicy.d.ts +70 -0
- package/dist/docx/importPolicy.js +190 -0
- package/dist/docx/importPreserved.d.ts +30 -0
- package/dist/docx/importPreserved.js +54 -0
- package/dist/docx/importTable.js +56 -12
- package/dist/docx/invariants.js +16 -18
- package/dist/docx/notes.d.ts +6 -1
- package/dist/docx/notes.js +6 -16
- package/dist/docx/pageGeometry.d.ts +5 -14
- package/dist/docx/pageGeometry.js +0 -12
- package/dist/docx/protectionPolicy.d.ts +13 -5
- package/dist/docx/protectionPolicy.js +32 -22
- package/dist/docx/scan.d.ts +18 -8
- package/dist/docx/scan.js +17 -11
- package/dist/docx/sections.d.ts +126 -0
- package/dist/docx/sections.js +207 -0
- package/dist/docx/serializeBlock.d.ts +13 -4
- package/dist/docx/serializeBlock.js +16 -18
- package/dist/docx/serializeParagraph.d.ts +4 -0
- package/dist/docx/serializeParagraph.js +1 -0
- package/dist/docx/serializePreserved.d.ts +14 -0
- package/dist/docx/serializePreserved.js +24 -0
- package/dist/docx/serializeStory.d.ts +17 -0
- package/dist/docx/serializeStory.js +17 -0
- package/dist/docx/serializeTable.js +10 -13
- package/dist/docx/session.d.ts +23 -6
- package/dist/docx/session.js +26 -5
- package/dist/docx/story.d.ts +140 -0
- package/dist/docx/story.js +237 -0
- package/dist/docx/storyProjection.js +6 -1
- package/dist/editor/clipboard/htmlReader.d.ts +30 -0
- package/dist/editor/{externalClipboard.js → clipboard/htmlReader.js} +39 -223
- package/dist/editor/clipboard/internalChannel.d.ts +57 -0
- package/dist/editor/clipboard/internalChannel.js +58 -0
- package/dist/editor/clipboard/normalizers.d.ts +99 -0
- package/dist/editor/clipboard/normalizers.js +199 -0
- package/dist/editor/clipboard/parser.d.ts +34 -0
- package/dist/editor/clipboard/parser.js +58 -0
- package/dist/editor/clipboard/plugin.d.ts +21 -0
- package/dist/editor/clipboard/plugin.js +320 -0
- package/dist/editor/clipboard/readContext.d.ts +24 -0
- package/dist/editor/clipboard/readContext.js +19 -0
- package/dist/editor/clipboard/readers.d.ts +33 -0
- package/dist/editor/clipboard/readers.js +37 -0
- package/dist/editor/commands/comments/editing.d.ts +26 -6
- package/dist/editor/commands/comments/editing.js +175 -105
- package/dist/editor/commands/comments/model.d.ts +34 -17
- package/dist/editor/commands/comments/model.js +11 -0
- package/dist/editor/commands/comments/reading.d.ts +5 -3
- package/dist/editor/commands/comments/reading.js +8 -58
- package/dist/editor/commands/index.d.ts +2 -2
- package/dist/editor/commands/index.js +2 -0
- package/dist/editor/commands/listCommands.d.ts +6 -0
- package/dist/editor/commands/listCommands.js +3 -2
- package/dist/editor/commands/noteQueries.d.ts +22 -5
- package/dist/editor/commands/noteQueries.js +34 -6
- package/dist/editor/createEditor.js +13 -3
- package/dist/editor/documentStyles.d.ts +26 -4
- package/dist/editor/documentStyles.js +9 -4
- package/dist/editor/imageFiles.d.ts +2 -2
- package/dist/editor/imageFiles.js +2 -0
- package/dist/editor/insertTable.d.ts +1 -1
- package/dist/editor/insertTable.js +2 -2
- package/dist/editor/plainText.d.ts +12 -0
- package/dist/editor/plainText.js +2 -1
- package/dist/editor/plugins/columnResize.js +6 -3
- package/dist/editor/plugins/commentComposer.d.ts +28 -0
- package/dist/editor/plugins/commentComposer.js +46 -0
- package/dist/editor/plugins/commentDecorations.d.ts +29 -2
- package/dist/editor/plugins/commentDecorations.js +89 -15
- package/dist/editor/plugins/documentProjection.d.ts +31 -0
- package/dist/editor/plugins/documentProjection.js +22 -0
- package/dist/editor/plugins/imagePaste.js +15 -8
- package/dist/editor/plugins/linkPanel.d.ts +7 -3
- package/dist/editor/plugins/linkPanel.js +13 -27
- package/dist/editor/plugins/panelState.d.ts +67 -0
- package/dist/editor/plugins/panelState.js +54 -0
- package/dist/editor/plugins/tableContextMenu.d.ts +1 -1
- package/dist/editor/plugins/tableContextMenu.js +30 -47
- package/dist/editor/plugins/textContextMenu.d.ts +1 -1
- package/dist/editor/plugins/textContextMenu.js +30 -47
- package/dist/ooxml/fragment.d.ts +11 -0
- package/dist/ooxml/fragment.js +14 -4
- package/dist/ooxml/image.d.ts +3 -4
- package/dist/ooxml/image.js +50 -5
- package/dist/ooxml/names.d.ts +6 -0
- package/dist/ooxml/names.js +2 -0
- package/dist/ooxml/props.d.ts +8 -0
- package/dist/ooxml/props.js +14 -4
- package/dist/ooxml/rangeMarkers.d.ts +5 -0
- package/dist/ooxml/rangeMarkers.js +24 -0
- package/dist/page/PageGuides.d.ts +7 -3
- package/dist/page/PageGuides.js +13 -24
- package/dist/page/pageLayout.d.ts +64 -5
- package/dist/page/pageLayout.js +90 -29
- package/dist/page/usePageLayout.d.ts +14 -4
- package/dist/page/usePageLayout.js +19 -20
- package/dist/schema/attrRoles.js +38 -20
- package/dist/schema/docxSchema.d.ts +9 -1
- package/dist/schema/docxSchema.js +191 -139
- package/dist/schema/editGuard.d.ts +1 -1
- package/dist/schema/guards.js +2 -2
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/preservedFragments.d.ts +12 -0
- package/dist/schema/preservedFragments.js +38 -0
- package/dist/schema/preservedGuards.d.ts +9 -7
- package/dist/schema/preservedGuards.js +112 -11
- package/dist/schema/protection.d.ts +34 -5
- package/dist/schema/protection.js +42 -14
- package/dist/schema/rendering.js +3 -1
- package/dist/schema/stories.d.ts +49 -0
- package/dist/schema/stories.js +78 -0
- package/dist/styles/classNames.d.ts +3 -5
- package/dist/styles/classNames.js +3 -5
- package/dist/styles.css +74 -12
- package/dist/table/resize.d.ts +5 -3
- package/dist/ui/CommentsPanel.d.ts +1 -3
- package/dist/ui/CommentsPanel.js +24 -15
- package/dist/ui/NotesPanel.js +2 -2
- package/dist/ui/TextMenu.d.ts +1 -3
- package/dist/ui/TextMenu.js +10 -6
- package/dist/ui/comments/CommentComposer.d.ts +6 -1
- package/dist/ui/comments/CommentComposer.js +26 -3
- package/package.json +1 -1
- package/dist/editor/externalClipboard.d.ts +0 -22
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// src/schema/docxSchema.ts
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Schema
|
|
4
|
+
} from "prosemirror-model";
|
|
3
5
|
import {
|
|
4
6
|
spanCount,
|
|
5
7
|
toBandSizes,
|
|
@@ -17,6 +19,7 @@ import {
|
|
|
17
19
|
} from "../model/format.js";
|
|
18
20
|
import {
|
|
19
21
|
ANY_ELEMENT,
|
|
22
|
+
ANY_ELEMENTS,
|
|
20
23
|
ATTRIBUTES,
|
|
21
24
|
acceptRawXml,
|
|
22
25
|
ELEMENT
|
|
@@ -33,6 +36,7 @@ import {
|
|
|
33
36
|
} from "../styles/inlineStyle.js";
|
|
34
37
|
import { imageNodeSpec, runMarkSpec } from "./rendering.js";
|
|
35
38
|
import { imageNodeSpec as imageNodeSpec2, runMarkSpec as runMarkSpec2 } from "./rendering.js";
|
|
39
|
+
var NO_STORIES = Object.freeze({});
|
|
36
40
|
function isRecord(value) {
|
|
37
41
|
return typeof value === "object" && value !== null;
|
|
38
42
|
}
|
|
@@ -78,7 +82,7 @@ function repliesHoldTheirXml(value) {
|
|
|
78
82
|
const replies = value;
|
|
79
83
|
return replies.every((reply) => {
|
|
80
84
|
if (!isRecord(reply)) return true;
|
|
81
|
-
return acceptRawXml(
|
|
85
|
+
return acceptRawXml(ANY_ELEMENT, text(reply.extensionXml) ?? null) !== false;
|
|
82
86
|
});
|
|
83
87
|
}
|
|
84
88
|
var SDT_PREFIX = {
|
|
@@ -96,22 +100,65 @@ var LINK_PREFIX = {
|
|
|
96
100
|
function rawXml(dom, attribute, shape) {
|
|
97
101
|
return acceptRawXml(shape, dom.getAttribute(attribute));
|
|
98
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
|
+
}
|
|
99
152
|
var TABLE_PLACEHOLDER = "Table (unsupported layout, original is preserved)";
|
|
100
153
|
var UNKNOWN_PLACEHOLDER = "Unsupported content (not editable, original is preserved)";
|
|
101
154
|
var TABLE_NAMES = ["w:tbl", "tbl"];
|
|
102
|
-
function
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
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;
|
|
110
161
|
}
|
|
111
|
-
var DOCX_RAW_SELECTOR = [
|
|
112
|
-
editorClassNames.rawBlock,
|
|
113
|
-
editorClassNames.tablePlaceholder
|
|
114
|
-
].map((className) => `div[data-src].${className}`).join(", ");
|
|
115
162
|
var docxSchema = new Schema({
|
|
116
163
|
nodes: {
|
|
117
164
|
doc: {
|
|
@@ -121,7 +168,20 @@ var docxSchema = new Schema({
|
|
|
121
168
|
* The definitions of the lists started while editing, which the export writes into
|
|
122
169
|
* numbering.xml. Read back through `numbering/listRegistry`.
|
|
123
170
|
*/
|
|
124
|
-
newLists: { default: null }
|
|
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 }
|
|
125
185
|
}
|
|
126
186
|
},
|
|
127
187
|
paragraph: {
|
|
@@ -221,7 +281,13 @@ var docxSchema = new Schema({
|
|
|
221
281
|
*/
|
|
222
282
|
styleConditions: { default: null },
|
|
223
283
|
/** How many rows and columns one band of the table style is made of */
|
|
224
|
-
styleBands: { default: null }
|
|
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 }
|
|
225
291
|
},
|
|
226
292
|
toDOM(node) {
|
|
227
293
|
const format = toTableFormat(node.attrs.format);
|
|
@@ -246,7 +312,8 @@ var docxSchema = new Schema({
|
|
|
246
312
|
"data-style-conditions": formatJson(
|
|
247
313
|
toTableStyleConditions(node.attrs.styleConditions)
|
|
248
314
|
),
|
|
249
|
-
"data-style-bands": formatJson(toBandSizes(node.attrs.styleBands))
|
|
315
|
+
"data-style-bands": formatJson(toBandSizes(node.attrs.styleBands)),
|
|
316
|
+
"data-leading": text(node.attrs.leadingXml)
|
|
250
317
|
};
|
|
251
318
|
const body = ["tbody", 0];
|
|
252
319
|
if (gridCols.length === 0) return ["table", attrs, body];
|
|
@@ -269,7 +336,8 @@ var docxSchema = new Schema({
|
|
|
269
336
|
"data-gridchange",
|
|
270
337
|
ELEMENT("tblGridChange")
|
|
271
338
|
);
|
|
272
|
-
|
|
339
|
+
const leadingXml = rawXml(dom, "data-leading", ANY_ELEMENTS);
|
|
340
|
+
if (tblAttrs === false || tblPr === false || gridChange === false || leadingXml === false) {
|
|
273
341
|
return false;
|
|
274
342
|
}
|
|
275
343
|
return {
|
|
@@ -291,7 +359,8 @@ var docxSchema = new Schema({
|
|
|
291
359
|
),
|
|
292
360
|
styleBands: toBandSizes(
|
|
293
361
|
parseJson(dom.getAttribute("data-style-bands"))
|
|
294
|
-
)
|
|
362
|
+
),
|
|
363
|
+
leadingXml
|
|
295
364
|
};
|
|
296
365
|
}
|
|
297
366
|
}
|
|
@@ -307,7 +376,11 @@ var docxSchema = new Schema({
|
|
|
307
376
|
tblPrEx: { default: null },
|
|
308
377
|
/** The whole `<w:trPr>...</w:trPr>` XML */
|
|
309
378
|
trPr: { default: null },
|
|
310
|
-
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 }
|
|
311
384
|
},
|
|
312
385
|
toDOM(node) {
|
|
313
386
|
const format = toRowFormat(node.attrs.format);
|
|
@@ -319,7 +392,9 @@ var docxSchema = new Schema({
|
|
|
319
392
|
"data-trattrs": text(node.attrs.trAttrs),
|
|
320
393
|
"data-tblprex": text(node.attrs.tblPrEx),
|
|
321
394
|
"data-trpr": text(node.attrs.trPr),
|
|
322
|
-
"data-fmt": formatJson(format)
|
|
395
|
+
"data-fmt": formatJson(format),
|
|
396
|
+
"data-leading": text(node.attrs.leadingXml),
|
|
397
|
+
"data-trailing": text(node.attrs.trailingXml)
|
|
323
398
|
},
|
|
324
399
|
0
|
|
325
400
|
];
|
|
@@ -331,14 +406,18 @@ var docxSchema = new Schema({
|
|
|
331
406
|
const trAttrs = rawXml(dom, "data-trattrs", ATTRIBUTES);
|
|
332
407
|
const tblPrEx = rawXml(dom, "data-tblprex", ELEMENT("tblPrEx"));
|
|
333
408
|
const trPr = rawXml(dom, "data-trpr", ELEMENT("trPr"));
|
|
334
|
-
|
|
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) {
|
|
335
412
|
return false;
|
|
336
413
|
}
|
|
337
414
|
return {
|
|
338
415
|
trAttrs,
|
|
339
416
|
tblPrEx,
|
|
340
417
|
trPr,
|
|
341
|
-
format: toRowFormat(parseJson(dom.getAttribute("data-fmt")))
|
|
418
|
+
format: toRowFormat(parseJson(dom.getAttribute("data-fmt"))),
|
|
419
|
+
leadingXml,
|
|
420
|
+
trailingXml
|
|
342
421
|
};
|
|
343
422
|
}
|
|
344
423
|
}
|
|
@@ -372,7 +451,9 @@ var docxSchema = new Schema({
|
|
|
372
451
|
* the lock lives inside that very XML.
|
|
373
452
|
*/
|
|
374
453
|
sdtContentsLocked: { default: false },
|
|
375
|
-
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 }
|
|
376
457
|
},
|
|
377
458
|
toDOM(node) {
|
|
378
459
|
const format = toCellFormat(node.attrs.format);
|
|
@@ -394,7 +475,8 @@ var docxSchema = new Schema({
|
|
|
394
475
|
"data-fmt": formatJson(format),
|
|
395
476
|
"data-sdt-prefix": text(node.attrs.sdtPrefix),
|
|
396
477
|
"data-sdt-contents-locked": locked ? "1" : void 0,
|
|
397
|
-
"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)
|
|
398
480
|
},
|
|
399
481
|
0
|
|
400
482
|
];
|
|
@@ -406,7 +488,8 @@ var docxSchema = new Schema({
|
|
|
406
488
|
const tcAttrs = rawXml(dom, "data-tcattrs", ATTRIBUTES);
|
|
407
489
|
const tcPr = rawXml(dom, "data-tcpr", ELEMENT("tcPr"));
|
|
408
490
|
const sdtPrefix = rawXml(dom, "data-sdt-prefix", SDT_PREFIX);
|
|
409
|
-
|
|
491
|
+
const trailingXml = rawXml(dom, "data-trailing", ANY_ELEMENTS);
|
|
492
|
+
if (tcAttrs === false || tcPr === false || sdtPrefix === false || trailingXml === false) {
|
|
410
493
|
return false;
|
|
411
494
|
}
|
|
412
495
|
return {
|
|
@@ -421,109 +504,68 @@ var docxSchema = new Schema({
|
|
|
421
504
|
format: toCellFormat(parseJson(dom.getAttribute("data-fmt"))),
|
|
422
505
|
sdtPrefix,
|
|
423
506
|
sdtContentsLocked: dom.getAttribute("data-sdt-contents-locked") === "1",
|
|
424
|
-
sdtDeletionLocked: dom.getAttribute("data-sdt-deletion-locked") === "1"
|
|
507
|
+
sdtDeletionLocked: dom.getAttribute("data-sdt-deletion-locked") === "1",
|
|
508
|
+
trailingXml
|
|
425
509
|
};
|
|
426
510
|
}
|
|
427
511
|
}
|
|
428
512
|
]
|
|
429
513
|
},
|
|
430
514
|
/**
|
|
431
|
-
* The node
|
|
432
|
-
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
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.
|
|
435
525
|
*/
|
|
436
526
|
rawBlock: {
|
|
437
527
|
group: "block preserved",
|
|
438
528
|
atom: true,
|
|
439
529
|
selectable: false,
|
|
440
530
|
attrs: {
|
|
531
|
+
/** The element, verbatim, for a block the session holds no fragment of */
|
|
441
532
|
xml: { default: null },
|
|
533
|
+
/** The fragment of the session this block was opened from */
|
|
534
|
+
srcId: { default: null },
|
|
442
535
|
/** The original element name (for example `w:tbl`) */
|
|
443
|
-
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 }
|
|
444
540
|
},
|
|
445
541
|
toDOM(node) {
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
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)];
|
|
455
554
|
},
|
|
456
555
|
parseDOM: [
|
|
457
556
|
{
|
|
458
|
-
tag: `div.${editorClassNames.
|
|
557
|
+
tag: `div.${editorClassNames.rawBlock}[data-name]`,
|
|
459
558
|
getAttrs: (dom) => {
|
|
460
559
|
const xml = rawXml(dom, "data-xml", ANY_ELEMENT);
|
|
461
560
|
if (xml === false) return false;
|
|
462
|
-
return {
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
group: "block preserved",
|
|
470
|
-
atom: true,
|
|
471
|
-
selectable: false,
|
|
472
|
-
attrs: {
|
|
473
|
-
srcId: { default: null },
|
|
474
|
-
/** The original element name (for example `w:tbl`) */
|
|
475
|
-
name: { default: null }
|
|
476
|
-
},
|
|
477
|
-
toDOM(node) {
|
|
478
|
-
const { className, label } = rawBlockDom(text(node.attrs.name));
|
|
479
|
-
return [
|
|
480
|
-
"div",
|
|
481
|
-
{
|
|
482
|
-
class: className,
|
|
483
|
-
"data-src": text(node.attrs.srcId) ?? "",
|
|
484
|
-
"data-name": text(node.attrs.name)
|
|
485
|
-
},
|
|
486
|
-
label
|
|
487
|
-
];
|
|
488
|
-
},
|
|
489
|
-
parseDOM: [
|
|
490
|
-
{
|
|
491
|
-
tag: DOCX_RAW_SELECTOR,
|
|
492
|
-
getAttrs: (dom) => ({
|
|
493
|
-
srcId: srcIdOf(dom),
|
|
494
|
-
name: dom.getAttribute("data-name")
|
|
495
|
-
})
|
|
496
|
-
}
|
|
497
|
-
]
|
|
498
|
-
},
|
|
499
|
-
/** A bookmark range marker that occurs directly under w:body rather than inside a paragraph */
|
|
500
|
-
bookmarkBlock: {
|
|
501
|
-
group: "block preserved",
|
|
502
|
-
atom: true,
|
|
503
|
-
isolating: true,
|
|
504
|
-
selectable: false,
|
|
505
|
-
attrs: {
|
|
506
|
-
srcId: { default: null },
|
|
507
|
-
name: { default: null }
|
|
508
|
-
},
|
|
509
|
-
toDOM(node) {
|
|
510
|
-
return [
|
|
511
|
-
"div",
|
|
512
|
-
{
|
|
513
|
-
class: editorClassNames.bookmarkBlock,
|
|
514
|
-
"data-src": text(node.attrs.srcId) ?? "",
|
|
515
|
-
"data-name": text(node.attrs.name),
|
|
516
|
-
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
|
+
};
|
|
517
568
|
}
|
|
518
|
-
];
|
|
519
|
-
},
|
|
520
|
-
parseDOM: [
|
|
521
|
-
{
|
|
522
|
-
tag: `div.${editorClassNames.bookmarkBlock}`,
|
|
523
|
-
getAttrs: (dom) => ({
|
|
524
|
-
srcId: srcIdOf(dom),
|
|
525
|
-
name: dom.getAttribute("data-name")
|
|
526
|
-
})
|
|
527
569
|
}
|
|
528
570
|
]
|
|
529
571
|
},
|
|
@@ -672,9 +714,6 @@ var docxSchema = new Schema({
|
|
|
672
714
|
authorId: { default: null },
|
|
673
715
|
initials: { default: null },
|
|
674
716
|
date: { default: null },
|
|
675
|
-
text: { default: "" },
|
|
676
|
-
commentXml: { default: null },
|
|
677
|
-
imported: { default: false },
|
|
678
717
|
paraId: { default: null },
|
|
679
718
|
resolved: { default: false },
|
|
680
719
|
extensionXml: { default: null },
|
|
@@ -693,9 +732,6 @@ var docxSchema = new Schema({
|
|
|
693
732
|
"data-comment-author-id": text(node.attrs.authorId),
|
|
694
733
|
"data-comment-initials": text(node.attrs.initials),
|
|
695
734
|
"data-comment-date": text(node.attrs.date),
|
|
696
|
-
"data-comment-text": text(node.attrs.text),
|
|
697
|
-
"data-comment-xml": text(node.attrs.commentXml),
|
|
698
|
-
"data-comment-imported": node.attrs.imported === true ? "1" : void 0,
|
|
699
735
|
"data-comment-para-id": text(node.attrs.paraId),
|
|
700
736
|
"data-comment-resolved": node.attrs.resolved === true ? "1" : void 0,
|
|
701
737
|
"data-comment-extension-xml": text(node.attrs.extensionXml),
|
|
@@ -713,18 +749,13 @@ var docxSchema = new Schema({
|
|
|
713
749
|
"data-reference-xml",
|
|
714
750
|
ELEMENT("commentReference")
|
|
715
751
|
);
|
|
716
|
-
const commentXml = rawXml(
|
|
717
|
-
dom,
|
|
718
|
-
"data-comment-xml",
|
|
719
|
-
ELEMENT("comment")
|
|
720
|
-
);
|
|
721
752
|
const extensionXml = rawXml(
|
|
722
753
|
dom,
|
|
723
754
|
"data-comment-extension-xml",
|
|
724
755
|
ANY_ELEMENT
|
|
725
756
|
);
|
|
726
757
|
const replies = parseJson(dom.getAttribute("data-comment-replies")) ?? [];
|
|
727
|
-
if (referenceXml === false ||
|
|
758
|
+
if (referenceXml === false || extensionXml === false || !repliesHoldTheirXml(replies)) {
|
|
728
759
|
return false;
|
|
729
760
|
}
|
|
730
761
|
return {
|
|
@@ -734,9 +765,6 @@ var docxSchema = new Schema({
|
|
|
734
765
|
authorId: dom.getAttribute("data-comment-author-id"),
|
|
735
766
|
initials: dom.getAttribute("data-comment-initials"),
|
|
736
767
|
date: dom.getAttribute("data-comment-date"),
|
|
737
|
-
text: dom.getAttribute("data-comment-text") ?? "",
|
|
738
|
-
commentXml,
|
|
739
|
-
imported: dom.getAttribute("data-comment-imported") === "1",
|
|
740
768
|
paraId: dom.getAttribute("data-comment-para-id"),
|
|
741
769
|
resolved: dom.getAttribute("data-comment-resolved") === "1",
|
|
742
770
|
extensionXml,
|
|
@@ -757,14 +785,12 @@ var docxSchema = new Schema({
|
|
|
757
785
|
kind: { default: "footnote" },
|
|
758
786
|
id: { default: null },
|
|
759
787
|
label: { default: "?" },
|
|
760
|
-
text: { default: "" },
|
|
761
788
|
customMarkFollows: { default: false },
|
|
762
789
|
referenceXml: { default: null }
|
|
763
790
|
},
|
|
764
791
|
toDOM(node) {
|
|
765
792
|
const kind = node.attrs.kind === "endnote" ? "Endnote" : "Footnote";
|
|
766
793
|
const label = text(node.attrs.label) ?? "?";
|
|
767
|
-
const body = text(node.attrs.text) ?? "";
|
|
768
794
|
return [
|
|
769
795
|
"sup",
|
|
770
796
|
{
|
|
@@ -772,11 +798,9 @@ var docxSchema = new Schema({
|
|
|
772
798
|
"data-note-kind": text(node.attrs.kind),
|
|
773
799
|
"data-note-id": text(node.attrs.id),
|
|
774
800
|
"data-note-label": label,
|
|
775
|
-
"data-note-text": body,
|
|
776
801
|
"data-custom-mark-follows": node.attrs.customMarkFollows === true ? "1" : void 0,
|
|
777
802
|
"data-reference-xml": text(node.attrs.referenceXml),
|
|
778
|
-
"aria-label": `${kind} ${label}
|
|
779
|
-
title: body
|
|
803
|
+
"aria-label": `${kind} ${label}`
|
|
780
804
|
},
|
|
781
805
|
node.attrs.customMarkFollows === true ? "" : label
|
|
782
806
|
];
|
|
@@ -795,7 +819,6 @@ var docxSchema = new Schema({
|
|
|
795
819
|
kind: dom.getAttribute("data-note-kind") === "endnote" ? "endnote" : "footnote",
|
|
796
820
|
id: dom.getAttribute("data-note-id"),
|
|
797
821
|
label: dom.getAttribute("data-note-label") ?? "?",
|
|
798
|
-
text: dom.getAttribute("data-note-text") ?? "",
|
|
799
822
|
customMarkFollows: dom.getAttribute("data-custom-mark-follows") === "1",
|
|
800
823
|
referenceXml
|
|
801
824
|
};
|
|
@@ -803,29 +826,58 @@ var docxSchema = new Schema({
|
|
|
803
826
|
}
|
|
804
827
|
]
|
|
805
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
|
+
},
|
|
806
860
|
/** The node that carries a non-run element inside a paragraph (a bookmark, for instance) exactly as it came */
|
|
807
861
|
rawInline: {
|
|
808
862
|
group: "inline",
|
|
809
863
|
inline: true,
|
|
810
864
|
atom: true,
|
|
811
865
|
marks: "sdt link",
|
|
812
|
-
attrs: {
|
|
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
|
+
},
|
|
813
874
|
toDOM(node) {
|
|
814
|
-
return
|
|
815
|
-
"span",
|
|
816
|
-
{
|
|
817
|
-
class: editorClassNames.rawInline,
|
|
818
|
-
"data-xml": text(node.attrs.xml)
|
|
819
|
-
}
|
|
820
|
-
];
|
|
875
|
+
return preservedDom(node, editorClassNames.rawInline);
|
|
821
876
|
},
|
|
822
877
|
parseDOM: [
|
|
823
878
|
{
|
|
824
879
|
tag: `span.${editorClassNames.rawInline}`,
|
|
825
|
-
getAttrs:
|
|
826
|
-
const xml = rawXml(dom, "data-xml", ANY_ELEMENT);
|
|
827
|
-
return xml === false ? false : { xml };
|
|
828
|
-
}
|
|
880
|
+
getAttrs: preservedAttrs
|
|
829
881
|
}
|
|
830
882
|
]
|
|
831
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" | "
|
|
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;
|
package/dist/schema/guards.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
transactionReaches
|
|
5
5
|
} from "./editGuard.js";
|
|
6
6
|
import { lockGuard } from "./locks.js";
|
|
7
|
-
import {
|
|
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
|
-
|
|
39
|
+
preservedGuard,
|
|
40
40
|
noteGuard,
|
|
41
41
|
sectionGuard
|
|
42
42
|
];
|
package/dist/schema/index.d.ts
CHANGED
|
@@ -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
|
+
};
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The guards over what a document is opened with and the editor only preserves: the
|
|
3
|
-
*
|
|
4
|
-
* paragraph that ends a section.
|
|
2
|
+
* The guards over what a document is opened with and the editor only preserves: the fragments a
|
|
3
|
+
* file falls apart without, the reference standing where a footnote or an endnote is called, and
|
|
4
|
+
* the paragraph that ends a section.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* The first of those is the two ends of a bookmark range, the two ends of a permission or move
|
|
7
|
+
* range, and the pieces of a field, which say what they say only in the order they stand in. None
|
|
8
|
+
* of it is content the editor writes, so nothing in it can put such a thing back once it is gone,
|
|
9
|
+
* and a document that lost one of a bookmark's two ends cannot be written back as a file at all
|
|
10
|
+
* (`docx/exportDocx` refuses it). What the first two guards hold is therefore the whole list of
|
|
9
11
|
* the nodes they answer for, in the order the document carries them; a section break, which an
|
|
10
12
|
* edit may legitimately move from one paragraph to another, is held by its number instead.
|
|
11
13
|
*/
|
|
@@ -27,7 +29,7 @@ type Signature = (node: PMNode) => string;
|
|
|
27
29
|
* was.
|
|
28
30
|
*/
|
|
29
31
|
export declare function preservedNodeGuard(name: EditGuardName, holds: (node: PMNode) => boolean, signature: Signature): ChangeGuard;
|
|
30
|
-
export declare const
|
|
32
|
+
export declare const preservedGuard: ChangeGuard;
|
|
31
33
|
export declare const noteGuard: ChangeGuard;
|
|
32
34
|
/**
|
|
33
35
|
* A guard that lets a change through only while it leaves at least as many section breaks standing
|