@portone/docx-editor 0.2.1 → 0.4.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 +155 -0
- package/CONTRIBUTING.md +5 -1
- package/dist/DocxEditor.d.ts +6 -0
- package/dist/DocxEditor.js +13 -29
- package/dist/core.d.ts +23 -8
- package/dist/core.js +9 -4
- package/dist/docx/cloning.d.ts +38 -0
- package/dist/docx/cloning.js +74 -0
- package/dist/docx/commentOnlyChange.d.ts +12 -7
- package/dist/docx/commentOnlyChange.js +9 -156
- package/dist/docx/comments/constants.d.ts +0 -1
- package/dist/docx/comments/constants.js +0 -2
- package/dist/docx/comments/grammar.d.ts +10 -4
- package/dist/docx/comments/grammar.js +12 -2
- package/dist/docx/comments/{verifying.d.ts → parts.d.ts} +26 -18
- package/dist/docx/comments/parts.js +279 -0
- package/dist/docx/comments/people.d.ts +11 -2
- package/dist/docx/comments/people.js +16 -92
- package/dist/docx/comments/policy.d.ts +7 -0
- package/dist/docx/comments/policy.js +43 -0
- package/dist/docx/comments/reading.js +8 -10
- package/dist/docx/comments/writing.d.ts +19 -7
- package/dist/docx/comments/writing.js +59 -112
- package/dist/docx/documentSettings.d.ts +7 -0
- package/dist/docx/documentSettings.js +10 -2
- package/dist/docx/exportDocx.d.ts +40 -5
- package/dist/docx/exportDocx.js +88 -74
- package/dist/docx/exportRefs.d.ts +5 -2
- package/dist/docx/exportRefs.js +3 -1
- package/dist/docx/fidelity.d.ts +43 -0
- package/dist/docx/fidelity.js +64 -0
- package/dist/docx/formatting/attrs.d.ts +45 -0
- package/dist/docx/formatting/attrs.js +86 -0
- package/dist/docx/formatting/context.d.ts +39 -0
- package/dist/docx/formatting/context.js +60 -0
- package/dist/docx/formatting/direct.d.ts +6 -5
- package/dist/docx/formatting/direct.js +52 -78
- package/dist/docx/formatting/resolve.d.ts +51 -0
- package/dist/docx/formatting/resolve.js +160 -0
- package/dist/docx/formatting/runProperties.d.ts +93 -0
- package/dist/docx/formatting/runProperties.js +316 -0
- package/dist/docx/formatting/styles.d.ts +25 -2
- package/dist/docx/formatting/styles.js +87 -6
- package/dist/docx/formatting/tabStops.js +7 -22
- package/dist/docx/formatting.d.ts +4 -1
- package/dist/docx/formatting.js +4 -1
- package/dist/docx/headersFooters.js +6 -13
- package/dist/docx/hyperlink.d.ts +14 -4
- package/dist/docx/hyperlink.js +4 -1
- package/dist/docx/identities.d.ts +67 -0
- package/dist/docx/identities.js +174 -0
- package/dist/docx/importDocx.d.ts +12 -1
- package/dist/docx/importDocx.js +90 -88
- package/dist/docx/importParagraph.d.ts +1 -1
- package/dist/docx/importParagraph.js +4 -3
- package/dist/docx/importTable.d.ts +2 -2
- package/dist/docx/importTable.js +69 -56
- package/dist/docx/invariants.d.ts +33 -0
- package/dist/docx/invariants.js +269 -0
- package/dist/docx/media.d.ts +6 -4
- package/dist/docx/media.js +6 -37
- package/dist/docx/newLists.d.ts +50 -0
- package/dist/docx/newLists.js +59 -0
- package/dist/docx/notes.js +3 -7
- package/dist/docx/numberingPlanner.d.ts +11 -0
- package/dist/docx/numberingPlanner.js +50 -0
- package/dist/docx/packageParts.d.ts +42 -0
- package/dist/docx/packageParts.js +135 -0
- package/dist/docx/pageGeometry.d.ts +2 -0
- package/dist/docx/pageGeometry.js +18 -9
- package/dist/docx/paraProps.d.ts +10 -22
- package/dist/docx/paraProps.js +47 -76
- package/dist/docx/partPlan.d.ts +36 -0
- package/dist/docx/partPlan.js +59 -0
- package/dist/docx/protectionPolicy.d.ts +127 -0
- package/dist/docx/protectionPolicy.js +169 -0
- package/dist/docx/relationships.d.ts +1 -1
- package/dist/docx/relationships.js +8 -13
- package/dist/docx/runProps.d.ts +9 -22
- package/dist/docx/runProps.js +15 -168
- package/dist/docx/scan.js +20 -52
- package/dist/docx/sdt.js +9 -34
- package/dist/docx/sdtProps.d.ts +8 -1
- package/dist/docx/sdtProps.js +10 -0
- package/dist/docx/serializeBlock.d.ts +2 -0
- package/dist/docx/serializeBlock.js +8 -5
- package/dist/docx/serializeTable.js +32 -15
- package/dist/docx/session.d.ts +42 -14
- package/dist/docx/session.js +53 -17
- package/dist/docx/tableFormatting/conditions.d.ts +76 -0
- package/dist/docx/tableFormatting/conditions.js +196 -0
- package/dist/docx/tableFormatting/editing.d.ts +7 -3
- package/dist/docx/tableFormatting/editing.js +111 -143
- package/dist/docx/tableFormatting/reading.d.ts +63 -23
- package/dist/docx/tableFormatting/reading.js +132 -38
- package/dist/docx/tableFormatting.d.ts +1 -0
- package/dist/docx/tableFormatting.js +1 -0
- package/dist/docx/tableTemplate.js +30 -19
- package/dist/download.d.ts +8 -5
- package/dist/download.js +2 -0
- package/dist/editor/clipboard/inlineFormatting.js +19 -30
- package/dist/editor/commands/comments/editing.d.ts +6 -2
- package/dist/editor/commands/comments/editing.js +19 -31
- package/dist/editor/commands/exportQueries.d.ts +15 -0
- package/dist/editor/commands/exportQueries.js +14 -0
- package/dist/editor/commands/fidelityQueries.d.ts +12 -0
- package/dist/editor/commands/fidelityQueries.js +8 -0
- package/dist/editor/commands/formatting/editing.d.ts +2 -2
- package/dist/editor/commands/formatting/editing.js +26 -108
- package/dist/editor/commands/formatting/propertyCommands.d.ts +21 -0
- package/dist/editor/commands/formatting/propertyCommands.js +108 -0
- package/dist/editor/commands/formatting/shared.d.ts +3 -3
- package/dist/editor/commands/formatting/shared.js +5 -2
- package/dist/editor/commands/indentCommands.js +5 -4
- package/dist/editor/commands/index.d.ts +11 -0
- package/dist/editor/commands/index.js +5 -0
- package/dist/editor/commands/linkCommands.js +5 -6
- package/dist/editor/commands/listCommands.d.ts +6 -3
- package/dist/editor/commands/listCommands.js +73 -30
- package/dist/editor/commands/lockCommands.d.ts +7 -1
- package/dist/editor/commands/lockCommands.js +35 -46
- package/dist/editor/commands/paragraphCommands.js +33 -31
- package/dist/editor/commands/spacingCommands.js +1 -1
- package/dist/editor/createEditor.d.ts +17 -29
- package/dist/editor/createEditor.js +58 -58
- package/dist/editor/documentStyles.d.ts +11 -35
- package/dist/editor/documentStyles.js +9 -52
- package/dist/editor/editorDocument.d.ts +57 -0
- package/dist/editor/editorDocument.js +86 -0
- package/dist/editor/externalClipboard.d.ts +13 -2
- package/dist/editor/externalClipboard.js +76 -75
- package/dist/editor/insertTable.js +4 -3
- package/dist/editor/paragraphEdits.d.ts +27 -19
- package/dist/editor/paragraphEdits.js +18 -19
- package/dist/editor/paragraphPlacement.d.ts +11 -0
- package/dist/editor/paragraphPlacement.js +18 -0
- package/dist/editor/plugins/displayDerivation.d.ts +47 -0
- package/dist/editor/plugins/displayDerivation.js +78 -0
- package/dist/editor/plugins/imagePaste.js +11 -7
- package/dist/editor/plugins/keymap.js +18 -3
- package/dist/editor/plugins/numberingDecorations.d.ts +14 -14
- package/dist/editor/plugins/numberingDecorations.js +50 -19
- package/dist/editor/plugins/paragraphDisplay.d.ts +7 -0
- package/dist/editor/plugins/paragraphDisplay.js +57 -0
- package/dist/editor/plugins/tabLayout.js +1 -1
- package/dist/editor/plugins/tableDisplay.d.ts +6 -0
- package/dist/editor/plugins/tableDisplay.js +30 -0
- package/dist/index.d.ts +2 -0
- package/dist/model/format.d.ts +80 -8
- package/dist/model/format.js +100 -22
- package/dist/model/tabStops.d.ts +9 -0
- package/dist/model/tabStops.js +18 -0
- package/dist/numbering/listRegistry.d.ts +37 -0
- package/dist/numbering/listRegistry.js +112 -0
- package/dist/numbering/listTemplate.d.ts +26 -17
- package/dist/numbering/listTemplate.js +88 -25
- package/dist/numbering/markers.d.ts +15 -6
- package/dist/numbering/markers.js +26 -59
- package/dist/numbering/parseNumbering.d.ts +84 -6
- package/dist/numbering/parseNumbering.js +131 -44
- package/dist/numbering/spellers.d.ts +15 -0
- package/dist/numbering/spellers.js +96 -0
- package/dist/numbering/writeNumbering.d.ts +8 -7
- package/dist/numbering/writeNumbering.js +28 -39
- package/dist/ooxml/childOrder.d.ts +34 -0
- package/dist/ooxml/childOrder.js +496 -0
- package/dist/ooxml/conformance.d.ts +28 -0
- package/dist/ooxml/conformance.js +20 -0
- package/dist/ooxml/element.d.ts +24 -11
- package/dist/ooxml/element.js +31 -12
- package/dist/ooxml/errors.d.ts +6 -5
- package/dist/ooxml/image.d.ts +4 -0
- package/dist/ooxml/image.js +2 -5
- package/dist/ooxml/names.d.ts +9 -0
- package/dist/ooxml/names.js +8 -1
- package/dist/ooxml/partSplice.d.ts +67 -0
- package/dist/ooxml/partSplice.js +176 -0
- package/dist/ooxml/props.d.ts +112 -0
- package/dist/{docx/propsXml.js → ooxml/props.js} +72 -200
- package/dist/ooxml/simpleTypes.d.ts +103 -0
- package/dist/ooxml/simpleTypes.js +182 -0
- package/dist/ooxml/tabStops.js +8 -27
- package/dist/ooxml/tagScan.d.ts +34 -0
- package/dist/ooxml/tagScan.js +108 -0
- package/dist/ooxml/units.d.ts +25 -13
- package/dist/ooxml/units.js +65 -31
- package/dist/ooxml/xml.d.ts +35 -15
- package/dist/ooxml/xml.js +43 -11
- package/dist/page/PageGuides.d.ts +1 -1
- package/dist/page/PageGuides.js +0 -13
- package/dist/page/blockKinds.d.ts +61 -0
- package/dist/page/blockKinds.js +11 -0
- package/dist/page/kinds/index.d.ts +6 -0
- package/dist/page/kinds/index.js +10 -0
- package/dist/page/kinds/paragraphKind.d.ts +10 -0
- package/dist/page/kinds/paragraphKind.js +71 -0
- package/dist/page/kinds/tableKind.d.ts +10 -0
- package/dist/page/kinds/tableKind.js +178 -0
- package/dist/page/measureBlocks.d.ts +3 -14
- package/dist/page/measureBlocks.js +24 -45
- package/dist/page/pageDecorations.d.ts +27 -44
- package/dist/page/pageDecorations.js +70 -152
- package/dist/page/pageLayout.d.ts +2 -29
- package/dist/page/pageLayout.js +39 -16
- package/dist/page/usePageLayout.d.ts +2 -24
- package/dist/page/usePageLayout.js +5 -48
- package/dist/schema/attrRoles.d.ts +25 -18
- package/dist/schema/attrRoles.js +110 -68
- package/dist/schema/displayDerivation.d.ts +82 -0
- package/dist/schema/displayDerivation.js +130 -0
- package/dist/schema/docxSchema.d.ts +3 -0
- package/dist/schema/docxSchema.js +58 -17
- package/dist/schema/editGuard.d.ts +1 -1
- package/dist/schema/guards.d.ts +37 -14
- package/dist/schema/guards.js +29 -3
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.js +2 -0
- package/dist/schema/locks.d.ts +11 -44
- package/dist/schema/locks.js +0 -9
- package/dist/schema/preservedGuards.d.ts +26 -6
- package/dist/schema/preservedGuards.js +31 -1
- package/dist/schema/protection.d.ts +7 -1
- package/dist/schema/protection.js +2 -1
- package/dist/schema/sourceEquality.d.ts +1 -9
- package/dist/schema/sourceEquality.js +1 -27
- package/dist/styles/classNames.d.ts +13 -2
- package/dist/styles/classNames.js +13 -2
- package/dist/styles/inlineStyle.js +15 -6
- package/dist/styles.css +16 -18
- package/dist/table/cellFormatting.d.ts +8 -1
- package/dist/table/cellFormatting.js +11 -20
- package/dist/table/commands.js +20 -18
- package/dist/table/format.d.ts +3 -0
- package/dist/table/format.js +3 -9
- package/dist/table/gridBorders.d.ts +24 -30
- package/dist/table/gridBorders.js +35 -59
- package/dist/table/merge.d.ts +2 -6
- package/dist/table/merge.js +5 -5
- package/package.json +7 -3
- package/dist/docx/comments/contentTypes.d.ts +0 -7
- package/dist/docx/comments/contentTypes.js +0 -38
- package/dist/docx/comments/verifying.js +0 -206
- package/dist/docx/formatting/effectiveParagraph.d.ts +0 -15
- package/dist/docx/formatting/effectiveParagraph.js +0 -81
- package/dist/docx/propsXml.d.ts +0 -67
- package/dist/docx/uniqueControls.d.ts +0 -14
- package/dist/docx/uniqueControls.js +0 -62
- package/dist/editor/plugins/commentReservations.d.ts +0 -5
- package/dist/editor/plugins/commentReservations.js +0 -26
- package/dist/editor/plugins/styledParagraphs.d.ts +0 -15
- package/dist/editor/plugins/styledParagraphs.js +0 -65
- package/dist/page/tableMeasurements.d.ts +0 -18
- package/dist/page/tableMeasurements.js +0 -119
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The lists that were started during editing, and the part their definitions are written into.
|
|
3
|
+
*
|
|
4
|
+
* Both the writer and the export invariants ask these questions, so they stand apart from the
|
|
5
|
+
* writer rather than being read off it.
|
|
6
|
+
*/
|
|
7
|
+
import type { Node as PMNode } from "prosemirror-model";
|
|
8
|
+
import { type NewList } from "../numbering/parseNumbering";
|
|
9
|
+
import type { SessionStore } from "./session";
|
|
10
|
+
/**
|
|
11
|
+
* How the main part relates the numbering part, and what the package declares that part to hold.
|
|
12
|
+
*
|
|
13
|
+
* The reader finds the part by this relationship and the writer relates a new one under it, so
|
|
14
|
+
* neither can name it differently from the other.
|
|
15
|
+
*/
|
|
16
|
+
export declare const NUMBERING_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
|
|
17
|
+
export declare const NUMBERING_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml";
|
|
18
|
+
/**
|
|
19
|
+
* The numbering ids that appeared during editing and have no definition.
|
|
20
|
+
*
|
|
21
|
+
* An id that was already in use without a definition when the document was opened is left alone,
|
|
22
|
+
* because exporting such a document without editing it must not disturb numbering.xml.
|
|
23
|
+
*/
|
|
24
|
+
export declare function newNumIds(doc: PMNode, session: SessionStore): number[];
|
|
25
|
+
/** The lists started during editing, split by whether a definition was registered for each */
|
|
26
|
+
export interface StartedLists {
|
|
27
|
+
/** The definition each list was started with, which is what goes into numbering.xml */
|
|
28
|
+
readonly defined: ReadonlyMap<number, NewList>;
|
|
29
|
+
/** The numbers a list was started under that no definition stands behind */
|
|
30
|
+
readonly unregistered: readonly number[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The lists started during editing, each against the definition it was started with.
|
|
34
|
+
*
|
|
35
|
+
* The definition is the one the document node carries (`numbering/listRegistry`), which the list
|
|
36
|
+
* commands and the clipboard record as they start a list. A number carrying none is reported here
|
|
37
|
+
* rather than written bare, which the export invariants turn into a refusal.
|
|
38
|
+
*/
|
|
39
|
+
export declare function startedLists(doc: PMNode, session: SessionStore): StartedLists;
|
|
40
|
+
/** The numbering part as it was opened, which a new definition is spliced into. null when the document has none */
|
|
41
|
+
export declare function numberingPartOf(session: SessionStore): {
|
|
42
|
+
path: string;
|
|
43
|
+
bytes: Uint8Array;
|
|
44
|
+
} | null;
|
|
45
|
+
/**
|
|
46
|
+
* Whether the definition of a new list has somewhere to go: the numbering part the document was
|
|
47
|
+
* opened with, or one written from scratch, which only a package that can declare what the new
|
|
48
|
+
* part holds may take.
|
|
49
|
+
*/
|
|
50
|
+
export declare function canDefineNewList(session: SessionStore): boolean;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// src/docx/newLists.ts
|
|
2
|
+
import { toParagraphFormat } from "../model/format.js";
|
|
3
|
+
import { NEW_LISTS_ATTR, newListsOf } from "../numbering/listRegistry.js";
|
|
4
|
+
import { parseNumbering } from "../numbering/parseNumbering.js";
|
|
5
|
+
import { R_NS } from "../ooxml/xml.js";
|
|
6
|
+
import { CONTENT_TYPES_PATH } from "./packageParts.js";
|
|
7
|
+
var NUMBERING_REL_TYPE = `${R_NS}/numbering`;
|
|
8
|
+
var NUMBERING_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml";
|
|
9
|
+
function collectNumIds(node, into) {
|
|
10
|
+
const visit = (candidate) => {
|
|
11
|
+
if (candidate.type.name !== "paragraph") return true;
|
|
12
|
+
const numId = toParagraphFormat(candidate.attrs.format)?.numbering?.numId;
|
|
13
|
+
if (numId !== void 0) into.add(numId);
|
|
14
|
+
return false;
|
|
15
|
+
};
|
|
16
|
+
if (visit(node)) node.descendants(visit);
|
|
17
|
+
}
|
|
18
|
+
function numIdsIn(node) {
|
|
19
|
+
const used = /* @__PURE__ */ new Set();
|
|
20
|
+
collectNumIds(node, used);
|
|
21
|
+
return used;
|
|
22
|
+
}
|
|
23
|
+
function numIdsAtOpen(session) {
|
|
24
|
+
const used = /* @__PURE__ */ new Set();
|
|
25
|
+
for (const block of session.blocks) collectNumIds(block.node, used);
|
|
26
|
+
return used;
|
|
27
|
+
}
|
|
28
|
+
function newNumIds(doc, session) {
|
|
29
|
+
const defined = parseNumbering(session.numberingXml).lists;
|
|
30
|
+
const atOpen = numIdsAtOpen(session);
|
|
31
|
+
return Array.from(numIdsIn(doc)).filter((numId) => !defined.has(numId) && !atOpen.has(numId)).sort((a, b) => a - b);
|
|
32
|
+
}
|
|
33
|
+
function startedLists(doc, session) {
|
|
34
|
+
const registered = newListsOf(doc.attrs[NEW_LISTS_ATTR]);
|
|
35
|
+
const defined = /* @__PURE__ */ new Map();
|
|
36
|
+
const unregistered = [];
|
|
37
|
+
for (const numId of newNumIds(doc, session)) {
|
|
38
|
+
const list = registered.get(numId);
|
|
39
|
+
if (list === void 0) unregistered.push(numId);
|
|
40
|
+
else defined.set(numId, list);
|
|
41
|
+
}
|
|
42
|
+
return { defined, unregistered };
|
|
43
|
+
}
|
|
44
|
+
function numberingPartOf(session) {
|
|
45
|
+
const path = session.numberingPartPath;
|
|
46
|
+
const bytes = path === null ? void 0 : session.parts.get(path);
|
|
47
|
+
return path === null || bytes === void 0 ? null : { path, bytes };
|
|
48
|
+
}
|
|
49
|
+
function canDefineNewList(session) {
|
|
50
|
+
return numberingPartOf(session) !== null || session.parts.has(CONTENT_TYPES_PATH);
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
NUMBERING_CONTENT_TYPE,
|
|
54
|
+
NUMBERING_REL_TYPE,
|
|
55
|
+
canDefineNewList,
|
|
56
|
+
newNumIds,
|
|
57
|
+
numberingPartOf,
|
|
58
|
+
startedLists
|
|
59
|
+
};
|
package/dist/docx/notes.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
R_NS,
|
|
8
8
|
W_NS
|
|
9
9
|
} from "../ooxml/xml.js";
|
|
10
|
-
import {
|
|
10
|
+
import { relatedPartPath } from "./packageParts.js";
|
|
11
11
|
var EMPTY_PART = {
|
|
12
12
|
partPath: null,
|
|
13
13
|
ordered: [],
|
|
@@ -29,12 +29,8 @@ function noteText(el) {
|
|
|
29
29
|
return Array.from(el.getElementsByTagNameNS(W_NS, "p")).map(inlineText).join("\n");
|
|
30
30
|
}
|
|
31
31
|
function notePart(parts, mainPartPath, kind) {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
(entry) => entry.type === relationshipType && !entry.external
|
|
35
|
-
);
|
|
36
|
-
if (!relationship) return EMPTY_PART;
|
|
37
|
-
const partPath = resolveTarget(mainPartPath, relationship.target);
|
|
32
|
+
const partPath = relatedPartPath(parts, mainPartPath, `${R_NS}/${kind}s`);
|
|
33
|
+
if (partPath === null) return EMPTY_PART;
|
|
38
34
|
const bytes = parts.get(partPath);
|
|
39
35
|
if (!bytes) return { ...EMPTY_PART, partPath };
|
|
40
36
|
const root = parseXml(decodeUtf8(bytes).text).documentElement;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The numbering part with the definition every list started during editing was started with
|
|
3
|
+
* spliced in, and the part itself when the document arrived without one.
|
|
4
|
+
*
|
|
5
|
+
* The original text is left as is and only the new definitions go in. A document that has no
|
|
6
|
+
* numbering part gets one written from scratch, with the relationship that finds it and the
|
|
7
|
+
* declaration of what it holds asked of the context, so the first list a document takes costs it
|
|
8
|
+
* nothing outside this planner. Nothing is written when no list was started.
|
|
9
|
+
*/
|
|
10
|
+
import type { PartPlanner } from "./partPlan";
|
|
11
|
+
export declare const numberingPlanner: PartPlanner;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// src/docx/numberingPlanner.ts
|
|
2
|
+
import { addListDefinitions } from "../numbering/writeNumbering.js";
|
|
3
|
+
import { elementXml, xmlnsAttr } from "../ooxml/element.js";
|
|
4
|
+
import { NAMESPACES, wName } from "../ooxml/names.js";
|
|
5
|
+
import { ensureRootDeclarations } from "../ooxml/partSplice.js";
|
|
6
|
+
import { decodeUtf8, encodeUtf8 } from "../ooxml/xml.js";
|
|
7
|
+
import {
|
|
8
|
+
NUMBERING_CONTENT_TYPE,
|
|
9
|
+
NUMBERING_REL_TYPE,
|
|
10
|
+
numberingPartOf,
|
|
11
|
+
startedLists
|
|
12
|
+
} from "./newLists.js";
|
|
13
|
+
import { availablePartPath } from "./packageParts.js";
|
|
14
|
+
import { directoryOf } from "./relationships.js";
|
|
15
|
+
function emptyNumberingPart() {
|
|
16
|
+
return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' + elementXml(wName("numbering"), [xmlnsAttr("w")]);
|
|
17
|
+
}
|
|
18
|
+
var numberingPlanner = {
|
|
19
|
+
name: "numbering",
|
|
20
|
+
plan(doc, session, context) {
|
|
21
|
+
const { defined } = startedLists(doc, session);
|
|
22
|
+
if (defined.size === 0) return null;
|
|
23
|
+
const original = numberingPartOf(session);
|
|
24
|
+
if (original === null) {
|
|
25
|
+
const path = session.numberingPartPath ?? availablePartPath(session.parts, session.mainPartPath, "numbering");
|
|
26
|
+
if (session.numberingPartPath === null) {
|
|
27
|
+
context.relationships.add({
|
|
28
|
+
type: NUMBERING_REL_TYPE,
|
|
29
|
+
target: path.slice(directoryOf(session.mainPartPath).length)
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
context.contentTypes.addOverride(path, NUMBERING_CONTENT_TYPE);
|
|
33
|
+
return /* @__PURE__ */ new Map([
|
|
34
|
+
[
|
|
35
|
+
path,
|
|
36
|
+
encodeUtf8(addListDefinitions(emptyNumberingPart(), defined), false)
|
|
37
|
+
]
|
|
38
|
+
]);
|
|
39
|
+
}
|
|
40
|
+
const { text, hadBom } = decodeUtf8(original.bytes);
|
|
41
|
+
const rewritten = ensureRootDeclarations(
|
|
42
|
+
addListDefinitions(text, defined),
|
|
43
|
+
{ namespaces: { w: NAMESPACES.w } }
|
|
44
|
+
);
|
|
45
|
+
return /* @__PURE__ */ new Map([[original.path, encodeUtf8(rewritten, hadBom)]]);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
export {
|
|
49
|
+
numberingPlanner
|
|
50
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a part sits in the package, asked one way by every reader and writer, and the content
|
|
3
|
+
* types part every part the export adds is declared in.
|
|
4
|
+
*
|
|
5
|
+
* A part beside the body is found through the relationship the main part declares for it, and a
|
|
6
|
+
* part the export adds takes the first name beside the main part that nothing has claimed. Each
|
|
7
|
+
* reader used to find its part with a lookup of its own, so the rule for what counts as the
|
|
8
|
+
* related part lived in five places.
|
|
9
|
+
*/
|
|
10
|
+
export declare const CONTENT_TYPES_PATH = "[Content_Types].xml";
|
|
11
|
+
/**
|
|
12
|
+
* Where the part the main part relates under this type sits. null for no such relationship, and
|
|
13
|
+
* for one that points outside the package, which no part of it can stand behind.
|
|
14
|
+
*/
|
|
15
|
+
export declare function relatedPartPath(parts: ReadonlyMap<string, Uint8Array>, mainPartPath: string, type: string): string | null;
|
|
16
|
+
/** A part as text, and null for a path there is no part at, so a missing relationship reads as a missing part */
|
|
17
|
+
export declare function readPart(parts: ReadonlyMap<string, Uint8Array>, path: string | null): string | null;
|
|
18
|
+
/** `comments.xml`, then `comments2.xml`, and so on beside the main part: the first name no part of the package has taken */
|
|
19
|
+
export declare function availablePartPath(parts: ReadonlyMap<string, Uint8Array>, mainPartPath: string, stem: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* The content types part as an export leaves it: what the package declared when it was opened,
|
|
22
|
+
* and every declaration the planners asked for on top, written once at the end.
|
|
23
|
+
*
|
|
24
|
+
* Each writer that added a part used to splice its own declaration in and hand the result to the
|
|
25
|
+
* next, so what the part came to hold depended on the order they were called in, and a writer
|
|
26
|
+
* called without the last one's result wrote over its declaration.
|
|
27
|
+
*/
|
|
28
|
+
export interface ContentTypeWriter {
|
|
29
|
+
/** Declares the type of the one part at this path */
|
|
30
|
+
addOverride(partPath: string, contentType: string): void;
|
|
31
|
+
/** Declares the type of every part with this extension */
|
|
32
|
+
addDefault(extension: string, contentType: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* The part with everything added, or null when nothing was added or everything asked for was
|
|
35
|
+
* declared already. The additions go right after the opening tag, the defaults ahead of the
|
|
36
|
+
* overrides, whichever order they were asked in.
|
|
37
|
+
*/
|
|
38
|
+
part(): Uint8Array | null;
|
|
39
|
+
}
|
|
40
|
+
/** XML parts named by OPC content types, even when their URI has no .xml suffix. */
|
|
41
|
+
export declare function declaredXmlParts(types: Uint8Array, paths: Iterable<string>): ReadonlySet<string>;
|
|
42
|
+
export declare function contentTypeWriter(parts: ReadonlyMap<string, Uint8Array>): ContentTypeWriter;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// src/docx/packageParts.ts
|
|
2
|
+
import { elementXml } from "../ooxml/element.js";
|
|
3
|
+
import { DocxExportError } from "../ooxml/errors.js";
|
|
4
|
+
import { rootPrefixOf, splicePart } from "../ooxml/partSplice.js";
|
|
5
|
+
import {
|
|
6
|
+
decodeUtf8,
|
|
7
|
+
elementChildren,
|
|
8
|
+
encodeUtf8,
|
|
9
|
+
parseXml
|
|
10
|
+
} from "../ooxml/xml.js";
|
|
11
|
+
import {
|
|
12
|
+
directoryOf,
|
|
13
|
+
readRelationships,
|
|
14
|
+
relsPathOf,
|
|
15
|
+
resolveTarget
|
|
16
|
+
} from "./relationships.js";
|
|
17
|
+
var CONTENT_TYPES_PATH = "[Content_Types].xml";
|
|
18
|
+
function relatedPartPath(parts, mainPartPath, type) {
|
|
19
|
+
const relationship = readRelationships(parts, relsPathOf(mainPartPath)).find(
|
|
20
|
+
(entry) => entry.type === type && !entry.external
|
|
21
|
+
);
|
|
22
|
+
return relationship === void 0 ? null : resolveTarget(mainPartPath, relationship.target);
|
|
23
|
+
}
|
|
24
|
+
function readPart(parts, path) {
|
|
25
|
+
const bytes = path === null ? void 0 : parts.get(path);
|
|
26
|
+
return bytes ? decodeUtf8(bytes).text : null;
|
|
27
|
+
}
|
|
28
|
+
function availablePartPath(parts, mainPartPath, stem) {
|
|
29
|
+
const directory = directoryOf(mainPartPath);
|
|
30
|
+
const taken = new Set(Array.from(parts.keys(), (path) => path.toLowerCase()));
|
|
31
|
+
for (let suffix = 0; ; suffix += 1) {
|
|
32
|
+
const path = `${directory}${stem}${suffix === 0 ? "" : suffix + 1}.xml`;
|
|
33
|
+
if (!taken.has(path.toLowerCase())) return path;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function declaredIn(text) {
|
|
37
|
+
let root;
|
|
38
|
+
try {
|
|
39
|
+
root = parseXml(text).documentElement;
|
|
40
|
+
} catch (cause) {
|
|
41
|
+
throw new DocxExportError(
|
|
42
|
+
"malformed-xml",
|
|
43
|
+
`${CONTENT_TYPES_PATH} could not be parsed`,
|
|
44
|
+
{ cause }
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
const defaults = /* @__PURE__ */ new Set();
|
|
48
|
+
const overrides = /* @__PURE__ */ new Set();
|
|
49
|
+
const xmlDefaults = /* @__PURE__ */ new Set();
|
|
50
|
+
const xmlOverrides = /* @__PURE__ */ new Set();
|
|
51
|
+
for (const el of elementChildren(root)) {
|
|
52
|
+
const extension = el.getAttribute("Extension");
|
|
53
|
+
const partName = el.getAttribute("PartName");
|
|
54
|
+
const contentType = (el.getAttribute("ContentType") ?? "").split(";")[0].trim().toLowerCase();
|
|
55
|
+
const xml = contentType === "application/xml" || contentType === "text/xml" || contentType.endsWith("+xml");
|
|
56
|
+
if (el.localName === "Default" && extension !== null) {
|
|
57
|
+
defaults.add(extension.toLowerCase());
|
|
58
|
+
if (xml) xmlDefaults.add(extension.toLowerCase());
|
|
59
|
+
}
|
|
60
|
+
if (el.localName === "Override" && partName !== null) {
|
|
61
|
+
overrides.add(partName.toLowerCase());
|
|
62
|
+
if (xml) xmlOverrides.add(partName.toLowerCase());
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return { defaults, overrides, xmlDefaults, xmlOverrides };
|
|
66
|
+
}
|
|
67
|
+
function declaredXmlParts(types, paths) {
|
|
68
|
+
const declared = declaredIn(decodeUtf8(types).text);
|
|
69
|
+
return new Set(
|
|
70
|
+
Array.from(paths).filter((path) => {
|
|
71
|
+
const name = `/${path}`.toLowerCase();
|
|
72
|
+
if (declared.overrides.has(name)) return declared.xmlOverrides.has(name);
|
|
73
|
+
const extension = path.slice(path.lastIndexOf(".") + 1).toLowerCase();
|
|
74
|
+
return declared.xmlDefaults.has(extension);
|
|
75
|
+
})
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
function contentTypeWriter(parts) {
|
|
79
|
+
const overrides = /* @__PURE__ */ new Map();
|
|
80
|
+
const defaults = /* @__PURE__ */ new Map();
|
|
81
|
+
return {
|
|
82
|
+
addOverride: (partPath, contentType) => {
|
|
83
|
+
const key = partPath.toLowerCase();
|
|
84
|
+
if (!overrides.has(key)) overrides.set(key, [partPath, contentType]);
|
|
85
|
+
},
|
|
86
|
+
addDefault: (extension, contentType) => {
|
|
87
|
+
const key = extension.toLowerCase();
|
|
88
|
+
if (!defaults.has(key)) defaults.set(key, [extension, contentType]);
|
|
89
|
+
},
|
|
90
|
+
part: () => {
|
|
91
|
+
if (overrides.size === 0 && defaults.size === 0) return null;
|
|
92
|
+
const original = parts.get(CONTENT_TYPES_PATH);
|
|
93
|
+
if (!original) {
|
|
94
|
+
throw new DocxExportError(
|
|
95
|
+
"missing-content-types",
|
|
96
|
+
`cannot declare a part in a package that has no ${CONTENT_TYPES_PATH}`
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
const { text, hadBom } = decodeUtf8(original);
|
|
100
|
+
const declared = declaredIn(text);
|
|
101
|
+
const prefix = rootPrefixOf(text);
|
|
102
|
+
const declarations = [
|
|
103
|
+
...Array.from(defaults.values()).filter(
|
|
104
|
+
([extension]) => !declared.defaults.has(extension.toLowerCase())
|
|
105
|
+
).map(
|
|
106
|
+
([extension, contentType]) => elementXml(`${prefix}Default`, [
|
|
107
|
+
["Extension", extension],
|
|
108
|
+
["ContentType", contentType]
|
|
109
|
+
])
|
|
110
|
+
),
|
|
111
|
+
...Array.from(overrides.values()).filter(
|
|
112
|
+
([partPath]) => !declared.overrides.has(`/${partPath}`.toLowerCase())
|
|
113
|
+
).map(
|
|
114
|
+
([partPath, contentType]) => elementXml(`${prefix}Override`, [
|
|
115
|
+
["PartName", `/${partPath}`],
|
|
116
|
+
["ContentType", contentType]
|
|
117
|
+
])
|
|
118
|
+
)
|
|
119
|
+
];
|
|
120
|
+
if (declarations.length === 0) return null;
|
|
121
|
+
return encodeUtf8(
|
|
122
|
+
splicePart(text, { root: "Types", prepend: declarations.join("") }),
|
|
123
|
+
hadBom
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
export {
|
|
129
|
+
CONTENT_TYPES_PATH,
|
|
130
|
+
availablePartPath,
|
|
131
|
+
contentTypeWriter,
|
|
132
|
+
declaredXmlParts,
|
|
133
|
+
readPart,
|
|
134
|
+
relatedPartPath
|
|
135
|
+
};
|
|
@@ -21,6 +21,8 @@ export interface PageGeometry {
|
|
|
21
21
|
marginTopTwips: number;
|
|
22
22
|
marginBottomTwips: number;
|
|
23
23
|
}
|
|
24
|
+
/** CSS calls an inch 96 pixels, and a point is a 72nd of one */
|
|
25
|
+
export declare const PX_PER_PT: number;
|
|
24
26
|
export declare function twipsToPx(twips: number): number;
|
|
25
27
|
/**
|
|
26
28
|
* The paper a document that says nothing is drawn on: A4 portrait with the margins this
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
// src/docx/pageGeometry.ts
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
ST_SignedTwipsMeasure,
|
|
4
|
+
ST_TwipsMeasure,
|
|
5
|
+
TWIPS_PER_INCH,
|
|
6
|
+
TWIPS_PER_PT
|
|
7
|
+
} from "../ooxml/simpleTypes.js";
|
|
8
|
+
import { wAttr } from "../ooxml/units.js";
|
|
3
9
|
import { childByLocalName } from "../ooxml/xml.js";
|
|
4
|
-
var TWIPS_PER_CM =
|
|
5
|
-
var
|
|
10
|
+
var TWIPS_PER_CM = TWIPS_PER_INCH / 2.54;
|
|
11
|
+
var PX_PER_PT = 96 / 72;
|
|
12
|
+
var PX_PER_TWIP = PX_PER_PT / TWIPS_PER_PT;
|
|
6
13
|
function cm(value) {
|
|
7
14
|
return Math.round(value * TWIPS_PER_CM);
|
|
8
15
|
}
|
|
@@ -34,13 +41,14 @@ function readPageGeometry(sectPr) {
|
|
|
34
41
|
if (!sectPr) return A4_PORTRAIT;
|
|
35
42
|
const pgSz = childByLocalName(sectPr, "pgSz");
|
|
36
43
|
const pgMar = childByLocalName(sectPr, "pgMar");
|
|
37
|
-
const width = pgSz ? readSize(
|
|
38
|
-
const height = pgSz ? readSize(
|
|
44
|
+
const width = pgSz ? readSize(ST_TwipsMeasure.parse(wAttr(pgSz, "w"))) : null;
|
|
45
|
+
const height = pgSz ? readSize(ST_TwipsMeasure.parse(wAttr(pgSz, "h"))) : null;
|
|
39
46
|
const readable = width !== null && height !== null;
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
const
|
|
47
|
+
const margin = (side) => pgMar ? ST_SignedTwipsMeasure.parse(wAttr(pgMar, side)) : null;
|
|
48
|
+
const marginLeft = margin("left");
|
|
49
|
+
const marginRight = margin("right");
|
|
50
|
+
const marginTop = margin("top");
|
|
51
|
+
const marginBottom = margin("bottom");
|
|
44
52
|
const geometry = {
|
|
45
53
|
widthTwips: readable ? width : A4_PORTRAIT.widthTwips,
|
|
46
54
|
heightTwips: readable ? height : A4_PORTRAIT.heightTwips,
|
|
@@ -79,6 +87,7 @@ function firstSectPrIn(root) {
|
|
|
79
87
|
export {
|
|
80
88
|
A4_BODY_WIDTH,
|
|
81
89
|
A4_PORTRAIT,
|
|
90
|
+
PX_PER_PT,
|
|
82
91
|
bodyHeightTwips,
|
|
83
92
|
bodyWidth,
|
|
84
93
|
bodyWidthTwips,
|
package/dist/docx/paraProps.d.ts
CHANGED
|
@@ -5,14 +5,12 @@
|
|
|
5
5
|
* When one paragraph is changed, the formatting we do not touch, such as tab stops and borders,
|
|
6
6
|
* must stay as the original text wrote it. So we never rebuild the fragment; we change it one child
|
|
7
7
|
* at a time, and within a child one attribute at a time.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* and reopening.
|
|
8
|
+
* What the edited fragment is drawn with is not decided here: the caller hands the fragment to the
|
|
9
|
+
* resolver (`formatting/resolve`), the same one opening the document uses, so a changed paragraph's
|
|
10
|
+
* display values are the same as they would be after saving and reopening.
|
|
12
11
|
*/
|
|
13
|
-
import type { LineSpacing, NumberingRef, ParagraphAlign
|
|
12
|
+
import type { LineSpacing, NumberingRef, ParagraphAlign } from "../model/format";
|
|
14
13
|
import type { LevelIndent } from "../numbering/parseNumbering";
|
|
15
|
-
import { type StyleTable } from "./formatting";
|
|
16
14
|
/** What to do with the indents */
|
|
17
15
|
export type IndentChange =
|
|
18
16
|
/** Leaves the indents the paragraph wrote down as they are */
|
|
@@ -33,32 +31,22 @@ export interface ListChange {
|
|
|
33
31
|
numbering: NumberingRef | null;
|
|
34
32
|
indent: IndentChange;
|
|
35
33
|
}
|
|
36
|
-
/** The paragraph formatting we operated on
|
|
34
|
+
/** The paragraph formatting we operated on. A null `pPr` is a fragment with nothing left in it */
|
|
37
35
|
export interface ParagraphProps {
|
|
38
36
|
pPr: string | null;
|
|
39
|
-
format: ParagraphFormat | null;
|
|
40
|
-
/** The character formatting the style the paragraph now wears lays down (`styleRun` in `schema`) */
|
|
41
|
-
styleRun: RunFormat | null;
|
|
42
37
|
}
|
|
43
|
-
|
|
44
|
-
* Reads the fragment we operated on back along the same path used when opening the document.
|
|
45
|
-
*
|
|
46
|
-
* The values of the style the paragraph wears are laid down underneath (the same order as import),
|
|
47
|
-
* which for a paragraph pointing at no style of its own is the document's default paragraph style.
|
|
48
|
-
*/
|
|
49
|
-
export declare function readParagraphProps(pPr: string | null, styles?: StyleTable, defaultStyleId?: string | null): ParagraphFormat | null;
|
|
50
|
-
export declare function withListNumbering(pPr: string | null, change: ListChange, styles?: StyleTable, defaultStyleId?: string | null): ParagraphProps | null;
|
|
38
|
+
export declare function withListNumbering(pPr: string | null, change: ListChange): ParagraphProps | null;
|
|
51
39
|
/**
|
|
52
40
|
* The result of moving the paragraph's own left indent to `leftTwips`.
|
|
53
41
|
* Everything else the indent recorded - the hanging or first-line indent, the right indent -
|
|
54
42
|
* stays as it was.
|
|
55
43
|
*/
|
|
56
|
-
export declare function withLeftIndent(pPr: string | null, leftTwips: number
|
|
44
|
+
export declare function withLeftIndent(pPr: string | null, leftTwips: number): ParagraphProps | null;
|
|
57
45
|
/**
|
|
58
46
|
* The result of changing the line spacing. The space above and below the paragraph is left as it was.
|
|
59
47
|
* `auto` states the multiple in 240ths of a line; the other rules pin the height down in twips.
|
|
60
48
|
*/
|
|
61
|
-
export declare function withLineSpacing(pPr: string | null, spacing: LineSpacing
|
|
49
|
+
export declare function withLineSpacing(pPr: string | null, spacing: LineSpacing): ParagraphProps | null;
|
|
62
50
|
/**
|
|
63
51
|
* The result of pointing the paragraph at a named style.
|
|
64
52
|
* A null id takes the pStyle away, which is how the default style is worn.
|
|
@@ -66,9 +54,9 @@ export declare function withLineSpacing(pPr: string | null, spacing: LineSpacing
|
|
|
66
54
|
* Nothing else in the fragment moves: as in Word, a style is applied by naming it and not by
|
|
67
55
|
* copying its values into the paragraph, so the direct formatting written here keeps beating it.
|
|
68
56
|
*/
|
|
69
|
-
export declare function withParagraphStyle(pPr: string | null, styleId: string | null
|
|
57
|
+
export declare function withParagraphStyle(pPr: string | null, styleId: string | null): ParagraphProps | null;
|
|
70
58
|
/**
|
|
71
59
|
* The result of changing the paragraph alignment.
|
|
72
60
|
* One alignment is always on, so we provide no way to withdraw the setting (the same as Word).
|
|
73
61
|
*/
|
|
74
|
-
export declare function withParagraphAlign(pPr: string | null, align: ParagraphAlign
|
|
62
|
+
export declare function withParagraphAlign(pPr: string | null, align: ParagraphAlign): ParagraphProps | null;
|