@portone/docx-editor 0.6.0 → 0.6.2
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 +40 -0
- package/dist/DocxEditor.js +84 -26
- package/dist/core.d.ts +4 -3
- package/dist/docx/exportDocx.d.ts +3 -2
- package/dist/docx/exportDocx.js +6 -10
- package/dist/docx/headersFooters.js +35 -23
- package/dist/docx/identities.d.ts +30 -0
- package/dist/docx/identities.js +43 -10
- package/dist/docx/importDocx.js +25 -26
- package/dist/docx/importParagraph.d.ts +1 -4
- package/dist/docx/importParagraph.js +4 -18
- package/dist/docx/invariants.d.ts +13 -10
- package/dist/docx/invariants.js +300 -116
- package/dist/docx/newLists.js +12 -3
- package/dist/docx/notes/newNote.d.ts +39 -0
- package/dist/docx/notes/newNote.js +122 -0
- package/dist/docx/notes/numbering.d.ts +27 -0
- package/dist/docx/notes/numbering.js +113 -0
- package/dist/docx/notes/reading.d.ts +58 -0
- package/dist/docx/notes/reading.js +98 -0
- package/dist/docx/notes/references.d.ts +33 -0
- package/dist/docx/notes/references.js +37 -0
- package/dist/docx/notes/writing.d.ts +19 -0
- package/dist/docx/notes/writing.js +95 -0
- package/dist/docx/partPlan.d.ts +3 -0
- package/dist/docx/partPlanners.d.ts +13 -0
- package/dist/docx/partPlanners.js +48 -0
- package/dist/docx/sections.d.ts +5 -0
- package/dist/docx/sections.js +7 -2
- package/dist/docx/serializeParagraph.js +7 -2
- package/dist/docx/serializePreserved.d.ts +5 -1
- package/dist/docx/serializePreserved.js +24 -7
- package/dist/docx/session.d.ts +5 -0
- package/dist/docx/session.js +6 -0
- package/dist/docx/storyParts.d.ts +133 -0
- package/dist/docx/storyParts.js +314 -0
- package/dist/editor/clipboard/htmlReader.d.ts +24 -4
- package/dist/editor/clipboard/htmlReader.js +39 -4
- package/dist/editor/clipboard/internalChannel.d.ts +30 -3
- package/dist/editor/clipboard/internalChannel.js +43 -3
- package/dist/editor/clipboard/normalizers.d.ts +35 -8
- package/dist/editor/clipboard/normalizers.js +60 -11
- package/dist/editor/clipboard/plugin.js +42 -22
- package/dist/editor/commands/exportQueries.d.ts +4 -3
- package/dist/editor/commands/index.d.ts +2 -1
- package/dist/editor/commands/index.js +18 -0
- package/dist/editor/commands/noteCommands.d.ts +47 -0
- package/dist/editor/commands/noteCommands.js +95 -0
- package/dist/editor/commands/noteQueries.d.ts +22 -3
- package/dist/editor/commands/noteQueries.js +21 -13
- package/dist/editor/createEditor.js +21 -3
- package/dist/editor/documentStyles.d.ts +3 -0
- package/dist/editor/documentStyles.js +2 -1
- package/dist/editor/editorDocument.d.ts +24 -0
- package/dist/editor/editorDocument.js +34 -4
- package/dist/editor/notes/noteSurface.d.ts +53 -0
- package/dist/editor/notes/noteSurface.js +246 -0
- package/dist/editor/plugins/compositionSelection.d.ts +20 -0
- package/dist/editor/plugins/compositionSelection.js +19 -0
- package/dist/editor/plugins/keymap.d.ts +14 -0
- package/dist/editor/plugins/keymap.js +13 -1
- package/dist/editor/plugins/noteLifecycle.d.ts +18 -0
- package/dist/editor/plugins/noteLifecycle.js +117 -0
- package/dist/editor/plugins/noteNavigation.d.ts +45 -0
- package/dist/editor/plugins/noteNavigation.js +86 -0
- package/dist/editor/plugins/noteNumbering.d.ts +13 -0
- package/dist/editor/plugins/noteNumbering.js +58 -0
- package/dist/editor/plugins/rowResize.js +2 -7
- package/dist/editor/plugins/tabLayout.js +2 -7
- package/dist/editor/stories/storyMarkup.d.ts +24 -0
- package/dist/editor/stories/storyMarkup.js +35 -0
- package/dist/editor/stories/storyState.d.ts +34 -0
- package/dist/editor/stories/storyState.js +74 -0
- package/dist/editor/stories/storyView.d.ts +115 -0
- package/dist/editor/stories/storyView.js +144 -0
- package/dist/index.d.ts +2 -2
- package/dist/numbering/spellers.d.ts +1 -1
- package/dist/numbering/spellers.js +6 -1
- package/dist/ooxml/errors.d.ts +135 -2
- package/dist/ooxml/errors.js +6 -0
- package/dist/page/blockKinds.d.ts +23 -4
- package/dist/page/demands/footnoteDemands.d.ts +18 -0
- package/dist/page/demands/footnoteDemands.js +51 -0
- package/dist/page/demands/index.d.ts +43 -0
- package/dist/page/demands/index.js +8 -0
- package/dist/page/kinds/paragraphKind.js +7 -1
- package/dist/page/kinds/tableKind.js +9 -1
- package/dist/page/measureBlocks.d.ts +2 -0
- package/dist/page/measureBlocks.js +31 -10
- package/dist/page/pageDecorations.d.ts +9 -2
- package/dist/page/pageDecorations.js +18 -5
- package/dist/page/pageLayout.d.ts +77 -1
- package/dist/page/pageLayout.js +186 -9
- package/dist/page/usePageLayout.d.ts +57 -2
- package/dist/page/usePageLayout.js +50 -5
- package/dist/schema/attrRoles.js +3 -2
- package/dist/schema/docxSchema.js +5 -2
- package/dist/schema/editGuard.d.ts +1 -1
- package/dist/schema/guards.js +1 -2
- package/dist/schema/preservedGuards.d.ts +4 -6
- package/dist/schema/preservedGuards.js +0 -9
- package/dist/schema/stories.d.ts +42 -2
- package/dist/schema/stories.js +28 -5
- package/dist/styles/classNames.d.ts +21 -6
- package/dist/styles/classNames.js +21 -6
- package/dist/styles/inlineStyle.d.ts +7 -0
- package/dist/styles/inlineStyle.js +11 -5
- package/dist/styles/visualScale.d.ts +19 -0
- package/dist/styles/visualScale.js +26 -0
- package/dist/styles.css +89 -32
- package/dist/ui/InsertImageButton.d.ts +3 -1
- package/dist/ui/InsertImageButton.js +3 -2
- package/dist/ui/TableMenu.d.ts +5 -2
- package/dist/ui/TableMenu.js +18 -1
- package/dist/ui/TextMenu.d.ts +5 -2
- package/dist/ui/TextMenu.js +21 -6
- package/dist/ui/Toolbar.d.ts +17 -2
- package/dist/ui/Toolbar.js +23 -10
- package/dist/ui/comments/useCommentRailLayout.js +2 -4
- package/dist/ui/noteItems.d.ts +21 -0
- package/dist/ui/noteItems.js +30 -0
- package/dist/ui/notes/NoteAreas.d.ts +73 -0
- package/dist/ui/notes/NoteAreas.js +131 -0
- package/dist/ui/notes/NoteList.d.ts +25 -0
- package/dist/ui/notes/NoteList.js +58 -0
- package/dist/ui/notes/StoryRow.d.ts +75 -0
- package/dist/ui/notes/StoryRow.js +122 -0
- package/dist/ui/notes/noteBands.d.ts +100 -0
- package/dist/ui/notes/noteBands.js +142 -0
- package/dist/ui/notes/noteHeights.d.ts +10 -0
- package/dist/ui/notes/noteHeights.js +24 -0
- package/dist/ui/notes/noteSeparator.d.ts +12 -0
- package/dist/ui/notes/noteSeparator.js +9 -0
- package/dist/ui/notes/useStorySurface.d.ts +68 -0
- package/dist/ui/notes/useStorySurface.js +95 -0
- package/dist/ui/runCommand.d.ts +8 -1
- package/dist/ui/runCommand.js +2 -2
- package/dist/ui/shortcutLabels.d.ts +16 -0
- package/dist/ui/shortcutLabels.js +9 -0
- package/dist/ui/usePageRoom.d.ts +13 -0
- package/dist/ui/usePageRoom.js +31 -0
- package/package.json +1 -1
- package/dist/docx/notes.d.ts +0 -27
- package/dist/docx/notes.js +0 -55
- package/dist/ui/NotesPanel.d.ts +0 -6
- package/dist/ui/NotesPanel.js +0 -33
package/dist/docx/invariants.js
CHANGED
|
@@ -8,6 +8,12 @@ import {
|
|
|
8
8
|
} from "../ooxml/xml.js";
|
|
9
9
|
import { visitPreservedFragments } from "../schema/preservedFragments.js";
|
|
10
10
|
import { unattributedCommentAuthors } from "../schema/protection.js";
|
|
11
|
+
import {
|
|
12
|
+
HEADER_FOOTER_KINDS,
|
|
13
|
+
NOTE_KINDS,
|
|
14
|
+
splitStoryKey,
|
|
15
|
+
storyKey
|
|
16
|
+
} from "../schema/stories.js";
|
|
11
17
|
import {
|
|
12
18
|
commentReferencesIn,
|
|
13
19
|
commentsChanged,
|
|
@@ -22,79 +28,122 @@ import {
|
|
|
22
28
|
} from "./comments/parts.js";
|
|
23
29
|
import { unrecordedAuthors } from "./comments/people.js";
|
|
24
30
|
import { currentCommentBodies } from "./comments/writing.js";
|
|
25
|
-
import { identityProblems } from "./identities.js";
|
|
31
|
+
import { identityProblems, identityProblemsInStories } from "./identities.js";
|
|
26
32
|
import { insertedImageSrcs } from "./media.js";
|
|
27
33
|
import { canDefineNewList, newNumIds, startedLists } from "./newLists.js";
|
|
34
|
+
import { firstNoteReferences } from "./notes/references.js";
|
|
28
35
|
import { CONTENT_TYPES_PATH } from "./packageParts.js";
|
|
36
|
+
import { STORY_ENTRIES_PARTS, STORY_WRITINGS } from "./partPlanners.js";
|
|
29
37
|
import { lostOriginal } from "./serializePreserved.js";
|
|
30
38
|
import {
|
|
31
39
|
originalBlock,
|
|
32
40
|
sessionOf
|
|
33
41
|
} from "./session.js";
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
42
|
+
import {
|
|
43
|
+
rewrittenStories,
|
|
44
|
+
storyChangesOf,
|
|
45
|
+
storyEntriesOf,
|
|
46
|
+
storyEntriesProblems,
|
|
47
|
+
unwrittenStoryChanges
|
|
48
|
+
} from "./storyParts.js";
|
|
49
|
+
function found(scope, pos, problem) {
|
|
50
|
+
return scope.story === null ? { ...problem, pos } : problem;
|
|
51
|
+
}
|
|
52
|
+
function overScopes(name, check) {
|
|
53
|
+
return {
|
|
54
|
+
name,
|
|
55
|
+
check: ({ scopes, session }) => scopes.flatMap((scope) => check(scope, session))
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
var bookmarkPairs = overScopes("bookmarkPairs", (scope, session) => {
|
|
59
|
+
const problems = [];
|
|
60
|
+
const open = /* @__PURE__ */ new Map();
|
|
61
|
+
const used = /* @__PURE__ */ new Set();
|
|
62
|
+
visitPreservedFragments(scope.doc, (node, pos, xml) => {
|
|
63
|
+
const source = xml ?? originalBlock(node, session)?.xml ?? null;
|
|
64
|
+
if (source === null) return;
|
|
65
|
+
if (!source.includes("bookmark")) return;
|
|
66
|
+
let root;
|
|
67
|
+
try {
|
|
68
|
+
root = parseXml(
|
|
69
|
+
session.documentPrefix + source + session.documentSuffix
|
|
70
|
+
).documentElement;
|
|
71
|
+
} catch {
|
|
72
|
+
problems.push(
|
|
73
|
+
found(scope, pos, {
|
|
51
74
|
code: "malformed-xml",
|
|
52
75
|
message: "preserved bookmark XML could not be parsed",
|
|
53
|
-
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
76
|
+
reason: { kind: "unreadable-preserved-xml", story: scope.story }
|
|
77
|
+
})
|
|
78
|
+
);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
for (const marker of Array.from(root.getElementsByTagName("*"))) {
|
|
82
|
+
if (marker.namespaceURI !== W_NS || marker.localName !== "bookmarkStart" && marker.localName !== "bookmarkEnd")
|
|
83
|
+
continue;
|
|
84
|
+
const kind = marker.localName.slice("bookmark".length);
|
|
85
|
+
const value = attributeByLocalName(marker, "id");
|
|
86
|
+
if (value === null || value === "") {
|
|
87
|
+
problems.push(
|
|
88
|
+
found(scope, pos, {
|
|
64
89
|
code: "malformed-xml",
|
|
65
90
|
message: `a bookmark${kind} has no id`,
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
91
|
+
reason: {
|
|
92
|
+
kind: "unnamed-bookmark",
|
|
93
|
+
marker: kind === "Start" ? "start" : "end",
|
|
94
|
+
story: scope.story
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
);
|
|
98
|
+
} else if (kind === "Start") {
|
|
99
|
+
if (used.has(value)) {
|
|
100
|
+
problems.push(
|
|
101
|
+
found(scope, pos, {
|
|
71
102
|
code: "malformed-xml",
|
|
72
103
|
message: `bookmark ${value} has more than one start marker`,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
104
|
+
reason: {
|
|
105
|
+
kind: "repeated-bookmark-start",
|
|
106
|
+
id: value,
|
|
107
|
+
story: scope.story
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
);
|
|
111
|
+
} else {
|
|
112
|
+
open.set(value, pos);
|
|
113
|
+
used.add(value);
|
|
114
|
+
}
|
|
115
|
+
} else if (!open.delete(value)) {
|
|
116
|
+
problems.push(
|
|
117
|
+
found(scope, pos, {
|
|
81
118
|
code: "malformed-xml",
|
|
82
119
|
message: `bookmark ${value} ends without an earlier start marker`,
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
120
|
+
reason: {
|
|
121
|
+
kind: "unmatched-bookmark",
|
|
122
|
+
id: value,
|
|
123
|
+
marker: "end",
|
|
124
|
+
story: scope.story
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
);
|
|
86
128
|
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
for (const [id, pos] of open) {
|
|
132
|
+
problems.push(
|
|
133
|
+
found(scope, pos, {
|
|
90
134
|
code: "malformed-xml",
|
|
91
135
|
message: `bookmark ${id} has no end marker`,
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
136
|
+
reason: {
|
|
137
|
+
kind: "unmatched-bookmark",
|
|
138
|
+
id,
|
|
139
|
+
marker: "start",
|
|
140
|
+
story: scope.story
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
);
|
|
96
144
|
}
|
|
97
|
-
|
|
145
|
+
return problems;
|
|
146
|
+
});
|
|
98
147
|
function mergeReachesPastLastRow(table) {
|
|
99
148
|
let overlong = false;
|
|
100
149
|
table.forEach((row, _offset, at) => {
|
|
@@ -106,113 +155,190 @@ function mergeReachesPastLastRow(table) {
|
|
|
106
155
|
});
|
|
107
156
|
return overlong;
|
|
108
157
|
}
|
|
109
|
-
var tableGrids = {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
problems.push({
|
|
158
|
+
var tableGrids = overScopes("tableGrids", (scope) => {
|
|
159
|
+
const problems = [];
|
|
160
|
+
scope.doc.descendants((node, pos) => {
|
|
161
|
+
if (node.type.name !== "table") return true;
|
|
162
|
+
if (mergeReachesPastLastRow(node)) {
|
|
163
|
+
problems.push(
|
|
164
|
+
found(scope, pos, {
|
|
117
165
|
code: "invalid-table",
|
|
118
166
|
message: "a vertical merge in the table reaches past the last row",
|
|
119
|
-
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
};
|
|
167
|
+
reason: { kind: "vertical-merge-past-table", story: scope.story }
|
|
168
|
+
})
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
return true;
|
|
172
|
+
});
|
|
173
|
+
return problems;
|
|
174
|
+
});
|
|
127
175
|
var CARRIES_ITS_XML = /* @__PURE__ */ new Set([
|
|
128
176
|
"rawInline",
|
|
129
177
|
"rawRunContent"
|
|
130
178
|
]);
|
|
131
|
-
function lostOriginalOf(node, session) {
|
|
179
|
+
function lostOriginalOf(node, session, story) {
|
|
132
180
|
if (CARRIES_ITS_XML.has(node.type.name)) {
|
|
133
|
-
return typeof node.attrs.xml === "string" ? null :
|
|
181
|
+
return typeof node.attrs.xml === "string" ? null : {
|
|
182
|
+
message: "a preserved element has lost its original XML",
|
|
183
|
+
reason: {
|
|
184
|
+
kind: "lost-preserved-xml",
|
|
185
|
+
node: node.type.name,
|
|
186
|
+
story
|
|
187
|
+
}
|
|
188
|
+
};
|
|
134
189
|
}
|
|
135
190
|
if (node.type.isInGroup("preserved")) {
|
|
136
191
|
if (typeof node.attrs.xml === "string") return null;
|
|
137
|
-
return originalBlock(node, session) ? null : lostOriginal(node, session);
|
|
192
|
+
return originalBlock(node, session) ? null : lostOriginal(node, session, story);
|
|
138
193
|
}
|
|
139
194
|
return null;
|
|
140
195
|
}
|
|
141
|
-
var preservedOriginals =
|
|
142
|
-
|
|
143
|
-
|
|
196
|
+
var preservedOriginals = overScopes(
|
|
197
|
+
"preservedOriginals",
|
|
198
|
+
(scope, session) => {
|
|
144
199
|
const problems = [];
|
|
145
|
-
doc.descendants((node, pos) => {
|
|
146
|
-
const
|
|
147
|
-
if (
|
|
148
|
-
problems.push({ code: "lost-original",
|
|
200
|
+
scope.doc.descendants((node, pos) => {
|
|
201
|
+
const lost = lostOriginalOf(node, session, scope.story);
|
|
202
|
+
if (lost !== null) {
|
|
203
|
+
problems.push(found(scope, pos, { code: "lost-original", ...lost }));
|
|
204
|
+
}
|
|
149
205
|
return true;
|
|
150
206
|
});
|
|
151
207
|
return problems;
|
|
152
208
|
}
|
|
153
|
-
|
|
209
|
+
);
|
|
154
210
|
var uniqueIdentities = {
|
|
155
211
|
name: "uniqueIdentities",
|
|
156
|
-
check(doc) {
|
|
157
|
-
|
|
212
|
+
check({ doc, session }) {
|
|
213
|
+
const parts = [
|
|
214
|
+
...HEADER_FOOTER_KINDS.flatMap(
|
|
215
|
+
(kind) => storyChangesOf(doc, session, kind).flatMap(
|
|
216
|
+
(change) => change.change === "edited" ? [
|
|
217
|
+
[
|
|
218
|
+
{
|
|
219
|
+
key: change.imported.key,
|
|
220
|
+
story: change.current,
|
|
221
|
+
frozen: false
|
|
222
|
+
}
|
|
223
|
+
]
|
|
224
|
+
] : []
|
|
225
|
+
)
|
|
226
|
+
),
|
|
227
|
+
...STORY_ENTRIES_PARTS.map((part) => storyEntriesOf(part, doc, session))
|
|
228
|
+
];
|
|
229
|
+
return [
|
|
230
|
+
...identityProblems(doc).map(
|
|
231
|
+
({ code, message, node, pos }) => ({
|
|
232
|
+
code,
|
|
233
|
+
message,
|
|
234
|
+
reason: { kind: "duplicate-preserved-block", node, story: null },
|
|
235
|
+
pos
|
|
236
|
+
})
|
|
237
|
+
),
|
|
238
|
+
...parts.flatMap(
|
|
239
|
+
(entries) => identityProblemsInStories(entries).map(
|
|
240
|
+
({ code, message, node, story }) => {
|
|
241
|
+
const entry = entries[story];
|
|
242
|
+
return {
|
|
243
|
+
code,
|
|
244
|
+
message,
|
|
245
|
+
reason: {
|
|
246
|
+
kind: "duplicate-preserved-block",
|
|
247
|
+
node,
|
|
248
|
+
story: entry === void 0 ? null : splitStoryKey(entry.key)
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
)
|
|
253
|
+
)
|
|
254
|
+
];
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
var storiesHaveWriters = {
|
|
258
|
+
name: "storiesHaveWriters",
|
|
259
|
+
check({ doc, session }) {
|
|
260
|
+
return unwrittenStoryChanges(STORY_WRITINGS, doc, session).map(
|
|
261
|
+
({ key, change }) => ({
|
|
262
|
+
code: "unsupported-content",
|
|
263
|
+
message: `the ${key} story was ${change}, and no part writer carries that into the file`,
|
|
264
|
+
reason: {
|
|
265
|
+
kind: "unwritten-story-change",
|
|
266
|
+
story: splitStoryKey(key),
|
|
267
|
+
change
|
|
268
|
+
}
|
|
269
|
+
})
|
|
270
|
+
);
|
|
158
271
|
}
|
|
159
272
|
};
|
|
273
|
+
function undefinedListProblems(scope, undefinedIds) {
|
|
274
|
+
const problems = [];
|
|
275
|
+
scope.doc.descendants((node, pos) => {
|
|
276
|
+
if (node.type.name !== "paragraph") return true;
|
|
277
|
+
const numId = toParagraphFormat(node.attrs.format)?.numbering?.numId;
|
|
278
|
+
if (numId === void 0 || !undefinedIds.delete(numId)) return false;
|
|
279
|
+
problems.push(
|
|
280
|
+
found(scope, pos, {
|
|
281
|
+
code: "unsupported-content",
|
|
282
|
+
message: `the list numbered ${numId} has no definition to be written`,
|
|
283
|
+
reason: { kind: "undefined-list", numId, story: scope.story }
|
|
284
|
+
})
|
|
285
|
+
);
|
|
286
|
+
return false;
|
|
287
|
+
});
|
|
288
|
+
return problems;
|
|
289
|
+
}
|
|
160
290
|
var listDefinitions = {
|
|
161
291
|
name: "listDefinitions",
|
|
162
|
-
check(doc, session) {
|
|
292
|
+
check({ doc, session, scopes }) {
|
|
163
293
|
const undefinedIds = new Set(startedLists(doc, session).unregistered);
|
|
164
294
|
if (undefinedIds.size === 0) return [];
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const numId = toParagraphFormat(node.attrs.format)?.numbering?.numId;
|
|
169
|
-
if (numId === void 0 || !undefinedIds.delete(numId)) return false;
|
|
170
|
-
problems.push({
|
|
171
|
-
code: "unsupported-content",
|
|
172
|
-
message: `the list numbered ${numId} has no definition to be written`,
|
|
173
|
-
pos
|
|
174
|
-
});
|
|
175
|
-
return false;
|
|
176
|
-
});
|
|
177
|
-
return problems;
|
|
295
|
+
return scopes.flatMap(
|
|
296
|
+
(scope) => undefinedListProblems(scope, undefinedIds)
|
|
297
|
+
);
|
|
178
298
|
}
|
|
179
299
|
};
|
|
180
|
-
function
|
|
300
|
+
function addedCommentsPart(doc, session) {
|
|
181
301
|
const bodyChanged = commentsChanged(doc, session);
|
|
182
302
|
const threadChanged = extensionsChanged(doc, session);
|
|
183
|
-
if (!bodyChanged && !threadChanged) return
|
|
184
|
-
if (commentsPart.pathIn(session) === null || session.comments.xml === null)
|
|
185
|
-
return
|
|
303
|
+
if (!bodyChanged && !threadChanged) return null;
|
|
304
|
+
if (commentsPart.pathIn(session) === null || session.comments.xml === null) {
|
|
305
|
+
return "comments";
|
|
306
|
+
}
|
|
186
307
|
const references = commentReferencesIn(doc);
|
|
187
|
-
if (threadChanged && (references.size > 0 || session.comments.extendedPartPath !== null) && (commentsExtendedPart.pathIn(session) === null || session.comments.extendedXml === null))
|
|
188
|
-
return
|
|
308
|
+
if (threadChanged && (references.size > 0 || session.comments.extendedPartPath !== null) && (commentsExtendedPart.pathIn(session) === null || session.comments.extendedXml === null)) {
|
|
309
|
+
return "commentsExtended";
|
|
310
|
+
}
|
|
189
311
|
return bodyChanged && (peoplePart.pathIn(session) === null || session.comments.people.xml === null) && unrecordedAuthors(
|
|
190
312
|
currentCommentBodies(references).values(),
|
|
191
313
|
session.comments.people,
|
|
192
314
|
unattributedCommentAuthors(session.comments.ordered)
|
|
193
|
-
).size > 0;
|
|
315
|
+
).size > 0 ? "people" : null;
|
|
194
316
|
}
|
|
195
317
|
var mediaContentTypes = {
|
|
196
318
|
name: "mediaContentTypes",
|
|
197
|
-
check(doc, session) {
|
|
319
|
+
check({ doc, session }) {
|
|
198
320
|
if (session.parts.has(CONTENT_TYPES_PATH)) return [];
|
|
199
321
|
const problems = [];
|
|
200
322
|
if (insertedImageSrcs(doc).length > 0) {
|
|
201
323
|
problems.push({
|
|
202
324
|
code: "missing-content-types",
|
|
203
|
-
message: `cannot add an image to a package that has no ${CONTENT_TYPES_PATH}
|
|
325
|
+
message: `cannot add an image to a package that has no ${CONTENT_TYPES_PATH}`,
|
|
326
|
+
reason: { kind: "missing-content-types", part: "media" }
|
|
204
327
|
});
|
|
205
328
|
}
|
|
206
329
|
if (!canDefineNewList(session) && newNumIds(doc, session).length > 0) {
|
|
207
330
|
problems.push({
|
|
208
331
|
code: "missing-content-types",
|
|
209
|
-
message: `cannot add a part to a package that has no ${CONTENT_TYPES_PATH}
|
|
332
|
+
message: `cannot add a part to a package that has no ${CONTENT_TYPES_PATH}`,
|
|
333
|
+
reason: { kind: "missing-content-types", part: "numbering" }
|
|
210
334
|
});
|
|
211
335
|
}
|
|
212
|
-
|
|
336
|
+
const comments = addedCommentsPart(doc, session);
|
|
337
|
+
if (comments !== null) {
|
|
213
338
|
problems.push({
|
|
214
339
|
code: "missing-content-types",
|
|
215
|
-
message: `cannot add a part to a package that has no ${CONTENT_TYPES_PATH}
|
|
340
|
+
message: `cannot add a part to a package that has no ${CONTENT_TYPES_PATH}`,
|
|
341
|
+
reason: { kind: "missing-content-types", part: comments }
|
|
216
342
|
});
|
|
217
343
|
}
|
|
218
344
|
return problems;
|
|
@@ -220,37 +346,95 @@ var mediaContentTypes = {
|
|
|
220
346
|
};
|
|
221
347
|
var commentPartRoots = {
|
|
222
348
|
name: "commentPartRoots",
|
|
223
|
-
check(doc, session) {
|
|
349
|
+
check({ doc, session }) {
|
|
224
350
|
const problems = [];
|
|
225
351
|
const { xml, extendedXml, extendedPartPath } = session.comments;
|
|
226
352
|
if (xml !== null && commentsChanged(doc, session)) {
|
|
227
353
|
const problem = commentsRootProblem(xml);
|
|
228
|
-
if (problem !== null)
|
|
229
|
-
problems.push({
|
|
354
|
+
if (problem !== null) {
|
|
355
|
+
problems.push({
|
|
356
|
+
code: "malformed-xml",
|
|
357
|
+
message: problem,
|
|
358
|
+
reason: { kind: "unwritable-part-root", part: "comments" }
|
|
359
|
+
});
|
|
360
|
+
}
|
|
230
361
|
}
|
|
231
362
|
if (extendedXml !== null && extensionsChanged(doc, session) && (commentReferencesIn(doc).size > 0 || extendedPartPath !== null)) {
|
|
232
363
|
const problem = extensionsRootProblem(extendedXml);
|
|
233
|
-
if (problem !== null)
|
|
234
|
-
problems.push({
|
|
364
|
+
if (problem !== null) {
|
|
365
|
+
problems.push({
|
|
366
|
+
code: "malformed-xml",
|
|
367
|
+
message: problem,
|
|
368
|
+
reason: { kind: "unwritable-part-root", part: "commentsExtended" }
|
|
369
|
+
});
|
|
370
|
+
}
|
|
235
371
|
}
|
|
236
372
|
return problems;
|
|
237
373
|
}
|
|
238
374
|
};
|
|
375
|
+
var notePartRoots = {
|
|
376
|
+
name: "notePartRoots",
|
|
377
|
+
check: ({ doc, session }) => STORY_ENTRIES_PARTS.flatMap(
|
|
378
|
+
(part) => storyEntriesProblems(part, doc, session)
|
|
379
|
+
)
|
|
380
|
+
};
|
|
381
|
+
function noteKeyIn(reason) {
|
|
382
|
+
const story = "story" in reason ? reason.story : null;
|
|
383
|
+
if (story === null) return null;
|
|
384
|
+
const kind = NOTE_KINDS.find((candidate) => candidate === story.kind);
|
|
385
|
+
return kind === void 0 ? null : storyKey(kind, story.id);
|
|
386
|
+
}
|
|
387
|
+
function atNoteReferences(problems, doc) {
|
|
388
|
+
let references = null;
|
|
389
|
+
const placed = (key) => {
|
|
390
|
+
references ??= firstNoteReferences(
|
|
391
|
+
doc,
|
|
392
|
+
new Set(
|
|
393
|
+
problems.flatMap(
|
|
394
|
+
({ pos, reason }) => pos === void 0 ? noteKeyIn(reason) ?? [] : []
|
|
395
|
+
)
|
|
396
|
+
)
|
|
397
|
+
);
|
|
398
|
+
return references.get(key);
|
|
399
|
+
};
|
|
400
|
+
return problems.map((problem) => {
|
|
401
|
+
const key = problem.pos === void 0 ? noteKeyIn(problem.reason) : null;
|
|
402
|
+
const pos = key === null ? void 0 : placed(key);
|
|
403
|
+
return pos === void 0 ? problem : { ...problem, pos };
|
|
404
|
+
});
|
|
405
|
+
}
|
|
239
406
|
var EXPORT_INVARIANTS = [
|
|
240
407
|
bookmarkPairs,
|
|
241
408
|
tableGrids,
|
|
242
409
|
preservedOriginals,
|
|
243
410
|
uniqueIdentities,
|
|
244
411
|
listDefinitions,
|
|
412
|
+
storiesHaveWriters,
|
|
245
413
|
mediaContentTypes,
|
|
246
|
-
commentPartRoots
|
|
414
|
+
commentPartRoots,
|
|
415
|
+
notePartRoots
|
|
247
416
|
];
|
|
417
|
+
function exportScopes(doc, session) {
|
|
418
|
+
return [
|
|
419
|
+
{ doc, story: null },
|
|
420
|
+
...rewrittenStories(STORY_WRITINGS, doc, session).map(({ key, story }) => ({
|
|
421
|
+
doc: story,
|
|
422
|
+
story: splitStoryKey(key)
|
|
423
|
+
}))
|
|
424
|
+
];
|
|
425
|
+
}
|
|
248
426
|
var answered = /* @__PURE__ */ new WeakMap();
|
|
249
427
|
function problemsOf(doc, session) {
|
|
250
428
|
const known = answered.get(doc);
|
|
251
429
|
if (known && known.session === session) return known.problems;
|
|
252
|
-
const
|
|
253
|
-
|
|
430
|
+
const subject = {
|
|
431
|
+
doc,
|
|
432
|
+
session,
|
|
433
|
+
scopes: exportScopes(doc, session)
|
|
434
|
+
};
|
|
435
|
+
const problems = atNoteReferences(
|
|
436
|
+
EXPORT_INVARIANTS.flatMap((invariant) => invariant.check(subject)),
|
|
437
|
+
doc
|
|
254
438
|
);
|
|
255
439
|
answered.set(doc, { session, problems });
|
|
256
440
|
return problems;
|
package/dist/docx/newLists.js
CHANGED
|
@@ -3,6 +3,7 @@ import { toParagraphFormat } from "../model/format.js";
|
|
|
3
3
|
import { NEW_LISTS_ATTR, newListsOf } from "../numbering/listRegistry.js";
|
|
4
4
|
import { parseNumbering } from "../numbering/parseNumbering.js";
|
|
5
5
|
import { R_NS } from "../ooxml/xml.js";
|
|
6
|
+
import { asStoryKey, storiesOf, storyNodeOf } from "../schema/stories.js";
|
|
6
7
|
import { CONTENT_TYPES_PATH } from "./packageParts.js";
|
|
7
8
|
var NUMBERING_REL_TYPE = `${R_NS}/numbering`;
|
|
8
9
|
var NUMBERING_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml";
|
|
@@ -15,20 +16,28 @@ function collectNumIds(node, into) {
|
|
|
15
16
|
};
|
|
16
17
|
if (visit(node)) node.descendants(visit);
|
|
17
18
|
}
|
|
18
|
-
function
|
|
19
|
+
function numIdsNow(doc) {
|
|
19
20
|
const used = /* @__PURE__ */ new Set();
|
|
20
|
-
collectNumIds(
|
|
21
|
+
collectNumIds(doc, used);
|
|
22
|
+
for (const key of Object.keys(storiesOf(doc))) {
|
|
23
|
+
const story = asStoryKey(key);
|
|
24
|
+
const node = story === null ? null : storyNodeOf(doc, story);
|
|
25
|
+
if (node !== null) collectNumIds(node, used);
|
|
26
|
+
}
|
|
21
27
|
return used;
|
|
22
28
|
}
|
|
23
29
|
function numIdsAtOpen(session) {
|
|
24
30
|
const used = /* @__PURE__ */ new Set();
|
|
25
31
|
for (const block of session.blocks) collectNumIds(block.node, used);
|
|
32
|
+
for (const story of session.stories.values()) {
|
|
33
|
+
for (const block of story.blocks) collectNumIds(block.node, used);
|
|
34
|
+
}
|
|
26
35
|
return used;
|
|
27
36
|
}
|
|
28
37
|
function newNumIds(doc, session) {
|
|
29
38
|
const defined = parseNumbering(session.numberingXml).lists;
|
|
30
39
|
const atOpen = numIdsAtOpen(session);
|
|
31
|
-
return Array.from(
|
|
40
|
+
return Array.from(numIdsNow(doc)).filter((numId) => !defined.has(numId) && !atOpen.has(numId)).sort((a, b) => a - b);
|
|
32
41
|
}
|
|
33
42
|
function startedLists(doc, session) {
|
|
34
43
|
const registered = newListsOf(doc.attrs[NEW_LISTS_ATTR]);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The note an edit puts into a document: a new, empty one, and a copy of one the document holds.
|
|
3
|
+
*
|
|
4
|
+
* Both are side stories (`docx/story`), written back by the notes part writer (`./writing`) as an
|
|
5
|
+
* entry of their own, which is why a copy names none of the blocks its original was read from.
|
|
6
|
+
*/
|
|
7
|
+
import { type Node as PMNode } from "prosemirror-model";
|
|
8
|
+
import { type NoteKind, type StoryKey } from "../../schema/stories";
|
|
9
|
+
import type { FormattingContext } from "../formatting";
|
|
10
|
+
import { type SessionStore } from "../session";
|
|
11
|
+
/**
|
|
12
|
+
* The elements that stand for a note's own number inside its entry, which is what Word draws the
|
|
13
|
+
* number from and what a note that keeps its number keeps (`editor/notes/noteSurface`).
|
|
14
|
+
*/
|
|
15
|
+
export declare const NOTE_NUMBER_ELEMENTS: readonly string[];
|
|
16
|
+
/**
|
|
17
|
+
* The run properties a note's number is written with: the document's own style for it where the
|
|
18
|
+
* document defines one, and superscript where it does not.
|
|
19
|
+
*/
|
|
20
|
+
export declare function noteNumberRunProps(kind: NoteKind, formatting: FormattingContext): string;
|
|
21
|
+
/**
|
|
22
|
+
* The story of a new note holding no text yet: one paragraph in the document's style for note
|
|
23
|
+
* text, opening with the note's number the way Word writes a note it inserts.
|
|
24
|
+
*/
|
|
25
|
+
export declare function newNoteStory(kind: NoteKind, formatting: FormattingContext): PMNode;
|
|
26
|
+
/**
|
|
27
|
+
* Every id a note of this kind already answers to: the entries the opened part holds, the stories
|
|
28
|
+
* the document holds, and the ids the references name, whether or not a note stands behind them.
|
|
29
|
+
*/
|
|
30
|
+
export declare function takenNoteIds(doc: PMNode, kind: NoteKind, reserved: ReadonlySet<StoryKey>): Set<string>;
|
|
31
|
+
/** The id one above the largest of these, and never below one */
|
|
32
|
+
export declare function nextNoteId(taken: Iterable<string>): string;
|
|
33
|
+
/**
|
|
34
|
+
* The story a copied reference's note is given: the same content, naming none of the blocks the
|
|
35
|
+
* original was read from and none of its paragraph ids, so the export writes it as an entry of its
|
|
36
|
+
* own rather than as the bytes of the original a second time (`docx/cloning`). A preserved block
|
|
37
|
+
* that only names its fragment takes the fragment's XML along.
|
|
38
|
+
*/
|
|
39
|
+
export declare function copiedNoteStory(story: PMNode, session: SessionStore | null): PMNode;
|