@portone/docx-editor 0.1.1 → 0.2.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.
- package/CHANGELOG.md +82 -0
- package/CONTRIBUTING.md +4 -0
- package/README.md +17 -5
- package/dist/DocxEditor.d.ts +34 -10
- package/dist/DocxEditor.js +69 -24
- package/dist/core.d.ts +2 -0
- package/dist/core.js +2 -0
- package/dist/docx/commentOnlyChange.d.ts +47 -0
- package/dist/docx/commentOnlyChange.js +162 -0
- package/dist/docx/comments/constants.d.ts +11 -3
- package/dist/docx/comments/constants.js +10 -3
- package/dist/docx/comments/contentTypes.d.ts +7 -0
- package/dist/docx/comments/contentTypes.js +38 -0
- package/dist/docx/comments/grammar.d.ts +80 -0
- package/dist/docx/comments/grammar.js +213 -0
- package/dist/docx/comments/model.d.ts +2 -0
- package/dist/docx/comments/model.js +3 -0
- package/dist/docx/comments/people.d.ts +39 -0
- package/dist/docx/comments/people.js +196 -0
- package/dist/docx/comments/reading.d.ts +18 -1
- package/dist/docx/comments/reading.js +33 -20
- package/dist/docx/comments/verifying.d.ts +44 -0
- package/dist/docx/comments/verifying.js +206 -0
- package/dist/docx/comments/writing.d.ts +4 -1
- package/dist/docx/comments/writing.js +84 -77
- package/dist/docx/exportDocx.js +2 -1
- package/dist/docx/formatting/direct.js +3 -6
- package/dist/docx/headersFooters.js +8 -10
- package/dist/docx/importParagraph.js +1 -0
- package/dist/docx/notes.js +3 -5
- package/dist/docx/paraProps.js +51 -46
- package/dist/docx/propsXml.d.ts +20 -2
- package/dist/docx/propsXml.js +72 -32
- package/dist/docx/relationships.js +8 -3
- package/dist/docx/runProps.js +34 -34
- package/dist/docx/sdt.js +16 -14
- package/dist/docx/serializeBlock.js +1 -2
- package/dist/docx/serializeParagraph.d.ts +2 -1
- package/dist/docx/serializeParagraph.js +25 -14
- package/dist/docx/serializeTable.js +38 -24
- package/dist/docx/storyProjection.d.ts +36 -0
- package/dist/docx/storyProjection.js +23 -0
- package/dist/docx/tableFormatting/editing.js +49 -73
- package/dist/docx/tableTemplate.js +24 -3
- package/dist/docx/theme.d.ts +0 -6
- package/dist/docx/theme.js +0 -8
- package/dist/editor/clipboard/images.js +17 -3
- package/dist/editor/clipboard/inlineFormatting.d.ts +7 -0
- package/dist/editor/clipboard/inlineFormatting.js +1 -0
- package/dist/editor/commands/breakCommands.js +6 -2
- package/dist/editor/commands/canRunCommand.d.ts +3 -2
- package/dist/editor/commands/canRunCommand.js +2 -2
- package/dist/editor/commands/comments/editing.js +9 -10
- package/dist/editor/commands/comments/model.d.ts +9 -0
- package/dist/editor/commands/comments/reading.d.ts +7 -0
- package/dist/editor/commands/comments/reading.js +14 -0
- package/dist/editor/commands/formatting/editing.js +6 -1
- package/dist/editor/commands/historyCommands.js +14 -5
- package/dist/editor/commands/index.d.ts +7 -1
- package/dist/editor/commands/index.js +4 -0
- package/dist/editor/commands/linkCommands.js +2 -0
- package/dist/editor/commands/lockCommands.js +12 -1
- package/dist/editor/commands/tabCommands.js +4 -2
- package/dist/editor/createEditor.d.ts +13 -3
- package/dist/editor/createEditor.js +23 -15
- package/dist/editor/externalClipboard.js +166 -4
- package/dist/editor/insertImage.js +6 -2
- package/dist/editor/insertTable.js +2 -1
- package/dist/editor/paragraphEdits.d.ts +2 -0
- package/dist/editor/paragraphEdits.js +2 -0
- package/dist/editor/plugins/documentProtection.d.ts +21 -0
- package/dist/editor/plugins/documentProtection.js +44 -0
- package/dist/editor/plugins/imagePaste.js +4 -1
- package/dist/editor/plugins/keymap.d.ts +11 -1
- package/dist/editor/plugins/keymap.js +24 -4
- package/dist/editor/plugins/lockedContent.d.ts +4 -2
- package/dist/editor/plugins/lockedContent.js +2 -2
- package/dist/editor/plugins/tableContextMenu.js +2 -1
- package/dist/editor/plugins/textContextMenu.js +6 -1
- package/dist/index.d.ts +2 -0
- package/dist/numbering/listTemplate.js +32 -10
- package/dist/ooxml/element.d.ts +52 -0
- package/dist/ooxml/element.js +49 -0
- package/dist/ooxml/fragment.d.ts +53 -0
- package/dist/ooxml/fragment.js +76 -0
- package/dist/ooxml/image.js +4 -3
- package/dist/ooxml/names.d.ts +27 -0
- package/dist/ooxml/names.js +29 -0
- package/dist/ooxml/precedence.d.ts +31 -0
- package/dist/ooxml/precedence.js +51 -0
- package/dist/ooxml/xml.d.ts +31 -0
- package/dist/ooxml/xml.js +27 -0
- package/dist/page/blockKinds.d.ts +42 -0
- package/dist/page/blockKinds.js +0 -0
- package/dist/page/measureBlocks.d.ts +14 -1
- package/dist/page/measureBlocks.js +31 -11
- package/dist/page/pageDecorations.d.ts +16 -0
- package/dist/page/pageDecorations.js +1 -0
- package/dist/page/pageLayout.d.ts +8 -43
- package/dist/page/pageLayout.js +28 -51
- package/dist/page/tableMeasurements.d.ts +10 -2
- package/dist/page/tableMeasurements.js +20 -16
- package/dist/page/usePageLayout.d.ts +15 -0
- package/dist/page/usePageLayout.js +30 -2
- package/dist/schema/attrRoles.d.ts +35 -0
- package/dist/schema/attrRoles.js +106 -0
- package/dist/schema/docxSchema.d.ts +6 -0
- package/dist/schema/docxSchema.js +216 -100
- package/dist/schema/editGuard.d.ts +99 -0
- package/dist/schema/editGuard.js +43 -0
- package/dist/schema/guards.d.ts +68 -0
- package/dist/schema/guards.js +82 -0
- package/dist/schema/locks.d.ts +9 -8
- package/dist/schema/locks.js +32 -16
- package/dist/schema/preservedGuards.d.ts +30 -0
- package/dist/schema/preservedGuards.js +50 -0
- package/dist/schema/protection.d.ts +84 -0
- package/dist/schema/protection.js +171 -0
- package/dist/schema/protectionState.d.ts +20 -0
- package/dist/schema/protectionState.js +37 -0
- package/dist/schema/sourceEquality.d.ts +27 -0
- package/dist/schema/sourceEquality.js +65 -0
- package/dist/table/cellFormatting.js +5 -2
- package/dist/table/commands.d.ts +2 -2
- package/dist/table/commands.js +2 -2
- package/dist/table/index.d.ts +2 -2
- package/dist/table/merge.d.ts +2 -2
- package/dist/table/merge.js +3 -3
- package/dist/ui/CommentsPanel.d.ts +3 -3
- package/dist/ui/CommentsPanel.js +26 -18
- package/dist/ui/LinkCard.d.ts +1 -2
- package/dist/ui/LinkCard.js +3 -4
- package/dist/ui/TextMenu.js +15 -10
- package/package.json +5 -2
- package/dist/editor/plugins/bookmarkProtection.d.ts +0 -3
- package/dist/editor/plugins/bookmarkProtection.js +0 -28
- package/dist/editor/plugins/noteProtection.d.ts +0 -3
- package/dist/editor/plugins/noteProtection.js +0 -25
package/dist/docx/propsXml.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
// src/docx/propsXml.ts
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
elementChildren,
|
|
4
|
+
localPart,
|
|
5
|
+
namespaceDecls,
|
|
6
|
+
parseXml
|
|
7
|
+
} from "../ooxml/xml.js";
|
|
3
8
|
var RUN_PR_ORDER = [
|
|
4
9
|
"rStyle",
|
|
5
10
|
"rFonts",
|
|
@@ -179,6 +184,12 @@ function attrsOf(source, tag) {
|
|
|
179
184
|
const attrs = source.slice(tag.nameEnd, tag.end - closeLength).trim();
|
|
180
185
|
return attrs.length > 0 ? attrs : null;
|
|
181
186
|
}
|
|
187
|
+
function innerXml(xml) {
|
|
188
|
+
const open = readTag(xml, 0);
|
|
189
|
+
if (!open || xml[0] !== "<" || open.kind !== "open") return "";
|
|
190
|
+
const close = xml.lastIndexOf("</");
|
|
191
|
+
return close > open.end ? xml.slice(open.end, close) : "";
|
|
192
|
+
}
|
|
182
193
|
function parseProps(xml) {
|
|
183
194
|
const open = readTag(xml, 0);
|
|
184
195
|
if (!open || xml[0] !== "<") return null;
|
|
@@ -192,6 +203,11 @@ function parseProps(xml) {
|
|
|
192
203
|
let childStart = -1;
|
|
193
204
|
let childName = "";
|
|
194
205
|
let i = open.end;
|
|
206
|
+
let gapStart = open.end;
|
|
207
|
+
const gapBefore = (start) => {
|
|
208
|
+
const gap = xml.slice(gapStart, start);
|
|
209
|
+
return gap.length > 0 ? { before: gap } : {};
|
|
210
|
+
};
|
|
195
211
|
while (i < xml.length) {
|
|
196
212
|
const lt = xml.indexOf("<", i);
|
|
197
213
|
if (lt === -1) return null;
|
|
@@ -204,15 +220,18 @@ function parseProps(xml) {
|
|
|
204
220
|
if (depth === 0) {
|
|
205
221
|
if (tag.kind === "close") {
|
|
206
222
|
if (tag.name !== open.name || tag.end !== xml.length) return null;
|
|
207
|
-
|
|
223
|
+
const tail = xml.slice(gapStart, lt);
|
|
224
|
+
return tail.length > 0 ? { tag: open.name, attrs, children, tail } : { tag: open.name, attrs, children };
|
|
208
225
|
}
|
|
209
226
|
childStart = lt;
|
|
210
227
|
childName = tag.name;
|
|
211
228
|
if (tag.kind === "empty") {
|
|
212
229
|
children.push({
|
|
213
230
|
name: localPart(childName),
|
|
214
|
-
xml: xml.slice(childStart, tag.end)
|
|
231
|
+
xml: xml.slice(childStart, tag.end),
|
|
232
|
+
...gapBefore(childStart)
|
|
215
233
|
});
|
|
234
|
+
gapStart = tag.end;
|
|
216
235
|
} else {
|
|
217
236
|
depth = 1;
|
|
218
237
|
}
|
|
@@ -223,8 +242,10 @@ function parseProps(xml) {
|
|
|
223
242
|
if (depth === 0) {
|
|
224
243
|
children.push({
|
|
225
244
|
name: localPart(childName),
|
|
226
|
-
xml: xml.slice(childStart, tag.end)
|
|
245
|
+
xml: xml.slice(childStart, tag.end),
|
|
246
|
+
...gapBefore(childStart)
|
|
227
247
|
});
|
|
248
|
+
gapStart = tag.end;
|
|
228
249
|
}
|
|
229
250
|
}
|
|
230
251
|
i = tag.end;
|
|
@@ -232,9 +253,11 @@ function parseProps(xml) {
|
|
|
232
253
|
return null;
|
|
233
254
|
}
|
|
234
255
|
function renderProps(props) {
|
|
235
|
-
|
|
256
|
+
const tail = props.tail ?? "";
|
|
257
|
+
if (props.children.length === 0 && tail.trim().length === 0) return "";
|
|
236
258
|
const open = props.attrs ? `<${props.tag} ${props.attrs}>` : `<${props.tag}>`;
|
|
237
|
-
|
|
259
|
+
const inner = props.children.map((child) => (child.before ?? "") + child.xml).join("");
|
|
260
|
+
return open + inner + tail + `</${props.tag}>`;
|
|
238
261
|
}
|
|
239
262
|
function insertIndex(children, name, order) {
|
|
240
263
|
const target = order.indexOf(name);
|
|
@@ -248,37 +271,53 @@ function insertIndex(children, name, order) {
|
|
|
248
271
|
}
|
|
249
272
|
return children.length;
|
|
250
273
|
}
|
|
251
|
-
function
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
const child
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
274
|
+
function dropChildren(children, name) {
|
|
275
|
+
const kept = [];
|
|
276
|
+
let carried = "";
|
|
277
|
+
for (const child of children) {
|
|
278
|
+
const before = carried + (child.before ?? "");
|
|
279
|
+
if (child.name === name) {
|
|
280
|
+
carried = before;
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
carried = "";
|
|
284
|
+
kept.push(
|
|
285
|
+
before === "" ? { name: child.name, xml: child.xml } : { ...child, before }
|
|
286
|
+
);
|
|
259
287
|
}
|
|
260
|
-
return
|
|
261
|
-
...children.slice(0, at),
|
|
262
|
-
child,
|
|
263
|
-
...children.slice(at + 1).filter((entry) => entry.name !== name)
|
|
264
|
-
];
|
|
288
|
+
return { kept, carried };
|
|
265
289
|
}
|
|
266
|
-
function
|
|
267
|
-
|
|
290
|
+
function tailWith(props, carried) {
|
|
291
|
+
const tail = carried + (props.tail ?? "");
|
|
292
|
+
return tail === "" ? {} : { tail };
|
|
268
293
|
}
|
|
269
|
-
function
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
294
|
+
function setPropsChild(props, name, xml, order) {
|
|
295
|
+
const at = props.children.findIndex((entry) => entry.name === name);
|
|
296
|
+
if (at !== -1 && xml !== null) {
|
|
297
|
+
const rest = dropChildren(props.children.slice(at + 1), name);
|
|
298
|
+
return {
|
|
299
|
+
...props,
|
|
300
|
+
children: [
|
|
301
|
+
...props.children.slice(0, at),
|
|
302
|
+
{ ...props.children[at], xml },
|
|
303
|
+
...rest.kept
|
|
304
|
+
],
|
|
305
|
+
...tailWith(props, rest.carried)
|
|
306
|
+
};
|
|
273
307
|
}
|
|
274
|
-
|
|
275
|
-
|
|
308
|
+
const { kept, carried } = dropChildren(props.children, name);
|
|
309
|
+
if (xml === null) {
|
|
310
|
+
return { ...props, children: kept, ...tailWith(props, carried) };
|
|
276
311
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
(
|
|
281
|
-
|
|
312
|
+
const index = insertIndex(kept, name, order);
|
|
313
|
+
return {
|
|
314
|
+
...props,
|
|
315
|
+
children: [...kept.slice(0, index), { name, xml }, ...kept.slice(index)],
|
|
316
|
+
...tailWith(props, carried)
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
function propsChild(children, name) {
|
|
320
|
+
return children.find((child) => child.name === name);
|
|
282
321
|
}
|
|
283
322
|
function parsePropsXml(xml) {
|
|
284
323
|
try {
|
|
@@ -294,6 +333,7 @@ export {
|
|
|
294
333
|
TBL_PR_ORDER,
|
|
295
334
|
TC_PR_ORDER,
|
|
296
335
|
TR_PR_ORDER,
|
|
336
|
+
innerXml,
|
|
297
337
|
parseProps,
|
|
298
338
|
parsePropsXml,
|
|
299
339
|
propsChild,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// src/docx/relationships.ts
|
|
2
|
+
import { elementXml } from "../ooxml/element.js";
|
|
2
3
|
import { DocxExportError } from "../ooxml/errors.js";
|
|
3
4
|
import {
|
|
4
5
|
decodeUtf8,
|
|
5
6
|
elementChildren,
|
|
6
7
|
encodeUtf8,
|
|
7
|
-
escapeXml,
|
|
8
8
|
parseXml
|
|
9
9
|
} from "../ooxml/xml.js";
|
|
10
10
|
var RELATIONSHIPS_NS = "http://schemas.openxmlformats.org/package/2006/relationships";
|
|
@@ -48,8 +48,13 @@ function takeRelId(taken) {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
function relationshipXml(added) {
|
|
51
|
-
const mode = added.external ?
|
|
52
|
-
return
|
|
51
|
+
const mode = added.external ? [["TargetMode", "External"]] : [];
|
|
52
|
+
return elementXml("Relationship", [
|
|
53
|
+
["Id", added.id],
|
|
54
|
+
["Type", added.type],
|
|
55
|
+
["Target", added.target],
|
|
56
|
+
...mode
|
|
57
|
+
]);
|
|
53
58
|
}
|
|
54
59
|
function relationshipsPart(original, added) {
|
|
55
60
|
const entries = added.map(relationshipXml).join("");
|
package/dist/docx/runProps.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
// src/docx/runProps.ts
|
|
2
2
|
import { toRunFormat } from "../model/format.js";
|
|
3
|
+
import {
|
|
4
|
+
attrPairs,
|
|
5
|
+
attrValue,
|
|
6
|
+
elementXml
|
|
7
|
+
} from "../ooxml/element.js";
|
|
8
|
+
import { wName } from "../ooxml/names.js";
|
|
9
|
+
import { setAttr } from "../ooxml/precedence.js";
|
|
3
10
|
import { normalizeHex } from "../ooxml/units.js";
|
|
4
|
-
import { escapeXml, localPart } from "../ooxml/xml.js";
|
|
5
11
|
import { isEastAsianFontName } from "../styles/fontStack.js";
|
|
6
12
|
import { fontNamesOf, readRunFormat } from "./formatting.js";
|
|
7
13
|
import {
|
|
@@ -12,7 +18,6 @@ import {
|
|
|
12
18
|
renderProps,
|
|
13
19
|
setPropsChild
|
|
14
20
|
} from "./propsXml.js";
|
|
15
|
-
import { THEME_ATTRS } from "./theme.js";
|
|
16
21
|
var TOGGLE_CHILDREN = {
|
|
17
22
|
bold: ["b", "bCs"],
|
|
18
23
|
italic: ["i", "iCs"],
|
|
@@ -32,11 +37,15 @@ var TOGGLE_OFF_VALUE = {
|
|
|
32
37
|
strike: "0"
|
|
33
38
|
};
|
|
34
39
|
var MAX_FONT_SIZE_PT = 819;
|
|
35
|
-
function
|
|
36
|
-
return value === null ?
|
|
40
|
+
function valXml(name, value) {
|
|
41
|
+
return elementXml(wName(name), value === null ? [] : [[wName("val"), value]]);
|
|
37
42
|
}
|
|
38
43
|
function shadingXml(fill) {
|
|
39
|
-
return
|
|
44
|
+
return elementXml(wName("shd"), [
|
|
45
|
+
[wName("val"), "clear"],
|
|
46
|
+
[wName("color"), "auto"],
|
|
47
|
+
[wName("fill"), fill]
|
|
48
|
+
]);
|
|
40
49
|
}
|
|
41
50
|
function halfPoints(pt) {
|
|
42
51
|
if (!Number.isFinite(pt) || pt <= 0 || pt > MAX_FONT_SIZE_PT) return null;
|
|
@@ -53,29 +62,19 @@ function fontName(value) {
|
|
|
53
62
|
const name = value.trim();
|
|
54
63
|
return name.length > 0 && !/["';<>&]/.test(name) ? name : null;
|
|
55
64
|
}
|
|
56
|
-
function rFontsAttrs(xml) {
|
|
57
|
-
if (xml === null) return [];
|
|
58
|
-
const el = parsePropsXml(xml);
|
|
59
|
-
if (!el) return null;
|
|
60
|
-
return Array.from(el.attributes, (attr) => [
|
|
61
|
-
attr.name,
|
|
62
|
-
attr.value
|
|
63
|
-
]);
|
|
64
|
-
}
|
|
65
65
|
function rFontsXml(current, name) {
|
|
66
|
-
const
|
|
67
|
-
if (!
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
const el = current === null ? null : parsePropsXml(current);
|
|
67
|
+
if (current !== null && !el) return null;
|
|
68
|
+
const attrs = attrPairs(el);
|
|
69
|
+
const slots = fontSlots(name, attrValue(attrs, "cs") !== null);
|
|
70
|
+
const kept = slots.reduce(
|
|
71
|
+
(rest, slot) => setAttr(rest, "rFonts", slot, null),
|
|
72
|
+
attrs
|
|
71
73
|
);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const text = [
|
|
75
|
-
...slots.map((slot) => [`w:${slot}`, name]),
|
|
74
|
+
return elementXml(wName("rFonts"), [
|
|
75
|
+
...slots.map((slot) => [wName(slot), name]),
|
|
76
76
|
...kept
|
|
77
|
-
]
|
|
78
|
-
return `<w:rFonts ${text}/>`;
|
|
77
|
+
]);
|
|
79
78
|
}
|
|
80
79
|
function hasChild(xml, name) {
|
|
81
80
|
if (xml === null) return false;
|
|
@@ -87,7 +86,7 @@ function propsOf(rPr) {
|
|
|
87
86
|
return parseProps(rPr);
|
|
88
87
|
}
|
|
89
88
|
function offEdit(name, value, inherited) {
|
|
90
|
-
return [name, inherited ?
|
|
89
|
+
return [name, inherited ? valXml(name, value) : null];
|
|
91
90
|
}
|
|
92
91
|
function childEdits(edit, inherited, rFonts) {
|
|
93
92
|
switch (edit.kind) {
|
|
@@ -95,7 +94,7 @@ function childEdits(edit, inherited, rFonts) {
|
|
|
95
94
|
const names = TOGGLE_CHILDREN[edit.toggle];
|
|
96
95
|
if (edit.on) {
|
|
97
96
|
const value = TOGGLE_ON_VALUE[edit.toggle];
|
|
98
|
-
return names.map((name) => [name,
|
|
97
|
+
return names.map((name) => [name, valXml(name, value)]);
|
|
99
98
|
}
|
|
100
99
|
const off = TOGGLE_OFF_VALUE[edit.toggle];
|
|
101
100
|
return names.map((name) => offEdit(name, off, inherited));
|
|
@@ -110,8 +109,8 @@ function childEdits(edit, inherited, rFonts) {
|
|
|
110
109
|
const half = halfPoints(edit.pt);
|
|
111
110
|
if (half === null) return null;
|
|
112
111
|
return [
|
|
113
|
-
["sz",
|
|
114
|
-
["szCs",
|
|
112
|
+
["sz", valXml("sz", `${half}`)],
|
|
113
|
+
["szCs", valXml("szCs", `${half}`)]
|
|
115
114
|
];
|
|
116
115
|
}
|
|
117
116
|
case "fontFamily": {
|
|
@@ -124,7 +123,7 @@ function childEdits(edit, inherited, rFonts) {
|
|
|
124
123
|
case "color": {
|
|
125
124
|
if (edit.hex === null) return [offEdit("color", "auto", inherited)];
|
|
126
125
|
const hex = normalizeHex(edit.hex);
|
|
127
|
-
return hex === null ? null : [["color",
|
|
126
|
+
return hex === null ? null : [["color", valXml("color", hex)]];
|
|
128
127
|
}
|
|
129
128
|
case "background": {
|
|
130
129
|
const highlight = offEdit("highlight", "none", inherited);
|
|
@@ -162,11 +161,12 @@ function editRunProps(current, pPr, edit) {
|
|
|
162
161
|
const rFonts = propsChild(props.children, "rFonts")?.xml ?? null;
|
|
163
162
|
const edits = childEdits(edit, inherited, rFonts);
|
|
164
163
|
if (!edits) return null;
|
|
165
|
-
const
|
|
166
|
-
(
|
|
167
|
-
|
|
164
|
+
const rPr = renderProps(
|
|
165
|
+
edits.reduce(
|
|
166
|
+
(kept, [name, xml]) => setPropsChild(kept, name, xml, RUN_PR_ORDER),
|
|
167
|
+
props
|
|
168
|
+
)
|
|
168
169
|
);
|
|
169
|
-
const rPr = renderProps({ ...props, children });
|
|
170
170
|
return nextProps(rPr === "" ? null : rPr, current);
|
|
171
171
|
}
|
|
172
172
|
function isRunToggleOn(format, toggle) {
|
package/dist/docx/sdt.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// src/docx/sdt.ts
|
|
2
|
+
import { elementXml, emptyTagXml, openTagXml } from "../ooxml/element.js";
|
|
3
|
+
import { wName } from "../ooxml/names.js";
|
|
2
4
|
import { wAttr } from "../ooxml/units.js";
|
|
3
5
|
import { attrString, elementChildren, serializeXml } from "../ooxml/xml.js";
|
|
4
6
|
import {
|
|
@@ -31,7 +33,7 @@ function readSdtWrapper(el) {
|
|
|
31
33
|
const attrs = attrString(el);
|
|
32
34
|
const val = lockValue(sdtPr);
|
|
33
35
|
return {
|
|
34
|
-
prefix: (
|
|
36
|
+
prefix: openTagXml(wName("sdt"), attrs) + head.map(serializeXml).join(""),
|
|
35
37
|
content,
|
|
36
38
|
contentsLocked: val !== null && CONTENTS_LOCKED.includes(val),
|
|
37
39
|
deletionLocked: val !== null && DELETION_LOCKED.includes(val)
|
|
@@ -53,8 +55,8 @@ function newControlId() {
|
|
|
53
55
|
return Math.floor(Math.random() * 2147483647);
|
|
54
56
|
}
|
|
55
57
|
function renderPrefix(props) {
|
|
56
|
-
const
|
|
57
|
-
return
|
|
58
|
+
const inner = props.children.map((child) => (child.before ?? "") + child.xml).join("");
|
|
59
|
+
return openTagXml(props.tag, props.attrs) + inner + (props.tail ?? "");
|
|
58
60
|
}
|
|
59
61
|
var NAMES_NOTHING = ["id", "lock"];
|
|
60
62
|
function namesNothing(prefix) {
|
|
@@ -66,31 +68,31 @@ function namesNothing(prefix) {
|
|
|
66
68
|
return props.children.every((child) => NAMES_NOTHING.includes(child.name));
|
|
67
69
|
}
|
|
68
70
|
function emptyProps(props) {
|
|
69
|
-
return props.
|
|
71
|
+
return emptyTagXml(props.tag, props.attrs);
|
|
70
72
|
}
|
|
71
73
|
function editSdtPrefix(prefix, edits) {
|
|
72
74
|
const sdt = parseProps(`${prefix}</w:sdt>`);
|
|
73
75
|
const sdtPr = sdt && propsChild(sdt.children, "sdtPr");
|
|
74
76
|
const props = sdtPr ? parseProps(sdtPr.xml) : null;
|
|
75
77
|
if (!sdt || !props) return null;
|
|
76
|
-
const
|
|
77
|
-
(
|
|
78
|
-
|
|
78
|
+
const rendered = renderProps(
|
|
79
|
+
edits.reduce(
|
|
80
|
+
(kept, [name, xml]) => setPropsChild(kept, name, xml, SDT_PR_ORDER),
|
|
81
|
+
props
|
|
82
|
+
)
|
|
79
83
|
);
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
children: setPropsChild(
|
|
84
|
-
sdt.children,
|
|
84
|
+
return renderPrefix(
|
|
85
|
+
setPropsChild(
|
|
86
|
+
sdt,
|
|
85
87
|
"sdtPr",
|
|
86
88
|
rendered === "" ? emptyProps(props) : rendered,
|
|
87
89
|
SDT_ORDER
|
|
88
90
|
)
|
|
89
|
-
|
|
91
|
+
);
|
|
90
92
|
}
|
|
91
93
|
function copiedControlPrefix(prefix, id) {
|
|
92
94
|
const copied = editSdtPrefix(prefix, [
|
|
93
|
-
["id",
|
|
95
|
+
["id", elementXml(wName("id"), [[wName("val"), `${id}`]])],
|
|
94
96
|
["dataBinding", null]
|
|
95
97
|
]);
|
|
96
98
|
return copied ?? prefix;
|
|
@@ -18,8 +18,7 @@ function serializeBlock(node, session, refs = NO_EXPORT_REFS) {
|
|
|
18
18
|
if (node.type.name === "paragraph") return serializeParagraph(node, refs);
|
|
19
19
|
if (node.type.name === "table") return serializeTable(node, refs);
|
|
20
20
|
if (node.type.name === "rawBlock") return preservedXml(node);
|
|
21
|
-
if (node.type.
|
|
22
|
-
if (node.type.name === "docxRaw") return serializeRaw(node, session);
|
|
21
|
+
if (node.type.isInGroup("preserved")) return serializeRaw(node, session);
|
|
23
22
|
throw new DocxExportError(
|
|
24
23
|
"unsupported-content",
|
|
25
24
|
`block we cannot serialize: ${node.type.name}`
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { Node as PMNode } from "prosemirror-model";
|
|
12
12
|
import { type ExportRefs } from "./exportRefs";
|
|
13
|
-
|
|
13
|
+
/** The attribute text a node attr holds, which is either what the original wrote or nothing */
|
|
14
|
+
export declare function rawAttrsOf(value: unknown): string | null;
|
|
14
15
|
export declare function preservedXml(node: PMNode): string;
|
|
15
16
|
export declare function serializeParagraph(node: PMNode, refs?: ExportRefs): string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/docx/serializeParagraph.ts
|
|
2
|
+
import { elementXml, emptyTagXml, openTagXml } from "../ooxml/element.js";
|
|
2
3
|
import { DocxExportError } from "../ooxml/errors.js";
|
|
3
4
|
import {
|
|
4
5
|
imageDrawingXml,
|
|
@@ -6,6 +7,7 @@ import {
|
|
|
6
7
|
toImageSrc,
|
|
7
8
|
withExtent
|
|
8
9
|
} from "../ooxml/image.js";
|
|
10
|
+
import { wName } from "../ooxml/names.js";
|
|
9
11
|
import { escapeXml } from "../ooxml/xml.js";
|
|
10
12
|
import { NO_EXPORT_REFS } from "./exportRefs.js";
|
|
11
13
|
import { relIdIn, withRelId } from "./hyperlink.js";
|
|
@@ -16,11 +18,8 @@ function sameMark(a, b) {
|
|
|
16
18
|
function markOf(node, name) {
|
|
17
19
|
return node.marks.find((mark) => mark.type.name === name) ?? null;
|
|
18
20
|
}
|
|
19
|
-
function
|
|
20
|
-
return typeof
|
|
21
|
-
}
|
|
22
|
-
function emptyTag(name, attrs) {
|
|
23
|
-
return typeof attrs === "string" ? `<${name} ${attrs}/>` : `<${name}/>`;
|
|
21
|
+
function rawAttrsOf(value) {
|
|
22
|
+
return typeof value === "string" ? value : null;
|
|
24
23
|
}
|
|
25
24
|
function renderImage(node, images) {
|
|
26
25
|
const extent = toImageExtent(node.attrs.extent);
|
|
@@ -51,19 +50,28 @@ function renderInline(node, images) {
|
|
|
51
50
|
if (node.isText) {
|
|
52
51
|
const tab = markOf(node, "tab");
|
|
53
52
|
return (node.text ?? "").split(" ").flatMap((text, index, pieces) => {
|
|
54
|
-
const rendered = text ? [
|
|
55
|
-
|
|
53
|
+
const rendered = text ? [
|
|
54
|
+
elementXml(
|
|
55
|
+
wName("t"),
|
|
56
|
+
[["xml:space", "preserve"]],
|
|
57
|
+
[escapeXml(text)]
|
|
58
|
+
)
|
|
59
|
+
] : [];
|
|
60
|
+
return index < pieces.length - 1 ? [
|
|
61
|
+
...rendered,
|
|
62
|
+
emptyTagXml(wName("tab"), rawAttrsOf(tab?.attrs.tabAttrs))
|
|
63
|
+
] : rendered;
|
|
56
64
|
}).join("");
|
|
57
65
|
}
|
|
58
66
|
if (node.type.name === "hardBreak")
|
|
59
|
-
return
|
|
67
|
+
return emptyTagXml(wName("br"), rawAttrsOf(node.attrs.brAttrs));
|
|
60
68
|
if (node.type.name === "image") return renderImage(node, images);
|
|
61
69
|
if (node.type.name === "commentReference") {
|
|
62
70
|
const original = node.attrs.referenceXml;
|
|
63
71
|
if (typeof original === "string") return original;
|
|
64
72
|
const id = node.attrs.id;
|
|
65
73
|
if (typeof id === "string") {
|
|
66
|
-
return
|
|
74
|
+
return elementXml(wName("commentReference"), [[wName("id"), id]]);
|
|
67
75
|
}
|
|
68
76
|
throw new DocxExportError(
|
|
69
77
|
"lost-original",
|
|
@@ -76,7 +84,7 @@ function renderInline(node, images) {
|
|
|
76
84
|
const id = node.attrs.id;
|
|
77
85
|
const name = node.attrs.kind === "endnote" ? "endnoteReference" : "footnoteReference";
|
|
78
86
|
if (typeof id === "string") {
|
|
79
|
-
return
|
|
87
|
+
return elementXml(wName(name), [[wName("id"), id]]);
|
|
80
88
|
}
|
|
81
89
|
throw new DocxExportError(
|
|
82
90
|
"lost-original",
|
|
@@ -117,7 +125,10 @@ function addInline(parts, child, images) {
|
|
|
117
125
|
);
|
|
118
126
|
}
|
|
119
127
|
const name = child.type.name === "commentStart" ? "commentRangeStart" : "commentRangeEnd";
|
|
120
|
-
parts.push({
|
|
128
|
+
parts.push({
|
|
129
|
+
kind: "raw",
|
|
130
|
+
xml: elementXml(wName(name), [[wName("id"), id]])
|
|
131
|
+
});
|
|
121
132
|
return;
|
|
122
133
|
}
|
|
123
134
|
const piece = renderInline(child, images);
|
|
@@ -150,7 +161,7 @@ function splitParagraphGroups(paragraph, refs) {
|
|
|
150
161
|
}
|
|
151
162
|
function renderParagraphPart(part) {
|
|
152
163
|
if (part.kind === "raw") return part.xml;
|
|
153
|
-
const open =
|
|
164
|
+
const open = openTagXml(wName("r"), rawAttrsOf(part.mark?.attrs.rAttrs));
|
|
154
165
|
const rPr = part.mark?.attrs.rPr;
|
|
155
166
|
return open + (typeof rPr === "string" ? rPr : "") + part.pieces.join("") + "</w:r>";
|
|
156
167
|
}
|
|
@@ -196,13 +207,13 @@ function renderParagraphGroup(group, refs) {
|
|
|
196
207
|
return `${prefix}<w:sdtContent>${body}</w:sdtContent></w:sdt>`;
|
|
197
208
|
}
|
|
198
209
|
function serializeParagraph(node, refs = NO_EXPORT_REFS) {
|
|
199
|
-
const open =
|
|
210
|
+
const open = openTagXml(wName("p"), rawAttrsOf(node.attrs.pAttrs));
|
|
200
211
|
const pPr = node.attrs.pPr;
|
|
201
212
|
const body = splitParagraphGroups(node, refs).map((group) => renderParagraphGroup(group, refs)).join("");
|
|
202
213
|
return open + (typeof pPr === "string" ? pPr : "") + body + "</w:p>";
|
|
203
214
|
}
|
|
204
215
|
export {
|
|
205
|
-
openTag,
|
|
206
216
|
preservedXml,
|
|
217
|
+
rawAttrsOf,
|
|
207
218
|
serializeParagraph
|
|
208
219
|
};
|
|
@@ -5,18 +5,22 @@ import {
|
|
|
5
5
|
toTableWidth,
|
|
6
6
|
widthNumber
|
|
7
7
|
} from "../model/format.js";
|
|
8
|
+
import { elementXml, openTagXml } from "../ooxml/element.js";
|
|
8
9
|
import { DocxExportError } from "../ooxml/errors.js";
|
|
10
|
+
import { wName } from "../ooxml/names.js";
|
|
9
11
|
import { NO_EXPORT_REFS } from "./exportRefs.js";
|
|
10
12
|
import {
|
|
13
|
+
innerXml,
|
|
11
14
|
parseProps,
|
|
15
|
+
propsChild,
|
|
12
16
|
renderProps,
|
|
13
17
|
setPropsChild,
|
|
14
18
|
TBL_PR_ORDER,
|
|
15
19
|
TC_PR_ORDER
|
|
16
20
|
} from "./propsXml.js";
|
|
17
21
|
import {
|
|
18
|
-
openTag,
|
|
19
22
|
preservedXml,
|
|
23
|
+
rawAttrsOf,
|
|
20
24
|
serializeParagraph
|
|
21
25
|
} from "./serializeParagraph.js";
|
|
22
26
|
function propsOf(xml, tag) {
|
|
@@ -27,15 +31,24 @@ function propsOf(xml, tag) {
|
|
|
27
31
|
}
|
|
28
32
|
return parsed;
|
|
29
33
|
}
|
|
30
|
-
function
|
|
31
|
-
|
|
34
|
+
function modelled(name, attrs, replacing) {
|
|
35
|
+
const inner = replacing === void 0 ? "" : innerXml(replacing);
|
|
36
|
+
return elementXml(wName(name), attrs, inner === "" ? [] : [inner]);
|
|
37
|
+
}
|
|
38
|
+
function widthXml(name, width, replacing) {
|
|
39
|
+
return modelled(
|
|
40
|
+
name,
|
|
41
|
+
[
|
|
42
|
+
[wName("w"), `${widthNumber(width) ?? 0}`],
|
|
43
|
+
[wName("type"), width.type]
|
|
44
|
+
],
|
|
45
|
+
replacing
|
|
46
|
+
);
|
|
32
47
|
}
|
|
33
48
|
function withWidth(props, name, width, order) {
|
|
34
49
|
if (!width) return props;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
children: setPropsChild(props.children, name, widthXml(name, width), order)
|
|
38
|
-
};
|
|
50
|
+
const replacing = propsChild(props.children, name)?.xml;
|
|
51
|
+
return setPropsChild(props, name, widthXml(name, width, replacing), order);
|
|
39
52
|
}
|
|
40
53
|
function tablePropsXml(table) {
|
|
41
54
|
const props = propsOf(table.attrs.tblPr, "w:tblPr");
|
|
@@ -45,26 +58,27 @@ function tablePropsXml(table) {
|
|
|
45
58
|
function tableGridXml(table) {
|
|
46
59
|
const gridCols = toGridCols(table.attrs.gridCols);
|
|
47
60
|
if (gridCols.length === 0) return "";
|
|
48
|
-
const cols = gridCols.map((w) =>
|
|
49
|
-
return
|
|
61
|
+
const cols = gridCols.map((w) => elementXml(wName("gridCol"), [[wName("w"), `${w}`]])).join("");
|
|
62
|
+
return elementXml(wName("tblGrid"), [], [cols]);
|
|
50
63
|
}
|
|
51
64
|
function cellPropsXml(cell, role) {
|
|
52
65
|
const props = propsOf(cell.attrs.tcPr, "w:tcPr");
|
|
53
66
|
const colspan = spanCount(cell.attrs.colspan);
|
|
54
67
|
const rowspan = spanCount(cell.attrs.rowspan);
|
|
55
|
-
const gridSpan = colspan > 1 ?
|
|
56
|
-
const vMerge = role === "continue" ? "<w:vMerge/>" : rowspan > 1 ? '<w:vMerge w:val="restart"/>' : null;
|
|
57
|
-
let children = setPropsChild(
|
|
58
|
-
props.children,
|
|
68
|
+
const gridSpan = colspan > 1 ? modelled(
|
|
59
69
|
"gridSpan",
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
);
|
|
63
|
-
|
|
70
|
+
[[wName("val"), `${colspan}`]],
|
|
71
|
+
propsChild(props.children, "gridSpan")?.xml
|
|
72
|
+
) : null;
|
|
73
|
+
const vMerge = role === "continue" ? elementXml(wName("vMerge"), []) : rowspan > 1 ? modelled(
|
|
74
|
+
"vMerge",
|
|
75
|
+
[[wName("val"), "restart"]],
|
|
76
|
+
propsChild(props.children, "vMerge")?.xml
|
|
77
|
+
) : null;
|
|
78
|
+
const spanned = setPropsChild(props, "gridSpan", gridSpan, TC_PR_ORDER);
|
|
79
|
+
const merged = setPropsChild(spanned, "vMerge", vMerge, TC_PR_ORDER);
|
|
64
80
|
const width = toTableWidth(cell.attrs.tcW);
|
|
65
|
-
return renderProps(
|
|
66
|
-
withWidth({ ...props, children }, "tcW", width, TC_PR_ORDER)
|
|
67
|
-
);
|
|
81
|
+
return renderProps(withWidth(merged, "tcW", width, TC_PR_ORDER));
|
|
68
82
|
}
|
|
69
83
|
function cellBlockXml(block, refs) {
|
|
70
84
|
if (block.type.name === "paragraph") return serializeParagraph(block, refs);
|
|
@@ -81,8 +95,8 @@ function wrapInSdt(xml, cell, role) {
|
|
|
81
95
|
return `${prefix}<w:sdtContent>${xml}</w:sdtContent></w:sdt>`;
|
|
82
96
|
}
|
|
83
97
|
function cellXml(cell, role, refs) {
|
|
84
|
-
const body = role === "continue" ? "
|
|
85
|
-
const xml =
|
|
98
|
+
const body = role === "continue" ? elementXml(wName("p"), []) : cell.children.map((block) => cellBlockXml(block, refs)).join("");
|
|
99
|
+
const xml = openTagXml(wName("tc"), rawAttrsOf(cell.attrs.tcAttrs)) + cellPropsXml(cell, role) + body + "</w:tc>";
|
|
86
100
|
return wrapInSdt(xml, cell, role);
|
|
87
101
|
}
|
|
88
102
|
function placeRow(row, covering) {
|
|
@@ -116,7 +130,7 @@ function rowXml(row, covering, refs) {
|
|
|
116
130
|
const cells = placeRow(row, covering).map((placed) => cellXml(placed.cell, placed.role, refs)).join("");
|
|
117
131
|
const tblPrEx = row.attrs.tblPrEx;
|
|
118
132
|
const trPr = row.attrs.trPr;
|
|
119
|
-
return
|
|
133
|
+
return openTagXml(wName("tr"), rawAttrsOf(row.attrs.trAttrs)) + (typeof tblPrEx === "string" ? tblPrEx : "") + (typeof trPr === "string" ? trPr : "") + cells + "</w:tr>";
|
|
120
134
|
}
|
|
121
135
|
function serializeTable(table, refs = NO_EXPORT_REFS) {
|
|
122
136
|
const covering = [];
|
|
@@ -127,7 +141,7 @@ function serializeTable(table, refs = NO_EXPORT_REFS) {
|
|
|
127
141
|
"a vertical merge in the table reaches past the last row"
|
|
128
142
|
);
|
|
129
143
|
}
|
|
130
|
-
return
|
|
144
|
+
return openTagXml(wName("tbl"), rawAttrsOf(table.attrs.tblAttrs)) + tablePropsXml(table) + tableGridXml(table) + rows + "</w:tbl>";
|
|
131
145
|
}
|
|
132
146
|
export {
|
|
133
147
|
serializeTable
|