@portone/docx-editor 0.2.0 → 0.3.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 +174 -0
- package/CONTRIBUTING.md +9 -1
- package/dist/DocxEditor.d.ts +6 -0
- package/dist/DocxEditor.js +12 -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 +14 -7
- package/dist/docx/commentOnlyChange.js +9 -139
- package/dist/docx/comments/constants.d.ts +3 -4
- package/dist/docx/comments/constants.js +4 -5
- package/dist/docx/comments/grammar.d.ts +86 -0
- package/dist/docx/comments/grammar.js +223 -0
- package/dist/docx/comments/parts.d.ts +52 -0
- package/dist/docx/comments/parts.js +279 -0
- package/dist/docx/comments/people.d.ts +11 -2
- package/dist/docx/comments/people.js +28 -106
- package/dist/docx/comments/policy.d.ts +7 -0
- package/dist/docx/comments/policy.js +43 -0
- package/dist/docx/comments/reading.d.ts +5 -3
- package/dist/docx/comments/reading.js +30 -29
- package/dist/docx/comments/writing.d.ts +19 -7
- package/dist/docx/comments/writing.js +105 -137
- 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 +71 -72
- 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 +27 -0
- package/dist/docx/formatting/attrs.js +31 -0
- package/dist/docx/formatting/context.d.ts +31 -0
- package/dist/docx/formatting/context.js +42 -0
- package/dist/docx/formatting/direct.d.ts +6 -5
- package/dist/docx/formatting/direct.js +52 -81
- package/dist/docx/formatting/resolve.d.ts +45 -0
- package/dist/docx/formatting/resolve.js +140 -0
- package/dist/docx/formatting/runProperties.d.ts +93 -0
- package/dist/docx/formatting/runProperties.js +316 -0
- package/dist/docx/formatting/styles.js +3 -3
- 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 +13 -22
- 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 +72 -79
- package/dist/docx/importParagraph.d.ts +1 -1
- package/dist/docx/importParagraph.js +4 -3
- package/dist/docx/importTable.d.ts +1 -1
- package/dist/docx/importTable.js +17 -1
- package/dist/docx/invariants.d.ts +33 -0
- package/dist/docx/invariants.js +256 -0
- package/dist/docx/media.d.ts +6 -4
- package/dist/docx/media.js +6 -37
- package/dist/docx/newLists.d.ts +20 -0
- package/dist/docx/newLists.js +36 -0
- package/dist/docx/notes.js +6 -12
- package/dist/docx/numberingPlanner.d.ts +8 -0
- package/dist/docx/numberingPlanner.js +19 -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 +75 -99
- 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 +15 -15
- 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 +14 -37
- 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 +9 -7
- package/dist/docx/serializeParagraph.d.ts +2 -1
- package/dist/docx/serializeParagraph.js +25 -14
- package/dist/docx/serializeTable.js +63 -32
- package/dist/docx/session.d.ts +42 -14
- package/dist/docx/session.js +43 -17
- package/dist/docx/storyProjection.d.ts +36 -0
- package/dist/docx/storyProjection.js +23 -0
- package/dist/docx/tableFormatting/editing.js +130 -185
- package/dist/docx/tableFormatting/reading.d.ts +16 -6
- package/dist/docx/tableFormatting/reading.js +40 -20
- package/dist/docx/tableTemplate.js +37 -5
- package/dist/docx/theme.d.ts +0 -6
- package/dist/docx/theme.js +0 -8
- package/dist/download.d.ts +8 -5
- package/dist/download.js +2 -0
- package/dist/editor/clipboard/images.js +17 -3
- package/dist/editor/clipboard/inlineFormatting.d.ts +7 -0
- package/dist/editor/clipboard/inlineFormatting.js +20 -30
- package/dist/editor/commands/breakCommands.js +4 -3
- package/dist/editor/commands/canRunCommand.d.ts +2 -2
- package/dist/editor/commands/canRunCommand.js +1 -1
- package/dist/editor/commands/comments/editing.d.ts +6 -2
- package/dist/editor/commands/comments/editing.js +21 -36
- 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 +103 -0
- package/dist/editor/commands/formatting/shared.d.ts +3 -3
- package/dist/editor/commands/formatting/shared.js +5 -2
- package/dist/editor/commands/historyCommands.js +2 -1
- 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.js +8 -10
- package/dist/editor/commands/lockCommands.d.ts +7 -1
- package/dist/editor/commands/lockCommands.js +35 -37
- package/dist/editor/commands/paragraphCommands.js +28 -31
- package/dist/editor/commands/spacingCommands.js +1 -1
- package/dist/editor/commands/tabCommands.js +4 -3
- package/dist/editor/createEditor.d.ts +17 -29
- package/dist/editor/createEditor.js +61 -67
- package/dist/editor/documentStyles.d.ts +11 -35
- package/dist/editor/documentStyles.js +9 -52
- package/dist/editor/editorDocument.d.ts +56 -0
- package/dist/editor/editorDocument.js +74 -0
- package/dist/editor/externalClipboard.js +166 -33
- package/dist/editor/insertImage.js +4 -3
- package/dist/editor/insertTable.js +4 -3
- package/dist/editor/paragraphEdits.d.ts +11 -18
- package/dist/editor/paragraphEdits.js +7 -16
- package/dist/editor/plugins/displayDerivation.d.ts +47 -0
- package/dist/editor/plugins/displayDerivation.js +78 -0
- package/dist/editor/plugins/documentProtection.d.ts +3 -3
- package/dist/editor/plugins/imagePaste.js +4 -3
- package/dist/editor/plugins/keymap.js +18 -3
- package/dist/editor/plugins/lockedContent.d.ts +4 -4
- package/dist/editor/plugins/lockedContent.js +1 -1
- package/dist/editor/plugins/numberingDecorations.d.ts +5 -11
- package/dist/editor/plugins/numberingDecorations.js +7 -17
- package/dist/editor/plugins/paragraphDisplay.d.ts +7 -0
- package/dist/editor/plugins/paragraphDisplay.js +51 -0
- package/dist/editor/plugins/tabLayout.js +1 -1
- package/dist/editor/plugins/tableDisplay.d.ts +6 -0
- package/dist/editor/plugins/tableDisplay.js +16 -0
- package/dist/index.d.ts +2 -0
- package/dist/model/format.d.ts +30 -8
- package/dist/model/format.js +35 -22
- package/dist/model/tabStops.d.ts +9 -0
- package/dist/model/tabStops.js +18 -0
- package/dist/numbering/listTemplate.js +49 -10
- package/dist/numbering/parseNumbering.d.ts +14 -1
- package/dist/numbering/parseNumbering.js +35 -22
- package/dist/numbering/writeNumbering.d.ts +3 -4
- package/dist/numbering/writeNumbering.js +14 -25
- package/dist/ooxml/childOrder.d.ts +34 -0
- package/dist/ooxml/childOrder.js +496 -0
- package/dist/ooxml/element.d.ts +65 -0
- package/dist/ooxml/element.js +68 -0
- package/dist/ooxml/errors.d.ts +3 -2
- package/dist/ooxml/fragment.d.ts +53 -0
- package/dist/ooxml/fragment.js +76 -0
- package/dist/ooxml/image.d.ts +4 -0
- package/dist/ooxml/image.js +3 -5
- package/dist/ooxml/names.d.ts +27 -0
- package/dist/ooxml/names.js +29 -0
- package/dist/ooxml/partSplice.d.ts +67 -0
- package/dist/ooxml/partSplice.js +169 -0
- package/dist/ooxml/precedence.d.ts +31 -0
- package/dist/ooxml/precedence.js +51 -0
- package/dist/ooxml/props.d.ts +112 -0
- package/dist/ooxml/props.js +214 -0
- 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 +52 -0
- package/dist/ooxml/xml.js +64 -5
- package/dist/page/blockKinds.d.ts +103 -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 -1
- package/dist/page/measureBlocks.js +24 -25
- package/dist/page/pageDecorations.d.ts +27 -28
- package/dist/page/pageDecorations.js +70 -151
- package/dist/page/pageLayout.d.ts +10 -62
- package/dist/page/pageLayout.js +60 -53
- package/dist/page/usePageLayout.d.ts +2 -2
- package/dist/page/usePageLayout.js +3 -11
- package/dist/schema/attrRoles.d.ts +42 -0
- package/dist/schema/attrRoles.js +141 -0
- package/dist/schema/displayDerivation.d.ts +82 -0
- package/dist/schema/displayDerivation.js +130 -0
- package/dist/schema/docxSchema.d.ts +9 -0
- package/dist/schema/docxSchema.js +237 -114
- package/dist/schema/editGuard.d.ts +99 -0
- package/dist/schema/editGuard.js +43 -0
- package/dist/schema/guards.d.ts +91 -0
- package/dist/schema/guards.js +108 -0
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.js +2 -0
- package/dist/schema/locks.d.ts +17 -77
- package/dist/schema/locks.js +26 -70
- package/dist/schema/preservedGuards.d.ts +50 -0
- package/dist/schema/preservedGuards.js +80 -0
- package/dist/schema/protection.d.ts +17 -4
- package/dist/schema/protection.js +4 -2
- package/dist/schema/sourceEquality.d.ts +19 -0
- package/dist/schema/sourceEquality.js +39 -0
- package/dist/styles/inlineStyle.js +15 -6
- package/dist/table/cellFormatting.d.ts +8 -1
- package/dist/table/cellFormatting.js +10 -17
- package/dist/table/commands.d.ts +2 -2
- 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 +14 -16
- package/dist/table/gridBorders.js +3 -41
- package/dist/table/index.d.ts +2 -2
- package/dist/table/merge.d.ts +4 -8
- package/dist/table/merge.js +5 -5
- package/package.json +10 -3
- package/dist/docx/comments/contentTypes.d.ts +0 -7
- package/dist/docx/comments/contentTypes.js +0 -38
- package/dist/docx/formatting/effectiveParagraph.d.ts +0 -15
- package/dist/docx/formatting/effectiveParagraph.js +0 -81
- package/dist/docx/propsXml.d.ts +0 -49
- package/dist/docx/propsXml.js +0 -302
- package/dist/docx/uniqueControls.d.ts +0 -14
- package/dist/docx/uniqueControls.js +0 -62
- package/dist/editor/plugins/bookmarkProtection.d.ts +0 -3
- package/dist/editor/plugins/bookmarkProtection.js +0 -28
- package/dist/editor/plugins/commentReservations.d.ts +0 -5
- package/dist/editor/plugins/commentReservations.js +0 -26
- package/dist/editor/plugins/noteProtection.d.ts +0 -3
- package/dist/editor/plugins/noteProtection.js +0 -25
- package/dist/editor/plugins/styledParagraphs.d.ts +0 -15
- package/dist/editor/plugins/styledParagraphs.js +0 -65
- package/dist/page/tableMeasurements.d.ts +0 -10
- package/dist/page/tableMeasurements.js +0 -115
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// src/schema/editGuard.ts
|
|
2
|
+
import {
|
|
3
|
+
AddMarkStep,
|
|
4
|
+
AddNodeMarkStep,
|
|
5
|
+
AttrStep,
|
|
6
|
+
RemoveMarkStep,
|
|
7
|
+
RemoveNodeMarkStep,
|
|
8
|
+
ReplaceAroundStep,
|
|
9
|
+
ReplaceStep
|
|
10
|
+
} from "prosemirror-transform";
|
|
11
|
+
function rangeHolds(doc, from, to, holds) {
|
|
12
|
+
let found = false;
|
|
13
|
+
doc.nodesBetween(from, to, (node) => {
|
|
14
|
+
if (found) return false;
|
|
15
|
+
if (holds(node)) found = true;
|
|
16
|
+
return !found;
|
|
17
|
+
});
|
|
18
|
+
return found;
|
|
19
|
+
}
|
|
20
|
+
function stepReaches(step, before, after, holds) {
|
|
21
|
+
if (step instanceof AttrStep || step instanceof AddNodeMarkStep || step instanceof RemoveNodeMarkStep) {
|
|
22
|
+
const node = before.nodeAt(step.pos);
|
|
23
|
+
return node !== null && holds(node);
|
|
24
|
+
}
|
|
25
|
+
if (!(step instanceof ReplaceStep || step instanceof ReplaceAroundStep || step instanceof AddMarkStep || step instanceof RemoveMarkStep)) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
let reached = false;
|
|
29
|
+
step.getMap().forEach((oldStart, oldEnd, newStart, newEnd) => {
|
|
30
|
+
reached ||= rangeHolds(before, oldStart, oldEnd, holds) || rangeHolds(after, newStart, newEnd, holds);
|
|
31
|
+
});
|
|
32
|
+
return reached;
|
|
33
|
+
}
|
|
34
|
+
function transactionReaches(tr, holds) {
|
|
35
|
+
return tr.steps.some(
|
|
36
|
+
(step, index) => stepReaches(step, tr.docs[index], tr.docs[index + 1] ?? tr.doc, holds)
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
rangeHolds,
|
|
41
|
+
stepReaches,
|
|
42
|
+
transactionReaches
|
|
43
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one list an edit is judged against.
|
|
3
|
+
*
|
|
4
|
+
* A guard answers, for one rule, whether an edit would leave the document in a state the file
|
|
5
|
+
* cannot be written back from. `transactionAllowed` runs the list over a built transaction, both
|
|
6
|
+
* where an edit is dispatched (`editor/plugins/lockedContent`) and where a command is dry-run
|
|
7
|
+
* (`editor/commands/canRunCommand`), and `editShut` runs it over the intent a command has before
|
|
8
|
+
* it builds anything. Both ask the same list, which is what keeps a disabled control and a refused
|
|
9
|
+
* edit saying the same thing.
|
|
10
|
+
*
|
|
11
|
+
* What a guard is written against - `EditGuard`, `EditIntent` and the reach primitives - stands in
|
|
12
|
+
* `./editGuard` so that a module writing a guard need not read this one, and is handed on from
|
|
13
|
+
* here so that a caller has one door to the whole seam.
|
|
14
|
+
*
|
|
15
|
+
* A command decides nothing of its own about any of this. It takes one of the two shapes an edit
|
|
16
|
+
* comes in - `guardedCommand`, which builds the whole edit and is refused whole, and
|
|
17
|
+
* `openStretches`, which leaves the shut stretches out and applies to the rest - and both ask the
|
|
18
|
+
* list below. A guard registered here therefore reaches every command by being registered, rather
|
|
19
|
+
* than by each command being taught about it.
|
|
20
|
+
*
|
|
21
|
+
* `editsShut` (`./protectionState`) stays what it was, the view-level question of whether the body
|
|
22
|
+
* is open at all, which is a question about the editor rather than about an edit.
|
|
23
|
+
*/
|
|
24
|
+
import type { Command, EditorState, Selection, Transaction } from "prosemirror-state";
|
|
25
|
+
import { type EditGuard, type EditIntent } from "./editGuard";
|
|
26
|
+
import { type ProtectionState } from "./protection";
|
|
27
|
+
export type { EditGuard, EditGuardName, EditIntent } from "./editGuard";
|
|
28
|
+
export { stepReaches } from "./editGuard";
|
|
29
|
+
/**
|
|
30
|
+
* Whether the transaction reaches a comment node, which is how a body, a reply and a resolution
|
|
31
|
+
* change. Every comment lives in its three nodes, so a change that reaches none of them cannot
|
|
32
|
+
* have changed a comment.
|
|
33
|
+
*/
|
|
34
|
+
export declare function transactionTouchesComments(tr: Transaction): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Whether the protection lets this transaction through (`./protection`).
|
|
37
|
+
*
|
|
38
|
+
* The whole-document judgement is reached for only when a comment is touched at all
|
|
39
|
+
* (`transactionTouchesComments`). A change that touches none is a body edit: through under `none`,
|
|
40
|
+
* refused under `comments`, and nothing about ownership to ask.
|
|
41
|
+
*/
|
|
42
|
+
export declare function protectionAllowsTransaction(tr: Transaction, rules: ProtectionState): boolean;
|
|
43
|
+
export declare const EDIT_GUARDS: readonly EditGuard[];
|
|
44
|
+
/**
|
|
45
|
+
* Whether every guard would let this transaction through, decided and nothing else.
|
|
46
|
+
*
|
|
47
|
+
* The refusal a guard itself answers with carries a side effect - the composition it ends
|
|
48
|
+
* (`editor/plugins/lockedContent`) - which a query about a button's state may not set off, so the
|
|
49
|
+
* decision stands apart from it and every caller building an edit asks this rather than handing
|
|
50
|
+
* the transaction to a state.
|
|
51
|
+
*
|
|
52
|
+
* A re-derivation of display values is no edit and is let through before any guard is asked. The
|
|
53
|
+
* whole-change judgements then come first and take no pass, since a pass lifts one guard's
|
|
54
|
+
* reading of a step rather than another guard's reading of the change. What is left is judged
|
|
55
|
+
* step by step, each step over the document it was built against.
|
|
56
|
+
*/
|
|
57
|
+
export declare function transactionAllowed(tr: Transaction, state: EditorState): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Whether any guard shuts this intent where it stands.
|
|
60
|
+
*
|
|
61
|
+
* This is what a command asks before it reports that it applies: a command reporting true and then
|
|
62
|
+
* being refused by the guard draws a live control that swallows the click.
|
|
63
|
+
*/
|
|
64
|
+
export declare function editShut(state: EditorState, intent: EditIntent): boolean;
|
|
65
|
+
/** What a command doing this to whatever is selected means to do, one intent per selected stretch */
|
|
66
|
+
export declare function selectionIntents(selection: Selection, kind: "mark" | "replace"): EditIntent[];
|
|
67
|
+
/**
|
|
68
|
+
* Build, guard, dispatch: the one shape of a command that is refused whole.
|
|
69
|
+
*
|
|
70
|
+
* A structural edit has no smaller piece to fall back on - half a row cannot be deleted, and half a
|
|
71
|
+
* block of cells cannot be merged into one - so the whole transaction is built, handed to the whole
|
|
72
|
+
* guard list, and dispatched only if it comes back allowed. A character or a paragraph edit does
|
|
73
|
+
* the opposite and leaves the shut stretches out (`openStretches`).
|
|
74
|
+
*
|
|
75
|
+
* The answer is the same whether or not `dispatch` was passed. The transaction is built before
|
|
76
|
+
* either way, so asking the guard costs nothing more, and a command reporting one thing to a button
|
|
77
|
+
* and doing another would be worse than the button being wrong.
|
|
78
|
+
*/
|
|
79
|
+
export declare function guardedCommand(build: (state: EditorState) => Transaction | null): Command;
|
|
80
|
+
/**
|
|
81
|
+
* The stretches the guards leave open, which is the one shape of a command that is trimmed.
|
|
82
|
+
*
|
|
83
|
+
* A shut stretch is left out rather than the whole edit refused: a guard turns down the whole
|
|
84
|
+
* transaction, so asking for the shut stretch as well would leave the rest of the selection
|
|
85
|
+
* unedited too. A selection the guards leave nothing of edits nothing, and the command reports that
|
|
86
|
+
* of its own accord, which is the disabled state of the control that runs it.
|
|
87
|
+
*/
|
|
88
|
+
export declare function openStretches<S extends {
|
|
89
|
+
from: number;
|
|
90
|
+
to: number;
|
|
91
|
+
}>(state: EditorState, stretches: readonly S[], kind: "mark" | "replace"): S[];
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// src/schema/guards.ts
|
|
2
|
+
import { changesOnlyDisplayAttrs, displayOnly } from "./displayDerivation.js";
|
|
3
|
+
import {
|
|
4
|
+
transactionReaches
|
|
5
|
+
} from "./editGuard.js";
|
|
6
|
+
import { lockGuard } from "./locks.js";
|
|
7
|
+
import { bookmarkGuard, noteGuard, sectionGuard } from "./preservedGuards.js";
|
|
8
|
+
import {
|
|
9
|
+
isCommentNode,
|
|
10
|
+
protectionAllows
|
|
11
|
+
} from "./protection.js";
|
|
12
|
+
import { editsShut, protectionOf } from "./protectionState.js";
|
|
13
|
+
import { stepReaches } from "./editGuard.js";
|
|
14
|
+
function transactionTouchesComments(tr) {
|
|
15
|
+
return transactionReaches(tr, isCommentNode);
|
|
16
|
+
}
|
|
17
|
+
function protectionAllowsTransaction(tr, rules) {
|
|
18
|
+
switch (rules.protection) {
|
|
19
|
+
case "readOnly":
|
|
20
|
+
return false;
|
|
21
|
+
case "none":
|
|
22
|
+
return !transactionTouchesComments(tr) || protectionAllows(tr.before, tr.doc, rules);
|
|
23
|
+
case "comments":
|
|
24
|
+
return transactionTouchesComments(tr) && protectionAllows(tr.before, tr.doc, rules);
|
|
25
|
+
default: {
|
|
26
|
+
const unmodelled = rules.protection;
|
|
27
|
+
return unmodelled;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
var protectionGuard = {
|
|
32
|
+
name: "protection",
|
|
33
|
+
change: (tr, state) => protectionAllowsTransaction(tr, protectionOf(state)),
|
|
34
|
+
shuts: (_intent, state) => editsShut(state)
|
|
35
|
+
};
|
|
36
|
+
var EDIT_GUARDS = [
|
|
37
|
+
protectionGuard,
|
|
38
|
+
lockGuard,
|
|
39
|
+
bookmarkGuard,
|
|
40
|
+
noteGuard,
|
|
41
|
+
sectionGuard
|
|
42
|
+
];
|
|
43
|
+
function judgesSteps(guard) {
|
|
44
|
+
return guard.step !== void 0;
|
|
45
|
+
}
|
|
46
|
+
function lifted(guard, tr) {
|
|
47
|
+
return guard.liftedBy?.some((pass) => tr.getMeta(pass) === true) === true;
|
|
48
|
+
}
|
|
49
|
+
function displayOnlyTransaction(tr, state) {
|
|
50
|
+
return tr.getMeta(displayOnly) === true && tr.steps.every(
|
|
51
|
+
(step, index) => changesOnlyDisplayAttrs(step, tr.docs[index] ?? state.doc)
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
function transactionAllowed(tr, state) {
|
|
55
|
+
if (!tr.docChanged) return true;
|
|
56
|
+
if (displayOnlyTransaction(tr, state)) return true;
|
|
57
|
+
if (EDIT_GUARDS.some((guard) => guard.change?.(tr, state) === false)) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
return EDIT_GUARDS.filter(judgesSteps).filter((guard) => !lifted(guard, tr)).every(
|
|
61
|
+
(guard) => (
|
|
62
|
+
// Each step counts positions in the document it was built against, which `docs` holds
|
|
63
|
+
tr.steps.every(
|
|
64
|
+
(step, index) => guard.step(
|
|
65
|
+
step,
|
|
66
|
+
tr.docs[index] ?? state.doc,
|
|
67
|
+
tr.docs[index + 1] ?? tr.doc,
|
|
68
|
+
state
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
)
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
function editShut(state, intent) {
|
|
75
|
+
return EDIT_GUARDS.some((guard) => guard.shuts(intent, state));
|
|
76
|
+
}
|
|
77
|
+
function intentOver(from, to, kind) {
|
|
78
|
+
return from === to ? { kind: "insert", at: from } : { kind, from, to };
|
|
79
|
+
}
|
|
80
|
+
function selectionIntents(selection, kind) {
|
|
81
|
+
return selection.ranges.map(
|
|
82
|
+
(range) => intentOver(range.$from.pos, range.$to.pos, kind)
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
function guardedCommand(build) {
|
|
86
|
+
return (state, dispatch) => {
|
|
87
|
+
const tr = build(state);
|
|
88
|
+
if (tr === null || !transactionAllowed(tr, state)) return false;
|
|
89
|
+
dispatch?.(tr);
|
|
90
|
+
return true;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function openStretches(state, stretches, kind) {
|
|
94
|
+
return stretches.filter(
|
|
95
|
+
(stretch) => !editShut(state, intentOver(stretch.from, stretch.to, kind))
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
export {
|
|
99
|
+
EDIT_GUARDS,
|
|
100
|
+
editShut,
|
|
101
|
+
guardedCommand,
|
|
102
|
+
openStretches,
|
|
103
|
+
protectionAllowsTransaction,
|
|
104
|
+
selectionIntents,
|
|
105
|
+
stepReaches,
|
|
106
|
+
transactionAllowed,
|
|
107
|
+
transactionTouchesComments
|
|
108
|
+
};
|
package/dist/schema/index.d.ts
CHANGED
package/dist/schema/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// src/schema/index.ts
|
|
2
|
+
import { attrsOfClass } from "./attrRoles.js";
|
|
2
3
|
import { docxSchema, isPageBreak } from "./docxSchema.js";
|
|
3
4
|
import { imageNodeSpec, runMarkSpec } from "./rendering.js";
|
|
4
5
|
export {
|
|
6
|
+
attrsOfClass,
|
|
5
7
|
docxSchema,
|
|
6
8
|
imageNodeSpec,
|
|
7
9
|
isPageBreak,
|
package/dist/schema/locks.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Evaluates OOXML content and deletion locks for inline controls and whole table cells.
|
|
3
|
-
* query these predicates before editing; `editor/plugins/lockedContent` enforces them at runtime.
|
|
2
|
+
* Evaluates OOXML content and deletion locks for inline controls and whole table cells.
|
|
4
3
|
*
|
|
5
|
-
* `
|
|
6
|
-
*
|
|
4
|
+
* `lockGuard` is what `./guards` registers all of this as, and it is the only way in: a caller
|
|
5
|
+
* asking about a lock asks the one guard list, which asks the locks along with every other rule an
|
|
6
|
+
* edit is judged by. What a lock says about a whole document or a whole selection - a question
|
|
7
|
+
* about the document rather than about an edit - is exported beside it.
|
|
7
8
|
*/
|
|
8
9
|
import type { Mark, Node as PMNode } from "prosemirror-model";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
10
|
+
import { PluginKey, type Selection } from "prosemirror-state";
|
|
11
|
+
import type { StepGuard } from "./editGuard";
|
|
11
12
|
/**
|
|
12
13
|
* The pass that lets a transaction through the guard, which is how a lock can be lifted at all.
|
|
13
14
|
* A plugin key is used as the name so that it cannot collide with a consumer's own metadata.
|
|
@@ -58,83 +59,22 @@ export interface ControlSpan extends StepRange {
|
|
|
58
59
|
*/
|
|
59
60
|
export declare function controlSpans(block: Textblock): ControlSpan[];
|
|
60
61
|
/**
|
|
61
|
-
* Whether
|
|
62
|
+
* Whether a lock shuts editing where this selection stands, which is what a menu that would lift a
|
|
63
|
+
* lock is built on (`editor/commands/lockCommands`).
|
|
62
64
|
*
|
|
63
|
-
* This is the
|
|
64
|
-
* (`
|
|
65
|
-
* a
|
|
66
|
-
|
|
67
|
-
export declare function insideLockedCell(doc: PMNode, pos: number): boolean;
|
|
68
|
-
/**
|
|
69
|
-
* Whether this stretch reaches contents a lock shuts: text inside a control that shuts its
|
|
70
|
-
* contents, or what a locked cell holds, the cell itself included.
|
|
71
|
-
*
|
|
72
|
-
* This is the question about editing what stands there rather than about taking it away, so every
|
|
73
|
-
* control the stretch meets answers with its contents clause. The lock commands and the formatting
|
|
74
|
-
* commands ask it of the stretch they are about to mark, so it is exported.
|
|
75
|
-
*/
|
|
76
|
-
export declare function rangeTouchesLocked(doc: PMNode, from: number, to: number): boolean;
|
|
77
|
-
/**
|
|
78
|
-
* Whether something inserted at this spot would land inside a locked control or a locked cell.
|
|
79
|
-
*
|
|
80
|
-
* Only a spot with the very same control on both sides is inside one. At either edge the other
|
|
81
|
-
* side belongs to a different control or to none, and since the mark is not inclusive what goes
|
|
82
|
-
* in there falls outside the control.
|
|
83
|
-
*/
|
|
84
|
-
export declare function insertionInsideLocked(doc: PMNode, pos: number): boolean;
|
|
85
|
-
/**
|
|
86
|
-
* Whether the guard shuts editing where this selection stands.
|
|
87
|
-
*
|
|
88
|
-
* This is the question a command that rewrites whatever is selected has to ask before it reports
|
|
89
|
-
* that it applies (`editor/insertImage`), and the one a menu offering to lift a lock is built on
|
|
90
|
-
* (`editor/commands/lockCommands`). A caret is shut by standing inside a control rather than
|
|
91
|
-
* against its edge, which is the same rule an insertion follows.
|
|
65
|
+
* This is a reading of the selection rather than of an edit - the lock guard answers an edit
|
|
66
|
+
* (`./guards`) - and it names the locks alone, which is what the menu says. A caret is shut by
|
|
67
|
+
* standing inside a control rather than against its edge, which is the same rule an insertion
|
|
68
|
+
* follows.
|
|
92
69
|
* A control locked against deletion alone shuts nothing here: its contents stand open, so editing
|
|
93
70
|
* where it stands goes through, and only taking the control away is refused.
|
|
94
71
|
*/
|
|
95
72
|
export declare function selectionShut(selection: Selection, doc: PMNode): boolean;
|
|
96
73
|
/**
|
|
97
|
-
*
|
|
98
|
-
* is what an image insertion does (`editor/insertImage`).
|
|
99
|
-
*
|
|
100
|
-
* A different question from `selectionShut`: what the selection covers whole goes away rather than
|
|
101
|
-
* being edited, so the deletion clause answers for it. A control that may be taken away whole may
|
|
102
|
-
* therefore be replaced, and one locked against deletion alone may not, even though editing inside
|
|
103
|
-
* it would have gone through.
|
|
104
|
-
*/
|
|
105
|
-
export declare function replacementShut(selection: Selection, doc: PMNode): boolean;
|
|
106
|
-
/**
|
|
107
|
-
* Whether any step of the transaction reaches a comment node: puts one in, takes one out, or
|
|
108
|
-
* rewrites the one where it stands, which is how a body, a reply and a resolution change.
|
|
109
|
-
*
|
|
110
|
-
* Every comment lives in its three nodes, so a change that reaches none of them cannot have
|
|
111
|
-
* changed a comment. That is what lets the guard settle the common transaction - typing, and
|
|
112
|
-
* nothing more - over the stretch it rewrote rather than over the whole document.
|
|
113
|
-
*
|
|
114
|
-
* A step of a kind this does not know - one a consumer brought - is answered as reaching one,
|
|
115
|
-
* since what it rewrote is not known either. The whole-document judgement then has the say, and
|
|
116
|
-
* an unknown step costs a comparison rather than a hole in the guard.
|
|
117
|
-
*/
|
|
118
|
-
export declare function transactionTouchesComments(tr: Transaction): boolean;
|
|
119
|
-
/**
|
|
120
|
-
* Whether the protection lets this transaction through (`./protection`).
|
|
121
|
-
*
|
|
122
|
-
* The whole-document judgement is reached for only when a comment is touched at all
|
|
123
|
-
* (`transactionTouchesComments`). A change that touches none is a body edit: through under `none`,
|
|
124
|
-
* refused under `comments`, and nothing about ownership to ask.
|
|
125
|
-
*/
|
|
126
|
-
export declare function protectionAllowsTransaction(tr: Transaction, rules: ProtectionState): boolean;
|
|
127
|
-
/**
|
|
128
|
-
* Whether the guard would let this transaction through, decided and nothing else.
|
|
129
|
-
*
|
|
130
|
-
* The refusal the guard itself answers with carries a side effect - the composition it ends
|
|
131
|
-
* (`editor/plugins/lockedContent`) - which a query about a button's state may not set off, so the
|
|
132
|
-
* decision stands apart from it and every caller building an edit asks this rather than handing
|
|
133
|
-
* the transaction to a state.
|
|
74
|
+
* The locks the document carries, as `./guards` registers them.
|
|
134
75
|
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
* than step by step, which is what lets it tell a comment from everything else.
|
|
76
|
+
* Both passes lift it: unlocking is the one edit that may reach into a lock, and every step the
|
|
77
|
+
* history replays is the reverse of a step that passed the guard when it was made.
|
|
138
78
|
*/
|
|
139
|
-
export declare
|
|
79
|
+
export declare const lockGuard: StepGuard;
|
|
140
80
|
export {};
|
package/dist/schema/locks.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
// src/schema/locks.ts
|
|
2
|
-
import {
|
|
3
|
-
PluginKey
|
|
4
|
-
} from "prosemirror-state";
|
|
2
|
+
import { PluginKey } from "prosemirror-state";
|
|
5
3
|
import {
|
|
6
4
|
AddMarkStep,
|
|
7
5
|
AddNodeMarkStep,
|
|
@@ -12,11 +10,6 @@ import {
|
|
|
12
10
|
ReplaceStep
|
|
13
11
|
} from "prosemirror-transform";
|
|
14
12
|
import { docxSchema } from "./index.js";
|
|
15
|
-
import {
|
|
16
|
-
isCommentNode,
|
|
17
|
-
protectionAllows
|
|
18
|
-
} from "./protection.js";
|
|
19
|
-
import { protectionOf } from "./protectionState.js";
|
|
20
13
|
var unlockAllowed = new PluginKey("docxEditorUnlockAllowed");
|
|
21
14
|
var historyReplay = new PluginKey("docxEditorHistoryReplay");
|
|
22
15
|
var OPEN = { contents: false, deletion: false };
|
|
@@ -123,18 +116,17 @@ function insertionInsideLocked(doc, pos) {
|
|
|
123
116
|
const after = lockedMarkOf($pos.nodeAfter);
|
|
124
117
|
return before !== null && after !== null && before.eq(after);
|
|
125
118
|
}
|
|
119
|
+
function markShut(doc, from, to) {
|
|
120
|
+
return from === to ? insertionInsideLocked(doc, from) : rangeTouchesLocked(doc, from, to);
|
|
121
|
+
}
|
|
122
|
+
function replaceShut(doc, from, to) {
|
|
123
|
+
return from === to ? insertionInsideLocked(doc, from) : rangeShut(doc, { from, to, takesAway: true });
|
|
124
|
+
}
|
|
126
125
|
function selectionShut(selection, doc) {
|
|
127
126
|
return selection.ranges.some(
|
|
128
|
-
(range) =>
|
|
127
|
+
(range) => markShut(doc, range.$from.pos, range.$to.pos)
|
|
129
128
|
);
|
|
130
129
|
}
|
|
131
|
-
function replacementShut(selection, doc) {
|
|
132
|
-
return selection.ranges.some((range) => {
|
|
133
|
-
const from = range.$from.pos;
|
|
134
|
-
const to = range.$to.pos;
|
|
135
|
-
return from === to ? insertionInsideLocked(doc, from) : rangeShut(doc, { from, to, takesAway: true });
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
130
|
function editedRanges(step) {
|
|
139
131
|
if (step instanceof ReplaceAroundStep) {
|
|
140
132
|
return [
|
|
@@ -192,71 +184,35 @@ function stepAllowed(step, doc) {
|
|
|
192
184
|
}
|
|
193
185
|
return true;
|
|
194
186
|
}
|
|
195
|
-
function
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
return found;
|
|
206
|
-
}
|
|
207
|
-
function transactionTouchesComments(tr) {
|
|
208
|
-
return tr.steps.some((step, index) => {
|
|
209
|
-
const before = tr.docs[index];
|
|
210
|
-
const after = tr.docs[index + 1] ?? tr.doc;
|
|
211
|
-
if (step instanceof AttrStep || step instanceof AddNodeMarkStep || step instanceof RemoveNodeMarkStep) {
|
|
212
|
-
const node = before.nodeAt(step.pos);
|
|
213
|
-
return node !== null && isCommentNode(node);
|
|
214
|
-
}
|
|
215
|
-
if (!(step instanceof ReplaceStep || step instanceof ReplaceAroundStep || step instanceof AddMarkStep || step instanceof RemoveMarkStep)) {
|
|
216
|
-
return true;
|
|
217
|
-
}
|
|
218
|
-
let touched = false;
|
|
219
|
-
step.getMap().forEach((oldStart, oldEnd, newStart, newEnd) => {
|
|
220
|
-
touched ||= rangeHoldsComment(before, oldStart, oldEnd) || rangeHoldsComment(after, newStart, newEnd);
|
|
221
|
-
});
|
|
222
|
-
return touched;
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
function protectionAllowsTransaction(tr, rules) {
|
|
226
|
-
switch (rules.protection) {
|
|
227
|
-
case "readOnly":
|
|
228
|
-
return false;
|
|
229
|
-
case "none":
|
|
230
|
-
return !transactionTouchesComments(tr) || protectionAllows(tr.before, tr.doc, rules);
|
|
231
|
-
case "comments":
|
|
232
|
-
return transactionTouchesComments(tr) && protectionAllows(tr.before, tr.doc, rules);
|
|
187
|
+
function intentShut(doc, intent) {
|
|
188
|
+
switch (intent.kind) {
|
|
189
|
+
case "insert":
|
|
190
|
+
return insertionInsideLocked(doc, intent.at);
|
|
191
|
+
case "block":
|
|
192
|
+
return insideLockedCell(doc, intent.at);
|
|
193
|
+
case "mark":
|
|
194
|
+
return markShut(doc, intent.from, intent.to);
|
|
195
|
+
case "replace":
|
|
196
|
+
return replaceShut(doc, intent.from, intent.to);
|
|
233
197
|
default: {
|
|
234
|
-
const unmodelled =
|
|
198
|
+
const unmodelled = intent;
|
|
235
199
|
return unmodelled;
|
|
236
200
|
}
|
|
237
201
|
}
|
|
238
202
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
);
|
|
246
|
-
}
|
|
203
|
+
var lockGuard = {
|
|
204
|
+
name: "lock",
|
|
205
|
+
liftedBy: [unlockAllowed, historyReplay],
|
|
206
|
+
step: (step, before) => stepAllowed(step, before),
|
|
207
|
+
shuts: (intent, state) => intentShut(state.doc, intent)
|
|
208
|
+
};
|
|
247
209
|
export {
|
|
248
210
|
carriesLock,
|
|
249
211
|
controlSpans,
|
|
250
212
|
historyReplay,
|
|
251
|
-
insertionInsideLocked,
|
|
252
|
-
insideLockedCell,
|
|
253
213
|
isLockedCell,
|
|
214
|
+
lockGuard,
|
|
254
215
|
lockedMarkOf,
|
|
255
|
-
protectionAllowsTransaction,
|
|
256
|
-
rangeTouchesLocked,
|
|
257
|
-
replacementShut,
|
|
258
216
|
selectionShut,
|
|
259
|
-
transactionAllowed,
|
|
260
|
-
transactionTouchesComments,
|
|
261
217
|
unlockAllowed
|
|
262
218
|
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The guards over what a document is opened with and the editor only preserves: the two ends of a
|
|
3
|
+
* bookmark range, the reference standing where a footnote or an endnote is called, and the
|
|
4
|
+
* paragraph that ends a section.
|
|
5
|
+
*
|
|
6
|
+
* None of it is content the editor writes, so nothing in it can put such a thing back once it is
|
|
7
|
+
* gone, and a document that lost one of a bookmark's two ends cannot be written back as a file at
|
|
8
|
+
* all (`docx/exportDocx` refuses it). What the first two guards hold is therefore the whole list of
|
|
9
|
+
* the nodes they answer for, in the order the document carries them; a section break, which an
|
|
10
|
+
* edit may legitimately move from one paragraph to another, is held by its number instead.
|
|
11
|
+
*/
|
|
12
|
+
import type { Node as PMNode } from "prosemirror-model";
|
|
13
|
+
import { type ChangeGuard, type EditGuardName } from "./editGuard";
|
|
14
|
+
/** Everything about one preserved node that has to read the same after a change as before it */
|
|
15
|
+
type Signature = (node: PMNode) => string;
|
|
16
|
+
/**
|
|
17
|
+
* A guard that lets a change through only while it leaves the list of these nodes reading exactly
|
|
18
|
+
* as it did, which holds their number, their contents and their order at once.
|
|
19
|
+
*
|
|
20
|
+
* The comparison walks the whole document, so it is reached for only once a step of the change has
|
|
21
|
+
* touched such a node: ordinary typing costs the stretches its own steps rewrote and nothing more.
|
|
22
|
+
* It is judged over the change rather than step by step because a marker moved whole is two steps,
|
|
23
|
+
* one taking it out and one putting it back, and neither of them alone leaves the list as it was.
|
|
24
|
+
*
|
|
25
|
+
* Nothing lifts it. A pass is how an edit reaches past a lock the document put on itself, and
|
|
26
|
+
* there is no such thing to reach past here: the file simply has no way to say what a lost marker
|
|
27
|
+
* was.
|
|
28
|
+
*/
|
|
29
|
+
export declare function preservedNodeGuard(name: EditGuardName, holds: (node: PMNode) => boolean, signature: Signature): ChangeGuard;
|
|
30
|
+
export declare const bookmarkGuard: ChangeGuard;
|
|
31
|
+
export declare const noteGuard: ChangeGuard;
|
|
32
|
+
/**
|
|
33
|
+
* A guard that lets a change through only while it leaves at least as many section breaks standing
|
|
34
|
+
* as it found.
|
|
35
|
+
*
|
|
36
|
+
* A paragraph-level `w:sectPr` is not content: it is where one section of the document ends, and
|
|
37
|
+
* the section carries the page size, the margins and the headers everything up to it is laid out
|
|
38
|
+
* under. Joining that paragraph into the one above it - a Backspace at its start, a selection run
|
|
39
|
+
* across its boundary - would take the whole section away with it, and nothing the editor writes
|
|
40
|
+
* puts a section back.
|
|
41
|
+
*
|
|
42
|
+
* It counts rather than compares, so splitting such a paragraph is still allowed: Enter leaves the
|
|
43
|
+
* break on the half that ends up last (`docx/cloning`), and one break stands where one stood. An
|
|
44
|
+
* edit that adds a break is no business of this guard's either.
|
|
45
|
+
*
|
|
46
|
+
* The count walks the whole document, so it is reached for only once a step has touched a
|
|
47
|
+
* paragraph that lays a break down.
|
|
48
|
+
*/
|
|
49
|
+
export declare const sectionGuard: ChangeGuard;
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// src/schema/preservedGuards.ts
|
|
2
|
+
import { parseProps, propsChild } from "../ooxml/props.js";
|
|
3
|
+
import {
|
|
4
|
+
rangeHolds,
|
|
5
|
+
transactionReaches
|
|
6
|
+
} from "./editGuard.js";
|
|
7
|
+
function signatures(doc, holds, signature) {
|
|
8
|
+
const found = [];
|
|
9
|
+
doc.descendants((node) => {
|
|
10
|
+
if (holds(node)) found.push(signature(node));
|
|
11
|
+
return true;
|
|
12
|
+
});
|
|
13
|
+
return found;
|
|
14
|
+
}
|
|
15
|
+
function same(a, b) {
|
|
16
|
+
return a.length === b.length && a.every((value, index) => value === b[index]);
|
|
17
|
+
}
|
|
18
|
+
function preservedNodeGuard(name, holds, signature) {
|
|
19
|
+
const listOf = (doc) => signatures(doc, holds, signature);
|
|
20
|
+
return {
|
|
21
|
+
name,
|
|
22
|
+
change: (tr) => !transactionReaches(tr, holds) || same(listOf(tr.before), listOf(tr.doc)),
|
|
23
|
+
shuts: (intent, state) => intent.kind === "replace" && rangeHolds(state.doc, intent.from, intent.to, holds)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
var BOOKMARK_XML = /<(?:[\w.-]+:)?bookmark(?:Start|End)\b/;
|
|
27
|
+
function isBookmarkMarker(node) {
|
|
28
|
+
if (node.type.name === "bookmarkBlock") return true;
|
|
29
|
+
return node.type.name === "rawInline" && typeof node.attrs.xml === "string" && BOOKMARK_XML.test(node.attrs.xml);
|
|
30
|
+
}
|
|
31
|
+
function bookmarkSignature(node) {
|
|
32
|
+
return node.type.name === "bookmarkBlock" ? `block:${node.attrs.srcId}:${node.attrs.name}` : `inline:${node.attrs.xml}`;
|
|
33
|
+
}
|
|
34
|
+
var bookmarkGuard = preservedNodeGuard(
|
|
35
|
+
"bookmark",
|
|
36
|
+
isBookmarkMarker,
|
|
37
|
+
bookmarkSignature
|
|
38
|
+
);
|
|
39
|
+
function isNoteReference(node) {
|
|
40
|
+
return node.type.name === "noteReference";
|
|
41
|
+
}
|
|
42
|
+
var noteGuard = preservedNodeGuard(
|
|
43
|
+
"note",
|
|
44
|
+
isNoteReference,
|
|
45
|
+
(node) => JSON.stringify(node.attrs)
|
|
46
|
+
);
|
|
47
|
+
function endsASection(node) {
|
|
48
|
+
if (node.type.name !== "paragraph") return false;
|
|
49
|
+
const pPr = node.attrs.pPr;
|
|
50
|
+
if (typeof pPr !== "string") return false;
|
|
51
|
+
const props = parseProps(pPr);
|
|
52
|
+
return props !== null && propsChild(props.children, "sectPr") !== void 0;
|
|
53
|
+
}
|
|
54
|
+
function sectionBreaks(doc) {
|
|
55
|
+
let seen = 0;
|
|
56
|
+
doc.descendants((node) => {
|
|
57
|
+
if (endsASection(node)) seen += 1;
|
|
58
|
+
return true;
|
|
59
|
+
});
|
|
60
|
+
return seen;
|
|
61
|
+
}
|
|
62
|
+
var sectionGuard = {
|
|
63
|
+
name: "section",
|
|
64
|
+
change: (tr) => !transactionReaches(tr, endsASection) || sectionBreaks(tr.doc) >= sectionBreaks(tr.before),
|
|
65
|
+
shuts: (intent, state) => {
|
|
66
|
+
if (intent.kind !== "replace") return false;
|
|
67
|
+
const $from = state.doc.resolve(intent.from);
|
|
68
|
+
const $to = state.doc.resolve(intent.to);
|
|
69
|
+
if ($from.parent.type.name === "paragraph" && $from.sameParent($to)) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return rangeHolds(state.doc, intent.from, intent.to, endsASection);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
export {
|
|
76
|
+
bookmarkGuard,
|
|
77
|
+
noteGuard,
|
|
78
|
+
preservedNodeGuard,
|
|
79
|
+
sectionGuard
|
|
80
|
+
};
|