docxodus 7.1.0 → 9.0.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/README.md +65 -24
- package/dist/docxodus.worker.js +2 -2
- package/dist/docxodus.worker.js.map +1 -1
- package/dist/editor-headerfooter.d.ts +166 -0
- package/dist/editor-headerfooter.d.ts.map +1 -0
- package/dist/editor-headerfooter.js +530 -0
- package/dist/editor-headerfooter.js.map +1 -0
- package/dist/editor-reconcile.d.ts +75 -0
- package/dist/editor-reconcile.d.ts.map +1 -0
- package/dist/editor-reconcile.js +125 -0
- package/dist/editor-reconcile.js.map +1 -0
- package/dist/editor.bundle.js +1861 -110
- package/dist/editor.d.ts +200 -6
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +868 -86
- package/dist/editor.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -4
- package/dist/index.js.map +1 -1
- package/dist/page-number-format.d.ts +22 -0
- package/dist/page-number-format.d.ts.map +1 -0
- package/dist/page-number-format.js +60 -0
- package/dist/page-number-format.js.map +1 -0
- package/dist/pagination.bundle.js +635 -37
- package/dist/pagination.d.ts +119 -0
- package/dist/pagination.d.ts.map +1 -1
- package/dist/pagination.js +706 -52
- package/dist/pagination.js.map +1 -1
- package/dist/react.d.ts +3 -1
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +6 -4
- package/dist/react.js.map +1 -1
- package/dist/session.bundle.js +241 -4
- package/dist/session.d.ts +160 -6
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +202 -4
- package/dist/session.js.map +1 -1
- package/dist/types.d.ts +238 -14
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +9 -11
- package/dist/types.js.map +1 -1
- package/dist/wasm/_framework/Docxodus.wasm +0 -0
- package/dist/wasm/_framework/DocxodusWasm.wasm +0 -0
- package/dist/wasm/_framework/System.Collections.Concurrent.wasm +0 -0
- package/dist/wasm/_framework/System.Collections.Immutable.wasm +0 -0
- package/dist/wasm/_framework/System.Collections.NonGeneric.wasm +0 -0
- package/dist/wasm/_framework/System.Collections.Specialized.wasm +0 -0
- package/dist/wasm/_framework/System.Collections.wasm +0 -0
- package/dist/wasm/_framework/System.ComponentModel.Primitives.wasm +0 -0
- package/dist/wasm/_framework/System.ComponentModel.TypeConverter.wasm +0 -0
- package/dist/wasm/_framework/System.ComponentModel.wasm +0 -0
- package/dist/wasm/_framework/System.Console.wasm +0 -0
- package/dist/wasm/_framework/System.Diagnostics.Process.wasm +0 -0
- package/dist/wasm/_framework/System.IO.Compression.wasm +0 -0
- package/dist/wasm/_framework/System.IO.Pipelines.wasm +0 -0
- package/dist/wasm/_framework/System.Linq.Expressions.wasm +0 -0
- package/dist/wasm/_framework/System.Linq.wasm +0 -0
- package/dist/wasm/_framework/System.Memory.wasm +0 -0
- package/dist/wasm/_framework/System.Net.Http.wasm +0 -0
- package/dist/wasm/_framework/System.Net.Primitives.wasm +0 -0
- package/dist/wasm/_framework/System.ObjectModel.wasm +0 -0
- package/dist/wasm/_framework/System.Private.CoreLib.wasm +0 -0
- package/dist/wasm/_framework/System.Private.Uri.wasm +0 -0
- package/dist/wasm/_framework/System.Private.Xml.Linq.wasm +0 -0
- package/dist/wasm/_framework/System.Private.Xml.wasm +0 -0
- package/dist/wasm/_framework/System.Runtime.InteropServices.JavaScript.wasm +0 -0
- package/dist/wasm/_framework/System.Runtime.wasm +0 -0
- package/dist/wasm/_framework/System.Security.Cryptography.wasm +0 -0
- package/dist/wasm/_framework/System.Text.Encoding.Extensions.wasm +0 -0
- package/dist/wasm/_framework/System.Text.Encodings.Web.wasm +0 -0
- package/dist/wasm/_framework/System.Text.Json.wasm +0 -0
- package/dist/wasm/_framework/System.Text.RegularExpressions.wasm +0 -0
- package/dist/wasm/_framework/System.Threading.Thread.wasm +0 -0
- package/dist/wasm/_framework/System.Threading.wasm +0 -0
- package/dist/wasm/_framework/System.Xml.Linq.wasm +0 -0
- package/dist/wasm/_framework/System.Xml.ReaderWriter.wasm +0 -0
- package/dist/wasm/_framework/System.Xml.XDocument.wasm +0 -0
- package/dist/wasm/_framework/System.Xml.XPath.XDocument.wasm +0 -0
- package/dist/wasm/_framework/System.Xml.XPath.wasm +0 -0
- package/dist/wasm/_framework/System.wasm +0 -0
- package/dist/wasm/_framework/dotnet.boot.js +41 -41
- package/dist/wasm/_framework/dotnet.js +1 -1
- package/dist/wasm/_framework/dotnet.js.map +1 -1
- package/dist/wasm/_framework/dotnet.native.js +3 -3
- package/dist/wasm/_framework/dotnet.native.js.symbols +2102 -2101
- package/dist/wasm/_framework/dotnet.native.wasm +0 -0
- package/dist/wasm/_framework/dotnet.runtime.js +1 -1
- package/dist/wasm/_framework/dotnet.runtime.js.map +1 -1
- package/dist/wasm/index.html +2 -1
- package/package.json +17 -4
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HeaderFooterRegion — the DocxEditor's docked header/footer editing bands.
|
|
3
|
+
*
|
|
4
|
+
* Header and footer stories live in their own OOXML parts (HeaderPart/FooterPart) *outside*
|
|
5
|
+
* the body, so they cannot be another block in the body flow. This module renders them as two
|
|
6
|
+
* docked bands — one above the body, one below — each composed PER STORY PARAGRAPH via the
|
|
7
|
+
* session-attached `RenderBlockHtml`, which resolves `hdr`/`ftr` anchors natively.
|
|
8
|
+
*
|
|
9
|
+
* Using the same renderer for first paint and for the post-edit incremental swap means there is
|
|
10
|
+
* no fidelity drift between them. It is also the only option that works in continuous mode at
|
|
11
|
+
* all: the editor's full-document render only asks for headers/footers in paginated mode, and it
|
|
12
|
+
* never stamps `data-anchor` inside header/footer parts (Unids are assigned to the main document
|
|
13
|
+
* part only). In paginated mode the page boxes additionally clone one header node onto every
|
|
14
|
+
* page, so page-margin nodes could never be uniquely addressable — bands keep exactly one DOM
|
|
15
|
+
* node per story paragraph.
|
|
16
|
+
*
|
|
17
|
+
* Once rendered, a story paragraph is an ORDINARY editable block: DocxSession's anchor
|
|
18
|
+
* resolution indexes every scope and routes by part, so ReplaceText/ApplyFormat/SetParagraphFormat
|
|
19
|
+
* all accept a `p:hdr1:<unid>` anchor. The editor wires band blocks with the same `wireBlock` it
|
|
20
|
+
* uses for the body, which is why the whole ribbon works inside a band with no new command code.
|
|
21
|
+
*/
|
|
22
|
+
/** The page-number formats Word's *Format Page Numbers…* dialog offers, in its order. The blank
|
|
23
|
+
* entry means "leave the section's format alone" — not "decimal", which would write an attribute
|
|
24
|
+
* the document may never have had. */
|
|
25
|
+
const PAGE_FORMAT_LABELS = [
|
|
26
|
+
{ value: "", label: "Format…" },
|
|
27
|
+
{ value: "decimal", label: "1, 2, 3" },
|
|
28
|
+
{ value: "lowerLetter", label: "a, b, c" },
|
|
29
|
+
{ value: "upperLetter", label: "A, B, C" },
|
|
30
|
+
{ value: "lowerRoman", label: "i, ii, iii" },
|
|
31
|
+
{ value: "upperRoman", label: "I, II, III" },
|
|
32
|
+
];
|
|
33
|
+
const KIND_LABELS = [
|
|
34
|
+
{ value: "default", label: "Default" },
|
|
35
|
+
{ value: "first", label: "First page" },
|
|
36
|
+
{ value: "even", label: "Even pages" },
|
|
37
|
+
];
|
|
38
|
+
/**
|
|
39
|
+
* Verbatim from docs/architecture/docx_mutation_api.md. `w:evenAndOddHeaders` is set on the
|
|
40
|
+
* SETTINGS part, so it is document-global and governs footers as well as headers: once set,
|
|
41
|
+
* even pages stop inheriting the Default stories entirely. A demo user who creates only an
|
|
42
|
+
* even header hits this immediately and sees their footer vanish on page 2.
|
|
43
|
+
*/
|
|
44
|
+
const EVEN_WARNING = "w:evenAndOddHeaders is document-global and governs footers too — even pages stop " +
|
|
45
|
+
"inheriting the Default stories, so a section with only a Default footer shows no footer " +
|
|
46
|
+
"at all on even pages.";
|
|
47
|
+
/**
|
|
48
|
+
* `w:titlePg` is per-section but has the same shape of surprise: once set, page 1 uses its OWN
|
|
49
|
+
* header AND footer, so an empty first-page footer means page 1 shows no footer even though the
|
|
50
|
+
* Default one is populated.
|
|
51
|
+
*/
|
|
52
|
+
const FIRST_WARNING = "w:titlePg makes page 1 use its own first-page header AND footer instead of the Default " +
|
|
53
|
+
"ones, so an empty first-page footer leaves page 1 with no footer.";
|
|
54
|
+
/** Kinds/scopes the markdown projection addresses as editable text blocks. */
|
|
55
|
+
const STORY_BLOCK_KINDS = new Set(["p", "h", "li"]);
|
|
56
|
+
export class HeaderFooterRegion {
|
|
57
|
+
constructor(bridge, handle, options, callbacks) {
|
|
58
|
+
/** The body anchor whose section the bands currently describe (needed to seed a story). */
|
|
59
|
+
this.bodyAnchorId = null;
|
|
60
|
+
this.sectionInfo = null;
|
|
61
|
+
/** Memoized body anchor → governing sectionUnid, so repeat focus costs no bridge call. */
|
|
62
|
+
this.sectionOfAnchor = new Map();
|
|
63
|
+
this.kinds = {
|
|
64
|
+
header: "default",
|
|
65
|
+
footer: "default",
|
|
66
|
+
};
|
|
67
|
+
this.bridge = bridge;
|
|
68
|
+
this.handle = handle;
|
|
69
|
+
this.options = options;
|
|
70
|
+
this.callbacks = callbacks;
|
|
71
|
+
this.headerBand = this.buildBand("header");
|
|
72
|
+
this.footerBand = this.buildBand("footer");
|
|
73
|
+
}
|
|
74
|
+
// ─── public surface ──────────────────────────────────────────────────
|
|
75
|
+
/**
|
|
76
|
+
* Point the bands at the section governing `bodyAnchorId` and repaint if it changed.
|
|
77
|
+
* Cheap to call on every focus change: the anchor → section lookup is memoized, and an
|
|
78
|
+
* unchanged `sectionUnid` returns without touching the DOM (so it never clobbers the
|
|
79
|
+
* user's kind selection).
|
|
80
|
+
*/
|
|
81
|
+
syncToBody(bodyAnchorId) {
|
|
82
|
+
if (!bodyAnchorId)
|
|
83
|
+
return;
|
|
84
|
+
const cached = this.sectionOfAnchor.get(bodyAnchorId);
|
|
85
|
+
if (cached !== undefined && cached === this.sectionInfo?.sectionUnid) {
|
|
86
|
+
this.bodyAnchorId = bodyAnchorId; // same section — keep it as the seed target
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const info = this.readSectionInfo(bodyAnchorId);
|
|
90
|
+
if (!info)
|
|
91
|
+
return; // not a body anchor (or no sectPr) — leave the bands as they are
|
|
92
|
+
this.sectionOfAnchor.set(bodyAnchorId, info.sectionUnid);
|
|
93
|
+
const changed = info.sectionUnid !== this.sectionInfo?.sectionUnid;
|
|
94
|
+
this.bodyAnchorId = bodyAnchorId;
|
|
95
|
+
this.sectionInfo = info;
|
|
96
|
+
if (changed)
|
|
97
|
+
this.refreshAll();
|
|
98
|
+
}
|
|
99
|
+
/** Repaint one band from the live session. */
|
|
100
|
+
refresh(which) {
|
|
101
|
+
this.sectionInfo = this.bodyAnchorId ? this.readSectionInfo(this.bodyAnchorId) : null;
|
|
102
|
+
this.renderBand(which);
|
|
103
|
+
}
|
|
104
|
+
/** Repaint both bands from the live session (after a remount, undo/redo, or section change). */
|
|
105
|
+
refreshAll() {
|
|
106
|
+
this.renderBand("header");
|
|
107
|
+
this.renderBand("footer");
|
|
108
|
+
}
|
|
109
|
+
/** Select (and, if absent, create) the story kind a band edits, and make it render. */
|
|
110
|
+
setKind(which, kind) {
|
|
111
|
+
this.kinds[which] = kind;
|
|
112
|
+
const select = this.bandFor(which).querySelector("[data-hf-kind]");
|
|
113
|
+
if (select && select.value !== kind)
|
|
114
|
+
select.value = kind;
|
|
115
|
+
if (!this.partUriFor(which, kind))
|
|
116
|
+
this.seedStory(which, kind);
|
|
117
|
+
// Selecting first/even IS the user saying "use a different first/even page", so the section's
|
|
118
|
+
// visibility flag must be set even when the part already exists — seedStory (which sets it as
|
|
119
|
+
// a side effect of writing content) doesn't run then. Word leaves first/even parts behind when
|
|
120
|
+
// those options are switched off, so a real document commonly has the reference WITHOUT the
|
|
121
|
+
// flag; without this the typed story is saved but never rendered.
|
|
122
|
+
if (this.bodyAnchorId && kind !== "default") {
|
|
123
|
+
this.bridge.EnsureHeaderFooterVisible(this.handle, this.bodyAnchorId, kind);
|
|
124
|
+
}
|
|
125
|
+
this.refresh(which);
|
|
126
|
+
}
|
|
127
|
+
/** The kind a band is currently editing. */
|
|
128
|
+
kindOf(which) {
|
|
129
|
+
return this.kinds[which];
|
|
130
|
+
}
|
|
131
|
+
/** Append a PAGE / NUMPAGES field to the story paragraph addressed by `anchorId`.
|
|
132
|
+
* Deliberately a PLAIN field (no `\*` switch), exactly as Word inserts one, so it follows the
|
|
133
|
+
* section's page-number format — see {@link setPageNumbering}. Stamping the section's current
|
|
134
|
+
* format as a switch here would silently WIN over any later format change. */
|
|
135
|
+
insertPageNumber(which, anchorId, field) {
|
|
136
|
+
const res = parseResult(this.bridge.InsertPageNumberField(this.handle, anchorId, field, ""));
|
|
137
|
+
if (!res.success)
|
|
138
|
+
return false;
|
|
139
|
+
this.refresh(which);
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Set this section's page numbering (`w:pgNumType`) — Word's *Format Page Numbers…*. Omitted
|
|
144
|
+
* fields are left alone, so the format and the start are independently settable. Both bands then
|
|
145
|
+
* repaint, because the values belong to the section rather than to either story.
|
|
146
|
+
*
|
|
147
|
+
* The rendered page numbers in the editor do not change: a page-number field's cached result is
|
|
148
|
+
* what the browser shows, and Word recomputes it on open. Paginated mode substitutes the real
|
|
149
|
+
* per-page number, so it does reflect the format immediately.
|
|
150
|
+
*/
|
|
151
|
+
setPageNumbering(op) {
|
|
152
|
+
if (!this.bodyAnchorId)
|
|
153
|
+
return false;
|
|
154
|
+
const res = parseResult(this.bridge.SetPageNumbering(this.handle, this.bodyAnchorId, JSON.stringify(op)));
|
|
155
|
+
if (!res.success)
|
|
156
|
+
return false;
|
|
157
|
+
this.reloadSection();
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
/** This section's page numbering as the live document states it. Fields are absent, not
|
|
161
|
+
* defaulted — "continues the previous section" is not the same claim as "starts at 1". */
|
|
162
|
+
pageNumbering() {
|
|
163
|
+
return {
|
|
164
|
+
start: this.sectionInfo?.pageNumberStart,
|
|
165
|
+
format: this.sectionInfo?.pageNumberFormat,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/** Remove this section's page-numbering start/format — it reverts to continuing the previous
|
|
169
|
+
* section's numbering in Word's default `1, 2, 3`. */
|
|
170
|
+
clearPageNumbering() {
|
|
171
|
+
if (!this.bodyAnchorId)
|
|
172
|
+
return false;
|
|
173
|
+
const res = parseResult(this.bridge.ClearPageNumbering(this.handle, this.bodyAnchorId));
|
|
174
|
+
if (!res.success)
|
|
175
|
+
return false;
|
|
176
|
+
this.reloadSection();
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Re-read the section from the live document and repaint BOTH bands.
|
|
181
|
+
*
|
|
182
|
+
* `refreshAll` only repaints — it deliberately does not re-read, because its callers (remount,
|
|
183
|
+
* undo/redo) already refreshed the section. A section-property write has no such caller, and
|
|
184
|
+
* repainting from the stale snapshot would leave the chrome reporting the value the document had
|
|
185
|
+
* before the edit.
|
|
186
|
+
*/
|
|
187
|
+
reloadSection() {
|
|
188
|
+
this.sectionInfo = this.bodyAnchorId ? this.readSectionInfo(this.bodyAnchorId) : null;
|
|
189
|
+
this.refreshAll();
|
|
190
|
+
}
|
|
191
|
+
/** Insert a page number into a band's own target paragraph (focused, else last). Seeds the
|
|
192
|
+
* story first if the band's selected kind has none, so the command is never a silent no-op. */
|
|
193
|
+
insertPageNumberInBand(which, field) {
|
|
194
|
+
if (!this.partUriFor(which, this.kinds[which])) {
|
|
195
|
+
this.seedStory(which, this.kinds[which]);
|
|
196
|
+
this.renderBand(which);
|
|
197
|
+
}
|
|
198
|
+
const target = this.pageNumberTarget(which);
|
|
199
|
+
return target ? this.insertPageNumber(which, target, field) : false;
|
|
200
|
+
}
|
|
201
|
+
/** The band element containing `node`, or null. */
|
|
202
|
+
bandOf(node) {
|
|
203
|
+
const el = node && node.nodeType === 1 ? node : node?.parentElement ?? null;
|
|
204
|
+
const band = el?.closest("[data-hf-band]") ?? null;
|
|
205
|
+
return band === this.headerBand || band === this.footerBand ? band : null;
|
|
206
|
+
}
|
|
207
|
+
/** The block-list root (a band's story container) owning `node`, or null. */
|
|
208
|
+
blockRootOf(node) {
|
|
209
|
+
const band = this.bandOf(node);
|
|
210
|
+
return band ? band.querySelector("[data-hf-body]") : null;
|
|
211
|
+
}
|
|
212
|
+
/** True when `node` is inside either band (including its chrome). */
|
|
213
|
+
contains(node) {
|
|
214
|
+
return this.bandOf(node) !== null;
|
|
215
|
+
}
|
|
216
|
+
/** `"header"` / `"footer"` for a band element produced by this region. */
|
|
217
|
+
whichOf(band) {
|
|
218
|
+
return band === this.footerBand ? "footer" : "header";
|
|
219
|
+
}
|
|
220
|
+
// ─── section + anchor resolution ─────────────────────────────────────
|
|
221
|
+
readSectionInfo(bodyAnchorId) {
|
|
222
|
+
try {
|
|
223
|
+
const raw = this.bridge.GetSectionInfo(this.handle, bodyAnchorId);
|
|
224
|
+
const parsed = JSON.parse(raw);
|
|
225
|
+
return parsed && typeof parsed.sectionUnid === "string" ? parsed : null;
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
refsFor(which) {
|
|
232
|
+
const info = this.sectionInfo;
|
|
233
|
+
if (!info)
|
|
234
|
+
return [];
|
|
235
|
+
return (which === "header" ? info.headerRefs : info.footerRefs) ?? [];
|
|
236
|
+
}
|
|
237
|
+
/** The reference supplying `kind` for this band — possibly inherited from an earlier section. */
|
|
238
|
+
refFor(which, kind) {
|
|
239
|
+
return this.refsFor(which).find((r) => r.kind === kind) ?? null;
|
|
240
|
+
}
|
|
241
|
+
/** URI of the part supplying `kind` for this band, or null when the story doesn't exist. */
|
|
242
|
+
partUriFor(which, kind) {
|
|
243
|
+
return this.refFor(which, kind)?.partUri ?? null;
|
|
244
|
+
}
|
|
245
|
+
/** Full anchor ids of the story paragraphs held in `partUri`, in document order. */
|
|
246
|
+
storyAnchors(partUri) {
|
|
247
|
+
let index;
|
|
248
|
+
try {
|
|
249
|
+
index = JSON.parse(this.bridge.Project(this.handle)).anchorIndex;
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
return [];
|
|
253
|
+
}
|
|
254
|
+
return Object.entries(index)
|
|
255
|
+
.filter(([, t]) => t.partUri === partUri && STORY_BLOCK_KINDS.has(t.kind))
|
|
256
|
+
.map(([id]) => id);
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Create an empty story for `kind`. Seeding happens the moment a kind is selected rather than
|
|
260
|
+
* lazily on first keystroke: an absent story renders no contenteditable element, so there
|
|
261
|
+
* would be nothing to click into.
|
|
262
|
+
*/
|
|
263
|
+
seedStory(which, kind) {
|
|
264
|
+
if (!this.bodyAnchorId)
|
|
265
|
+
return;
|
|
266
|
+
const set = which === "header" ? this.bridge.SetHeaderText : this.bridge.SetFooterText;
|
|
267
|
+
const res = parseResult(set(this.handle, this.bodyAnchorId, kind, ""));
|
|
268
|
+
if (!res.success)
|
|
269
|
+
return;
|
|
270
|
+
// A new part changes the projection (fresh hdr{N}/ftr{N} scope) and the section's refs.
|
|
271
|
+
this.callbacks.refreshAnchorMap();
|
|
272
|
+
this.sectionInfo = this.readSectionInfo(this.bodyAnchorId);
|
|
273
|
+
}
|
|
274
|
+
// ─── rendering ───────────────────────────────────────────────────────
|
|
275
|
+
bandFor(which) {
|
|
276
|
+
return which === "header" ? this.headerBand : this.footerBand;
|
|
277
|
+
}
|
|
278
|
+
buildBand(which) {
|
|
279
|
+
const band = document.createElement("div");
|
|
280
|
+
band.className = "docx-hf-band";
|
|
281
|
+
band.setAttribute("data-hf-band", which);
|
|
282
|
+
const chrome = document.createElement("div");
|
|
283
|
+
chrome.className = "docx-hf-chrome";
|
|
284
|
+
const label = document.createElement("span");
|
|
285
|
+
label.className = "docx-hf-label";
|
|
286
|
+
label.textContent = which === "header" ? "Header" : "Footer";
|
|
287
|
+
chrome.appendChild(label);
|
|
288
|
+
const kindSelect = document.createElement("select");
|
|
289
|
+
kindSelect.setAttribute("data-hf-kind", "");
|
|
290
|
+
kindSelect.title = "Which header/footer story to edit";
|
|
291
|
+
for (const k of KIND_LABELS) {
|
|
292
|
+
const opt = document.createElement("option");
|
|
293
|
+
opt.value = k.value;
|
|
294
|
+
opt.textContent = k.label;
|
|
295
|
+
kindSelect.appendChild(opt);
|
|
296
|
+
}
|
|
297
|
+
kindSelect.addEventListener("change", () => this.setKind(which, kindSelect.value));
|
|
298
|
+
chrome.appendChild(kindSelect);
|
|
299
|
+
const pageNum = document.createElement("select");
|
|
300
|
+
pageNum.setAttribute("data-hf-pagenum", "");
|
|
301
|
+
pageNum.title = "Insert a page-number field into the focused story paragraph";
|
|
302
|
+
for (const o of [
|
|
303
|
+
{ value: "", label: "Page №…" },
|
|
304
|
+
{ value: "currentPage", label: "Page number" },
|
|
305
|
+
{ value: "totalPages", label: "Total pages" },
|
|
306
|
+
]) {
|
|
307
|
+
const opt = document.createElement("option");
|
|
308
|
+
opt.value = o.value;
|
|
309
|
+
opt.textContent = o.label;
|
|
310
|
+
pageNum.appendChild(opt);
|
|
311
|
+
}
|
|
312
|
+
// The <select> steals focus from the story paragraph, collapsing the caret, so the target
|
|
313
|
+
// is resolved from the band's own blocks rather than from the editor's live selection.
|
|
314
|
+
pageNum.addEventListener("change", () => {
|
|
315
|
+
const field = pageNum.value;
|
|
316
|
+
pageNum.value = "";
|
|
317
|
+
if (field !== "currentPage" && field !== "totalPages")
|
|
318
|
+
return;
|
|
319
|
+
const target = this.pageNumberTarget(which);
|
|
320
|
+
if (target)
|
|
321
|
+
this.insertPageNumber(which, target, field);
|
|
322
|
+
});
|
|
323
|
+
chrome.appendChild(pageNum);
|
|
324
|
+
// Word's "Format Page Numbers…": these are SECTION properties (w:pgNumType), not properties of
|
|
325
|
+
// this band's story, so both bands show the same values and either can set them. An inserted
|
|
326
|
+
// page-number field is plain, so it renders through whatever is chosen here.
|
|
327
|
+
const pageFmt = document.createElement("select");
|
|
328
|
+
pageFmt.setAttribute("data-hf-pagefmt", "");
|
|
329
|
+
pageFmt.title = "Page-number format for this section";
|
|
330
|
+
for (const o of PAGE_FORMAT_LABELS) {
|
|
331
|
+
const opt = document.createElement("option");
|
|
332
|
+
opt.value = o.value;
|
|
333
|
+
opt.textContent = o.label;
|
|
334
|
+
pageFmt.appendChild(opt);
|
|
335
|
+
}
|
|
336
|
+
pageFmt.addEventListener("change", () => {
|
|
337
|
+
if (pageFmt.value === "")
|
|
338
|
+
return;
|
|
339
|
+
this.setPageNumbering({ format: pageFmt.value });
|
|
340
|
+
});
|
|
341
|
+
chrome.appendChild(pageFmt);
|
|
342
|
+
const pageStart = document.createElement("input");
|
|
343
|
+
pageStart.setAttribute("data-hf-pagestart", "");
|
|
344
|
+
pageStart.type = "number";
|
|
345
|
+
pageStart.min = "0";
|
|
346
|
+
pageStart.placeholder = "Start at";
|
|
347
|
+
pageStart.title = "Restart this section's page numbering at this number";
|
|
348
|
+
// Commit on blur/Enter, not on every keystroke: typing "12" would otherwise apply a start of 1
|
|
349
|
+
// first, and each apply is an undo step.
|
|
350
|
+
const commitStart = () => {
|
|
351
|
+
const raw = pageStart.value.trim();
|
|
352
|
+
if (raw === "")
|
|
353
|
+
return;
|
|
354
|
+
const start = Number(raw);
|
|
355
|
+
if (!Number.isInteger(start) || start < 0)
|
|
356
|
+
return;
|
|
357
|
+
this.setPageNumbering({ start });
|
|
358
|
+
};
|
|
359
|
+
pageStart.addEventListener("blur", commitStart);
|
|
360
|
+
pageStart.addEventListener("keydown", (e) => {
|
|
361
|
+
if (e.key === "Enter") {
|
|
362
|
+
e.preventDefault();
|
|
363
|
+
commitStart();
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
chrome.appendChild(pageStart);
|
|
367
|
+
const inheritedNote = document.createElement("span");
|
|
368
|
+
inheritedNote.className = "docx-hf-inherited";
|
|
369
|
+
inheritedNote.setAttribute("data-hf-inherited-note", "");
|
|
370
|
+
inheritedNote.hidden = true;
|
|
371
|
+
chrome.appendChild(inheritedNote);
|
|
372
|
+
band.appendChild(chrome);
|
|
373
|
+
const warning = document.createElement("div");
|
|
374
|
+
warning.className = "docx-hf-warning";
|
|
375
|
+
warning.setAttribute("data-hf-warning", "");
|
|
376
|
+
warning.hidden = true;
|
|
377
|
+
band.appendChild(warning);
|
|
378
|
+
const body = document.createElement("div");
|
|
379
|
+
body.className = "docx-hf-body";
|
|
380
|
+
body.setAttribute("data-hf-body", "");
|
|
381
|
+
band.appendChild(body);
|
|
382
|
+
return band;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Which story paragraph a page-number insert targets: the last one the user focused in this
|
|
386
|
+
* band if it is still attached, else the band's last paragraph (Word's convention — the page
|
|
387
|
+
* number goes at the end of the footer line).
|
|
388
|
+
*/
|
|
389
|
+
pageNumberTarget(which) {
|
|
390
|
+
const body = this.bandFor(which).querySelector("[data-hf-body]");
|
|
391
|
+
if (!body)
|
|
392
|
+
return null;
|
|
393
|
+
const focused = body.querySelector('[data-hf-focused="true"][data-hf-anchor]');
|
|
394
|
+
const blocks = Array.from(body.querySelectorAll("[data-hf-anchor]"));
|
|
395
|
+
const target = focused ?? blocks[blocks.length - 1];
|
|
396
|
+
return target?.getAttribute("data-hf-anchor") ?? null;
|
|
397
|
+
}
|
|
398
|
+
renderBand(which) {
|
|
399
|
+
const band = this.bandFor(which);
|
|
400
|
+
const body = band.querySelector("[data-hf-body]");
|
|
401
|
+
if (!body)
|
|
402
|
+
return;
|
|
403
|
+
const kind = this.kinds[which];
|
|
404
|
+
const select = band.querySelector("[data-hf-kind]");
|
|
405
|
+
if (select && select.value !== kind)
|
|
406
|
+
select.value = kind;
|
|
407
|
+
// Section-level page numbering — the same values on both bands, seeded from the live sectPr so
|
|
408
|
+
// the chrome reports what the document says rather than what was last clicked.
|
|
409
|
+
const pageFmt = band.querySelector("[data-hf-pagefmt]");
|
|
410
|
+
if (pageFmt)
|
|
411
|
+
pageFmt.value = this.sectionInfo?.pageNumberFormat ?? "";
|
|
412
|
+
const pageStart = band.querySelector("[data-hf-pagestart]");
|
|
413
|
+
if (pageStart && document.activeElement !== pageStart) {
|
|
414
|
+
const start = this.sectionInfo?.pageNumberStart;
|
|
415
|
+
pageStart.value = start === undefined ? "" : String(start);
|
|
416
|
+
}
|
|
417
|
+
// A section that declares no reference of this kind shows the story it inherits from an
|
|
418
|
+
// earlier section. Say so: editing it changes BOTH sections, because they share one part.
|
|
419
|
+
const inherited = this.refFor(which, kind)?.inherited === true;
|
|
420
|
+
band.toggleAttribute("data-hf-inherited", inherited);
|
|
421
|
+
const note = band.querySelector("[data-hf-inherited-note]");
|
|
422
|
+
if (note) {
|
|
423
|
+
note.hidden = !inherited;
|
|
424
|
+
note.textContent = inherited ? "inherited from an earlier section" : "";
|
|
425
|
+
}
|
|
426
|
+
this.renderKindWarning(which);
|
|
427
|
+
body.innerHTML = "";
|
|
428
|
+
const partUri = this.partUriFor(which, kind);
|
|
429
|
+
if (!partUri) {
|
|
430
|
+
body.appendChild(this.placeholder(which, kind));
|
|
431
|
+
band.setAttribute("data-hf-empty", "true");
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
band.removeAttribute("data-hf-empty");
|
|
435
|
+
const anchors = this.storyAnchors(partUri);
|
|
436
|
+
if (anchors.length === 0) {
|
|
437
|
+
body.appendChild(this.placeholder(which, kind));
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
for (const anchorId of anchors) {
|
|
441
|
+
const el = this.renderStoryBlock(anchorId);
|
|
442
|
+
if (!el)
|
|
443
|
+
continue;
|
|
444
|
+
body.appendChild(el);
|
|
445
|
+
// Adopt BEFORE wiring: the editor resolves a block's anchor from `data-hf-anchor` first,
|
|
446
|
+
// because a story paragraph's content-addressed unid can collide with another part's.
|
|
447
|
+
this.adoptBlock(el, anchorId);
|
|
448
|
+
this.callbacks.wireBlock(el);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Mark a story paragraph as belonging to this region. The full anchor id is stamped alongside
|
|
453
|
+
* `data-anchor` (which carries only the bare unid, matching the body's convention) so band
|
|
454
|
+
* chrome can address the block without going through the editor's unid map. Called on first
|
|
455
|
+
* render AND after an incremental swap, which replaces the DOM node.
|
|
456
|
+
*/
|
|
457
|
+
adoptBlock(el, anchorId) {
|
|
458
|
+
const body = this.blockRootOf(el);
|
|
459
|
+
if (!body)
|
|
460
|
+
return;
|
|
461
|
+
el.setAttribute("data-hf-anchor", anchorId);
|
|
462
|
+
if (el.dataset.hfAdopted === "true")
|
|
463
|
+
return;
|
|
464
|
+
el.dataset.hfAdopted = "true";
|
|
465
|
+
el.addEventListener("focus", () => {
|
|
466
|
+
body
|
|
467
|
+
.querySelectorAll("[data-hf-focused]")
|
|
468
|
+
.forEach((sib) => sib.removeAttribute("data-hf-focused"));
|
|
469
|
+
el.setAttribute("data-hf-focused", "true");
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
renderStoryBlock(anchorId) {
|
|
473
|
+
const html = this.bridge.RenderBlockHtml(this.handle, anchorId, this.options.cssPrefix, this.options.fabricateClasses);
|
|
474
|
+
if (html.charCodeAt(0) === 0x7b /* error object */)
|
|
475
|
+
return null;
|
|
476
|
+
return new DOMParser().parseFromString(html, "text/html").body
|
|
477
|
+
.firstElementChild;
|
|
478
|
+
}
|
|
479
|
+
placeholder(which, kind) {
|
|
480
|
+
const el = document.createElement("div");
|
|
481
|
+
el.className = "docx-hf-placeholder";
|
|
482
|
+
el.setAttribute("data-hf-placeholder", "");
|
|
483
|
+
const label = KIND_LABELS.find((k) => k.value === kind)?.label ?? kind;
|
|
484
|
+
el.textContent = `No ${label.toLowerCase()} ${which} — pick a kind to create one.`;
|
|
485
|
+
return el;
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Surface the caveat that comes with the selected kind. Turning on first/even means those pages
|
|
489
|
+
* stop using the Default stories entirely, which bites hardest on the OTHER band: enabling an
|
|
490
|
+
* even header with no even footer leaves even pages footer-less, and enabling a first-page
|
|
491
|
+
* header with an empty first-page footer leaves page 1 footer-less. The note is shown whenever
|
|
492
|
+
* first/even is selected (the behavior change is real either way); the fix button appears only
|
|
493
|
+
* when the counterpart story is missing entirely, which is what a user almost always wants next.
|
|
494
|
+
*/
|
|
495
|
+
renderKindWarning(which) {
|
|
496
|
+
const band = this.bandFor(which);
|
|
497
|
+
const warning = band.querySelector("[data-hf-warning]");
|
|
498
|
+
if (!warning)
|
|
499
|
+
return;
|
|
500
|
+
const kind = this.kinds[which];
|
|
501
|
+
if (kind === "default") {
|
|
502
|
+
warning.hidden = true;
|
|
503
|
+
warning.textContent = "";
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
const other = which === "header" ? "footer" : "header";
|
|
507
|
+
warning.hidden = false;
|
|
508
|
+
warning.textContent = `${kind === "even" ? EVEN_WARNING : FIRST_WARNING} `;
|
|
509
|
+
if (this.partUriFor(other, kind))
|
|
510
|
+
return; // counterpart exists — nothing to offer
|
|
511
|
+
const fix = document.createElement("button");
|
|
512
|
+
fix.type = "button";
|
|
513
|
+
fix.setAttribute("data-hf-fix-counterpart", "");
|
|
514
|
+
fix.textContent = `Also create a ${kind === "even" ? "matching even" : "first-page"} ${other}`;
|
|
515
|
+
fix.addEventListener("click", () => {
|
|
516
|
+
this.setKind(other, kind);
|
|
517
|
+
this.renderKindWarning(which);
|
|
518
|
+
});
|
|
519
|
+
warning.appendChild(fix);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
function parseResult(json) {
|
|
523
|
+
try {
|
|
524
|
+
return JSON.parse(json);
|
|
525
|
+
}
|
|
526
|
+
catch {
|
|
527
|
+
return { success: false };
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
//# sourceMappingURL=editor-headerfooter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor-headerfooter.js","sourceRoot":"","sources":["../src/editor-headerfooter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit-sequence diff for the editor's incremental structural repaint.
|
|
3
|
+
*
|
|
4
|
+
* After a structural op (insert table/row, footnote, delete block, undo/redo)
|
|
5
|
+
* the editor fetches the session's {@link RenderPlan} (`ListBlocks`) and diffs
|
|
6
|
+
* each container's unit sequence against the DOM's, so unchanged blocks keep
|
|
7
|
+
* their DOM nodes and only changed/created units re-render — replacing the
|
|
8
|
+
* whole-document remount that cost seconds on large documents.
|
|
9
|
+
*
|
|
10
|
+
* Pure functions only: DOM walking, rendering, and fallback policy live in
|
|
11
|
+
* `editor.ts` (`DocxEditor.reconcile`).
|
|
12
|
+
*/
|
|
13
|
+
/** One top-level render unit: a body block (`p`/`h`/`li`), one whole table
|
|
14
|
+
* (`tbl`), or one footnote/endnote definition (`fn`/`en`). Mirrors the wire
|
|
15
|
+
* shape of `DocxSessionBridge.ListBlocks`. `sig` (container units only) is a
|
|
16
|
+
* content signature: a table or note keeps its unid when content INSIDE it
|
|
17
|
+
* changes, so the diff tokens must include it or a changed container would be
|
|
18
|
+
* kept stale. */
|
|
19
|
+
export interface RenderUnit {
|
|
20
|
+
id: string;
|
|
21
|
+
kind: string;
|
|
22
|
+
sig?: string;
|
|
23
|
+
}
|
|
24
|
+
/** The diff token for a unit: unid plus the container content signature. The DOM
|
|
25
|
+
* side composes the same token from a node's `data-anchor` + `data-render-sig`
|
|
26
|
+
* stamp, so a container whose inside changed diffs as an in-place substitution. */
|
|
27
|
+
export declare function tokenOf(unit: RenderUnit): string;
|
|
28
|
+
/** Per-container render plan — the wire shape of `DocxSessionBridge.ListBlocks`. */
|
|
29
|
+
export interface RenderPlan {
|
|
30
|
+
body: RenderUnit[];
|
|
31
|
+
footnotes: RenderUnit[];
|
|
32
|
+
endnotes: RenderUnit[];
|
|
33
|
+
}
|
|
34
|
+
export interface UnitDiff {
|
|
35
|
+
/** newIndex → oldIndex for units that keep their existing DOM node. */
|
|
36
|
+
keep: Map<number, number>;
|
|
37
|
+
/** Indices into the OLD DOM sequence whose nodes must be removed. */
|
|
38
|
+
removed: number[];
|
|
39
|
+
/** Indices into the NEW plan that need a fresh render. */
|
|
40
|
+
added: number[];
|
|
41
|
+
/**
|
|
42
|
+
* added/removed pairs that are an IN-PLACE change (same number of kept units
|
|
43
|
+
* on each side) — e.g. a text edit re-hashing a block's content-addressed
|
|
44
|
+
* unid. A substituted list item keeps its list position, so it renumbers no
|
|
45
|
+
* siblings and may reconcile where a pure li insert/remove may not.
|
|
46
|
+
*/
|
|
47
|
+
substituted: Array<{
|
|
48
|
+
oldIndex: number;
|
|
49
|
+
newIndex: number;
|
|
50
|
+
}>;
|
|
51
|
+
}
|
|
52
|
+
/** unid ("a1b2…") from a full anchor id ("p:body:a1b2…"). */
|
|
53
|
+
export declare function unidOf(id: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* LCS diff of the DOM's unit-token sequence against the new plan's. Old entries
|
|
56
|
+
* are tokens (see {@link tokenOf} — bare unids for leaf blocks, `unid|sig` for
|
|
57
|
+
* containers). Equal tokens are interchangeable (content-addressed: equal token
|
|
58
|
+
* ⇒ equal content ⇒ equal rendering, up to position-dependent chrome the caller
|
|
59
|
+
* handles). O(n·m) — sequences are document block counts, a few hundred.
|
|
60
|
+
*/
|
|
61
|
+
export declare function diffUnits(oldUnids: string[], newUnits: RenderUnit[]): UnitDiff;
|
|
62
|
+
/**
|
|
63
|
+
* Whether this diff must fall back to a full remount:
|
|
64
|
+
* - a PURE li insert or removal (not an in-place substitution) — sibling list
|
|
65
|
+
* items renumber without their own XML changing, which a unit diff cannot see;
|
|
66
|
+
* - total churn above `threshold` (a remount is cheaper and simpler than
|
|
67
|
+
* rendering half the document block-by-block).
|
|
68
|
+
*
|
|
69
|
+
* `oldKinds[i]` is the kind of the old sequence's i-th unit (the DOM knows it).
|
|
70
|
+
* An li substitution deliberately does NOT force a remount — its list position
|
|
71
|
+
* is unchanged; the CALLER must still verify its list facts (numId/ilvl)
|
|
72
|
+
* survived, and remount when they changed.
|
|
73
|
+
*/
|
|
74
|
+
export declare function needsRemount(diff: UnitDiff, newUnits: RenderUnit[], oldKinds: string[], threshold?: number): boolean;
|
|
75
|
+
//# sourceMappingURL=editor-reconcile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor-reconcile.d.ts","sourceRoot":"","sources":["../src/editor-reconcile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;kBAKkB;AAClB,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;oFAEoF;AACpF,wBAAgB,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAEhD;AAED,oFAAoF;AACpF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,UAAU,EAAE,CAAC;IACnB,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB,QAAQ,EAAE,UAAU,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,QAAQ;IACvB,uEAAuE;IACvE,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1B,qEAAqE;IACrE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB;;;;;OAKG;IACH,WAAW,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5D;AAED,6DAA6D;AAC7D,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,QAAQ,CA8D9E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,UAAU,EAAE,EACtB,QAAQ,EAAE,MAAM,EAAE,EAClB,SAAS,SAAK,GACb,OAAO,CAWT"}
|