wordinweb 0.1.8 → 0.1.9
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 +1 -1
- package/dist/index.d.ts +16 -10
- package/dist/index.js +479 -75
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -6111,23 +6111,49 @@ var DocxDocument = class _DocxDocument {
|
|
|
6111
6111
|
}
|
|
6112
6112
|
this._modelVersion++;
|
|
6113
6113
|
}
|
|
6114
|
-
/**
|
|
6115
|
-
*
|
|
6116
|
-
*
|
|
6117
|
-
*
|
|
6118
|
-
* containers, revisions, bookmarks, and section breaks use refresh().
|
|
6119
|
-
*/
|
|
6114
|
+
/** Reparse the two sibling body-story paragraphs created by Enter without
|
|
6115
|
+
* rebuilding the complete document model. Paragraphs nested in table cells
|
|
6116
|
+
* are included because legal documents spend most of their body inside
|
|
6117
|
+
* tables; revisions, bookmarks, fields, and section breaks use refresh(). */
|
|
6120
6118
|
reparseDirectBodyParagraphSplit(beforeSource, afterSource) {
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6119
|
+
const parsed = this.reparseDirectBodyParagraphSplits(beforeSource, [afterSource]);
|
|
6120
|
+
return parsed ? { before: parsed[0], after: parsed[1] } : null;
|
|
6121
|
+
}
|
|
6122
|
+
/** Reparse a body paragraph plus several new siblings created by
|
|
6123
|
+
* click-and-type without rebuilding the complete document model. */
|
|
6124
|
+
reparseDirectBodyParagraphSplits(beforeSource, afterSources) {
|
|
6125
|
+
if (afterSources.length === 0) return null;
|
|
6126
|
+
const parent = this.findParentOf(beforeSource);
|
|
6127
|
+
if (!parent) return null;
|
|
6128
|
+
const beforeIndex = parent.children.indexOf(beforeSource);
|
|
6129
|
+
if (beforeIndex < 0 || afterSources.some((source, i) => parent.children[beforeIndex + i + 1] !== source)) {
|
|
6130
|
+
return null;
|
|
6131
|
+
}
|
|
6132
|
+
if (localName(beforeSource.name) !== "p" || afterSources.some((source) => localName(source.name) !== "p")) {
|
|
6133
|
+
return null;
|
|
6134
|
+
}
|
|
6135
|
+
const findBlockList = (blocks2) => {
|
|
6136
|
+
const index = blocks2.findIndex((block) => block.type === "paragraph" && block.src === beforeSource);
|
|
6137
|
+
if (index >= 0) return { blocks: blocks2, index };
|
|
6138
|
+
for (const block of blocks2) {
|
|
6139
|
+
if (block.type !== "table") continue;
|
|
6140
|
+
for (const row of block.rows) {
|
|
6141
|
+
for (const cell of row.cells) {
|
|
6142
|
+
const found = findBlockList(cell.blocks);
|
|
6143
|
+
if (found) return found;
|
|
6144
|
+
}
|
|
6145
|
+
}
|
|
6146
|
+
}
|
|
6147
|
+
return null;
|
|
6148
|
+
};
|
|
6149
|
+
let location = null;
|
|
6150
|
+
for (const section of this.sections) {
|
|
6151
|
+
location = findBlockList(section.blocks);
|
|
6152
|
+
if (location) break;
|
|
6153
|
+
}
|
|
6154
|
+
if (!location) return null;
|
|
6155
|
+
const { blocks, index: blockIndex } = location;
|
|
6156
|
+
if (afterSources.some((source) => blocks.some((block) => block.src === source))) return null;
|
|
6131
6157
|
const old = blocks[blockIndex];
|
|
6132
6158
|
if (old.type !== "paragraph" || old.sectionBreak) return null;
|
|
6133
6159
|
const unsafe = (element) => {
|
|
@@ -6135,7 +6161,7 @@ var DocxDocument = class _DocxDocument {
|
|
|
6135
6161
|
if (name === "sectPr" || name === "bookmarkStart" || name === "bookmarkEnd" || name === "fldChar" || name === "instrText" || name === "fldSimple" || name === "sdt" || name === "ins" || name === "del" || name.startsWith("move") || name.endsWith("PrChange")) return true;
|
|
6136
6162
|
return element.children.some(unsafe);
|
|
6137
6163
|
};
|
|
6138
|
-
if (unsafe(beforeSource) || unsafe
|
|
6164
|
+
if (unsafe(beforeSource) || afterSources.some(unsafe)) return null;
|
|
6139
6165
|
const readPart = (part) => this.readXmlOptional(part);
|
|
6140
6166
|
const ctx = {
|
|
6141
6167
|
...this.ctxBase,
|
|
@@ -6143,11 +6169,103 @@ var DocxDocument = class _DocxDocument {
|
|
|
6143
6169
|
readPart,
|
|
6144
6170
|
independentTextboxStories: true
|
|
6145
6171
|
};
|
|
6146
|
-
const
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6172
|
+
const parsed = [beforeSource, ...afterSources].map((source) => parseParagraph(source, ctx));
|
|
6173
|
+
if (parsed.some((paragraph) => paragraph.revisionHidden || paragraph.sectionBreak)) return null;
|
|
6174
|
+
blocks.splice(blockIndex, 1, ...parsed);
|
|
6175
|
+
return parsed;
|
|
6176
|
+
}
|
|
6177
|
+
/** Reparse one retained body-story paragraph after a structural edit that
|
|
6178
|
+
* leaves its surrounding block list unchanged, such as inserting ink. */
|
|
6179
|
+
reparseBodyParagraph(source) {
|
|
6180
|
+
if (localName(source.name) !== "p") return null;
|
|
6181
|
+
const findBlockList = (blocks) => {
|
|
6182
|
+
const index = blocks.findIndex((block) => block.type === "paragraph" && block.src === source);
|
|
6183
|
+
if (index >= 0) return { blocks, index };
|
|
6184
|
+
for (const block of blocks) {
|
|
6185
|
+
if (block.type !== "table") continue;
|
|
6186
|
+
for (const row of block.rows) {
|
|
6187
|
+
for (const cell of row.cells) {
|
|
6188
|
+
const found = findBlockList(cell.blocks);
|
|
6189
|
+
if (found) return found;
|
|
6190
|
+
}
|
|
6191
|
+
}
|
|
6192
|
+
}
|
|
6193
|
+
return null;
|
|
6194
|
+
};
|
|
6195
|
+
let location = null;
|
|
6196
|
+
for (const section of this.sections) {
|
|
6197
|
+
location = findBlockList(section.blocks);
|
|
6198
|
+
if (location) break;
|
|
6199
|
+
}
|
|
6200
|
+
if (!location) return null;
|
|
6201
|
+
const old = location.blocks[location.index];
|
|
6202
|
+
if (old.type !== "paragraph" || old.sectionBreak) return null;
|
|
6203
|
+
const unsafe = (element) => {
|
|
6204
|
+
const name = localName(element.name);
|
|
6205
|
+
if (name === "sectPr" || name === "bookmarkStart" || name === "bookmarkEnd") return true;
|
|
6206
|
+
return element.children.some(unsafe);
|
|
6207
|
+
};
|
|
6208
|
+
if (unsafe(source)) return null;
|
|
6209
|
+
const paragraph = parseParagraph(source, {
|
|
6210
|
+
...this.ctxBase,
|
|
6211
|
+
rels: this.documentRels,
|
|
6212
|
+
readPart: (part) => this.readXmlOptional(part),
|
|
6213
|
+
independentTextboxStories: true
|
|
6214
|
+
});
|
|
6215
|
+
if (paragraph.revisionHidden || paragraph.sectionBreak) return null;
|
|
6216
|
+
location.blocks[location.index] = paragraph;
|
|
6217
|
+
return paragraph;
|
|
6218
|
+
}
|
|
6219
|
+
/** Reparse two sibling body-story paragraphs after Backspace/Delete merged
|
|
6220
|
+
* their XML into one. Keeps the parsed model generation stable so long
|
|
6221
|
+
* documents can use incremental layout instead of repaginating in full. */
|
|
6222
|
+
reparseDirectBodyParagraphMerge(beforeSource, afterSource, survivorSource) {
|
|
6223
|
+
if (survivorSource !== beforeSource && survivorSource !== afterSource) return null;
|
|
6224
|
+
if (localName(beforeSource.name) !== "p" || localName(afterSource.name) !== "p") return null;
|
|
6225
|
+
const parent = this.findParentOf(survivorSource);
|
|
6226
|
+
if (!parent || parent.children.includes(survivorSource === beforeSource ? afterSource : beforeSource)) return null;
|
|
6227
|
+
const findBlockList = (blocks2) => {
|
|
6228
|
+
const index2 = blocks2.findIndex(
|
|
6229
|
+
(block, i) => block.type === "paragraph" && block.src === beforeSource && blocks2[i + 1]?.type === "paragraph" && blocks2[i + 1].src === afterSource
|
|
6230
|
+
);
|
|
6231
|
+
if (index2 >= 0) return { blocks: blocks2, index: index2 };
|
|
6232
|
+
for (const block of blocks2) {
|
|
6233
|
+
if (block.type !== "table") continue;
|
|
6234
|
+
for (const row of block.rows) {
|
|
6235
|
+
for (const cell of row.cells) {
|
|
6236
|
+
const found = findBlockList(cell.blocks);
|
|
6237
|
+
if (found) return found;
|
|
6238
|
+
}
|
|
6239
|
+
}
|
|
6240
|
+
}
|
|
6241
|
+
return null;
|
|
6242
|
+
};
|
|
6243
|
+
let location = null;
|
|
6244
|
+
for (const section of this.sections) {
|
|
6245
|
+
location = findBlockList(section.blocks);
|
|
6246
|
+
if (location) break;
|
|
6247
|
+
}
|
|
6248
|
+
if (!location) return null;
|
|
6249
|
+
const { blocks, index } = location;
|
|
6250
|
+
const before = blocks[index];
|
|
6251
|
+
const after = blocks[index + 1];
|
|
6252
|
+
if (before.type !== "paragraph" || after.type !== "paragraph" || before.sectionBreak || after.sectionBreak) return null;
|
|
6253
|
+
const unsafe = (element) => {
|
|
6254
|
+
const name = localName(element.name);
|
|
6255
|
+
if (name === "sectPr" || name === "bookmarkStart" || name === "bookmarkEnd" || name === "fldChar" || name === "instrText" || name === "fldSimple" || name === "sdt" || name === "ins" || name === "del" || name.startsWith("move") || name.endsWith("PrChange")) return true;
|
|
6256
|
+
return element.children.some(unsafe);
|
|
6257
|
+
};
|
|
6258
|
+
if (unsafe(beforeSource) || unsafe(afterSource)) return null;
|
|
6259
|
+
const readPart = (part) => this.readXmlOptional(part);
|
|
6260
|
+
const merged = parseParagraph(survivorSource, {
|
|
6261
|
+
...this.ctxBase,
|
|
6262
|
+
rels: this.documentRels,
|
|
6263
|
+
readPart,
|
|
6264
|
+
independentTextboxStories: true
|
|
6265
|
+
});
|
|
6266
|
+
if (merged.revisionHidden || merged.sectionBreak) return null;
|
|
6267
|
+
blocks.splice(index, 2, merged);
|
|
6268
|
+
return merged;
|
|
6151
6269
|
}
|
|
6152
6270
|
deriveComments() {
|
|
6153
6271
|
const out = [];
|
|
@@ -10833,6 +10951,7 @@ var __incrStats = {
|
|
|
10833
10951
|
resumePage: -1,
|
|
10834
10952
|
convergedBlock: -1,
|
|
10835
10953
|
convergedPage: -1,
|
|
10954
|
+
pageShift: 0,
|
|
10836
10955
|
blocksLaid: 0,
|
|
10837
10956
|
fallbackReason: ""
|
|
10838
10957
|
};
|
|
@@ -10933,6 +11052,7 @@ var Engine = class {
|
|
|
10933
11052
|
this.trailingSectionBreakMarkGap = 0;
|
|
10934
11053
|
/** Bookmark name -> formatted display page number (PAGEREF rewrite). */
|
|
10935
11054
|
this.bookmarkPages = /* @__PURE__ */ new Map();
|
|
11055
|
+
this.bookmarkPageIndices = /* @__PURE__ */ new Map();
|
|
10936
11056
|
/** STYLEREF page-awareness: styleIds whose paragraphs a header/footer STYLEREF
|
|
10937
11057
|
* references (null until precomputed; empty set = no STYLEREF, tracking off). */
|
|
10938
11058
|
this.styleRefTrack = null;
|
|
@@ -11025,6 +11145,8 @@ var Engine = class {
|
|
|
11025
11145
|
this.incrConvergeBlockIdx = -1;
|
|
11026
11146
|
this.incrConvergePageIdx = -1;
|
|
11027
11147
|
this.incrConvergeItemDelta = 0;
|
|
11148
|
+
this.incrConvergePrevPointPageIdx = -1;
|
|
11149
|
+
this.incrPageShift = 0;
|
|
11028
11150
|
/** New block indices are old indices plus this value after a structural
|
|
11029
11151
|
* split, so convergence compares the same semantic suffix boundary. */
|
|
11030
11152
|
this.incrBlockDelta = 0;
|
|
@@ -11231,6 +11353,7 @@ var Engine = class {
|
|
|
11231
11353
|
points: this.incrPoints,
|
|
11232
11354
|
pages: this.pages,
|
|
11233
11355
|
bookmarks: this.bookmarkPages,
|
|
11356
|
+
bookmarkPageIndices: this.bookmarkPageIndices,
|
|
11234
11357
|
modelVersion: this.doc.modelVersion,
|
|
11235
11358
|
seqCounters: this.seqCounters,
|
|
11236
11359
|
seqAssigned: this.seqAssigned,
|
|
@@ -11367,9 +11490,13 @@ var Engine = class {
|
|
|
11367
11490
|
});
|
|
11368
11491
|
if (this.incrPrevPoints && blockIdx > this.incrFirstDirty) {
|
|
11369
11492
|
const pp = this.incrPrevPoints.get(blockIdx);
|
|
11370
|
-
|
|
11493
|
+
const pageShift = pp ? globalPageIdx - pp.pageCount : 0;
|
|
11494
|
+
if (pp && this.statesMatch(pp.state, pageShift)) {
|
|
11371
11495
|
__incrStats.convergedBlock = blockIdx;
|
|
11372
11496
|
__incrStats.convergedPage = globalPageIdx;
|
|
11497
|
+
__incrStats.pageShift = pageShift;
|
|
11498
|
+
this.incrPageShift = pageShift;
|
|
11499
|
+
this.incrConvergePrevPointPageIdx = pp.pageCount;
|
|
11373
11500
|
this.incrPoints.push(snapshot());
|
|
11374
11501
|
const reuseWholePage = p.items.length === 0 && pp.pageItemCount === 0 && Math.abs(this.y - p.bodyTop) < 1e-6;
|
|
11375
11502
|
if (reuseWholePage) {
|
|
@@ -11394,9 +11521,9 @@ var Engine = class {
|
|
|
11394
11521
|
/** True when the current engine state at a clean page top exactly matches a
|
|
11395
11522
|
* prev-layout capture point — i.e. the relaid tail has re-converged and the
|
|
11396
11523
|
* rest of the layout is guaranteed identical. */
|
|
11397
|
-
statesMatch(s) {
|
|
11524
|
+
statesMatch(s, pageShift = 0) {
|
|
11398
11525
|
const p = this.cur;
|
|
11399
|
-
if (this.col !== s.col || this.y !== s.y || this.sectionFirstPagePhys !== s.sectionFirstPagePhys || this.lastParaSpacingAfter !== s.lastParaSpacingAfter || this.lastParaAfterPad !== s.lastParaAfterPad || this.lastParaWasEmpty !== s.lastParaWasEmpty || this.trailingSectionBreakMarkGap !== s.trailingSectionBreakMarkGap || this.suppressNextSpaceBefore !== s.suppressNextSpaceBefore || this.docGridDropBefore !== s.docGridDropBefore || this.gridResyncPending !== s.gridResyncPending || this.verticalGridFlow !== s.verticalGridFlow || this.bannerSlotUsed !== s.bannerSlotUsed || p.physIndex !== s.page.physIndex || p.displayNumber !== s.page.displayNumber || p.bodyTop !== s.page.bodyTop || p.bodyBottom !== s.page.bodyBottom) {
|
|
11526
|
+
if (this.col !== s.col || this.y !== s.y || this.sectionFirstPagePhys !== s.sectionFirstPagePhys || this.lastParaSpacingAfter !== s.lastParaSpacingAfter || this.lastParaAfterPad !== s.lastParaAfterPad || this.lastParaWasEmpty !== s.lastParaWasEmpty || this.trailingSectionBreakMarkGap !== s.trailingSectionBreakMarkGap || this.suppressNextSpaceBefore !== s.suppressNextSpaceBefore || this.docGridDropBefore !== s.docGridDropBefore || this.gridResyncPending !== s.gridResyncPending || this.verticalGridFlow !== s.verticalGridFlow || this.bannerSlotUsed !== s.bannerSlotUsed || p.physIndex !== s.page.physIndex + pageShift || p.displayNumber !== s.page.displayNumber + pageShift || p.bodyTop !== s.page.bodyTop || p.bodyBottom !== s.page.bodyBottom) {
|
|
11400
11527
|
return false;
|
|
11401
11528
|
}
|
|
11402
11529
|
if (this.seenNumIds.size !== s.seenNumIds.length) return false;
|
|
@@ -11453,11 +11580,60 @@ var Engine = class {
|
|
|
11453
11580
|
this.counters = new Map(s.counters.map(([k, v]) => [k, [...v]]));
|
|
11454
11581
|
this.seenNumIds = new Set(s.seenNumIds);
|
|
11455
11582
|
}
|
|
11583
|
+
bodyHasPageField(el16 = this.doc.docRoot) {
|
|
11584
|
+
const name = el16.name.includes(":") ? el16.name.slice(el16.name.indexOf(":") + 1) : el16.name;
|
|
11585
|
+
const instruction = name === "instrText" ? el16.text : name === "fldSimple" ? el16.attrs["w:instr"] ?? "" : "";
|
|
11586
|
+
if (/\bPAGE\b/i.test(instruction)) return true;
|
|
11587
|
+
return el16.children.some((child4) => this.bodyHasPageField(child4));
|
|
11588
|
+
}
|
|
11589
|
+
/** Clone a retained suffix page onto its new physical/display number. Body
|
|
11590
|
+
* items and page-border items stay identical; headers and footers are removed
|
|
11591
|
+
* so the final pass can rebuild PAGE fields against the shifted number. */
|
|
11592
|
+
shiftRetainedPage(page, pageShift) {
|
|
11593
|
+
if (page.hfStart === void 0) return null;
|
|
11594
|
+
const physIndex = page.physIndex + pageShift;
|
|
11595
|
+
const displayNumber = page.displayNumber + pageShift;
|
|
11596
|
+
const isFirstOfSection = physIndex === this.sectionFirstPagePhys;
|
|
11597
|
+
const useEven = this.doc.evenAndOddHeaders && displayNumber % 2 === 0;
|
|
11598
|
+
const headerRel = page.sp.titlePage && isFirstOfSection ? page.sp.headerRefs.first : useEven ? page.sp.headerRefs.even : page.sp.headerRefs.default;
|
|
11599
|
+
const footerRel = page.sp.titlePage && isFirstOfSection ? page.sp.footerRefs.first : useEven ? page.sp.footerRefs.even : page.sp.footerRefs.default;
|
|
11600
|
+
const shifted = {
|
|
11601
|
+
...page,
|
|
11602
|
+
items: page.items.slice(0, page.hfStart),
|
|
11603
|
+
physIndex,
|
|
11604
|
+
displayNumber,
|
|
11605
|
+
headerRel,
|
|
11606
|
+
footerRel,
|
|
11607
|
+
hfStart: void 0,
|
|
11608
|
+
colXs: [...page.colXs],
|
|
11609
|
+
colWidths: [...page.colWidths],
|
|
11610
|
+
footnotes: page.footnotes.map((note) => ({ ...note, items: [...note.items] })),
|
|
11611
|
+
footnoteH: [...page.footnoteH],
|
|
11612
|
+
bands: page.bands.map((band) => ({
|
|
11613
|
+
...band,
|
|
11614
|
+
colXs: [...band.colXs],
|
|
11615
|
+
colWidths: [...band.colWidths],
|
|
11616
|
+
bottoms: [...band.bottoms]
|
|
11617
|
+
}))
|
|
11618
|
+
};
|
|
11619
|
+
if (headerRel === page.headerRel && footerRel === page.footerRel) return shifted;
|
|
11620
|
+
this.sp = shifted.sp;
|
|
11621
|
+
const contentWidth = shifted.sp.pageWidth - shifted.sp.marginLeft - shifted.sp.marginRight - shifted.sp.gutter;
|
|
11622
|
+
const header = this.doc.headers.get(headerRel ?? "");
|
|
11623
|
+
const footer = this.doc.footers.get(footerRel ?? "");
|
|
11624
|
+
const headerHeight = this.measureHeaderFooter(header, shifted, contentWidth, this.pageFieldFrameOverlay(header));
|
|
11625
|
+
const footerHeight = this.measureHeaderFooter(footer, shifted, contentWidth, this.pageFieldFrameOverlay(footer));
|
|
11626
|
+
if (headerHeight !== page.headerHeight || footerHeight !== page.footerHeight) return null;
|
|
11627
|
+
shifted.headerHeight = headerHeight;
|
|
11628
|
+
shifted.footerHeight = footerHeight;
|
|
11629
|
+
return shifted;
|
|
11630
|
+
}
|
|
11456
11631
|
/** Attempt an incremental layout; return null (and leave a discarded, dirty
|
|
11457
11632
|
* engine) if reuse can't be proven safe, so the caller does a full layout in a
|
|
11458
11633
|
* fresh engine. */
|
|
11459
11634
|
runIncremental(prev, dirtyHint, dirtySource) {
|
|
11460
11635
|
__incrStats.fallbackReason = "";
|
|
11636
|
+
__incrStats.pageShift = 0;
|
|
11461
11637
|
const fallback = (reason) => {
|
|
11462
11638
|
__incrStats.fallbackReason = reason;
|
|
11463
11639
|
const perf2 = globalThis.__dxwPerf;
|
|
@@ -11472,11 +11648,12 @@ var Engine = class {
|
|
|
11472
11648
|
const blocks = this.doc.sections[0].blocks;
|
|
11473
11649
|
let newSigs = null;
|
|
11474
11650
|
let firstDirty = 0;
|
|
11475
|
-
if (dirtyHint && blocks.length
|
|
11651
|
+
if (dirtyHint && blocks.length > inc.sigs.length) {
|
|
11652
|
+
const delta = blocks.length - inc.sigs.length;
|
|
11476
11653
|
const inserted = blocks.findIndex((block) => block.src === dirtyHint);
|
|
11477
|
-
const changed = inserted -
|
|
11654
|
+
const changed = inserted - delta;
|
|
11478
11655
|
if (changed >= 0) {
|
|
11479
|
-
let hashed =
|
|
11656
|
+
let hashed = delta + 1;
|
|
11480
11657
|
let neighborsOk = true;
|
|
11481
11658
|
if (changed > 0) {
|
|
11482
11659
|
hashed++;
|
|
@@ -11484,21 +11661,47 @@ var Engine = class {
|
|
|
11484
11661
|
}
|
|
11485
11662
|
if (neighborsOk && inserted < blocks.length - 1) {
|
|
11486
11663
|
hashed++;
|
|
11487
|
-
neighborsOk = this.blockSig(blocks[inserted + 1]) === inc.sigs[
|
|
11664
|
+
neighborsOk = this.blockSig(blocks[inserted + 1]) === inc.sigs[changed + 1];
|
|
11488
11665
|
}
|
|
11489
11666
|
if (neighborsOk) {
|
|
11490
11667
|
newSigs = inc.sigs.slice();
|
|
11491
11668
|
newSigs[changed] = this.blockSig(blocks[changed]);
|
|
11492
|
-
newSigs.splice(
|
|
11669
|
+
newSigs.splice(changed + 1, 0, ...blocks.slice(changed + 1, inserted + 1).map((block) => this.blockSig(block)));
|
|
11493
11670
|
firstDirty = changed;
|
|
11494
11671
|
__incrStats.hintFastPath = true;
|
|
11495
11672
|
__incrStats.blocksHashed = hashed;
|
|
11496
11673
|
__incrStats.firstDirty = changed;
|
|
11497
|
-
this.incrBlockDelta =
|
|
11674
|
+
this.incrBlockDelta = delta;
|
|
11498
11675
|
this.incrBlockShiftAfter = changed;
|
|
11499
11676
|
}
|
|
11500
11677
|
}
|
|
11501
11678
|
}
|
|
11679
|
+
if (newSigs === null && dirtyHint && blocks.length === inc.sigs.length - 1) {
|
|
11680
|
+
const changed = blocks.findIndex((block) => block.src === dirtyHint);
|
|
11681
|
+
if (changed >= 0) {
|
|
11682
|
+
let hashed = 1;
|
|
11683
|
+
let neighborsOk = true;
|
|
11684
|
+
if (changed > 0) {
|
|
11685
|
+
hashed++;
|
|
11686
|
+
neighborsOk = this.blockSig(blocks[changed - 1]) === inc.sigs[changed - 1];
|
|
11687
|
+
}
|
|
11688
|
+
if (neighborsOk && changed < blocks.length - 1) {
|
|
11689
|
+
hashed++;
|
|
11690
|
+
neighborsOk = this.blockSig(blocks[changed + 1]) === inc.sigs[changed + 2];
|
|
11691
|
+
}
|
|
11692
|
+
if (neighborsOk) {
|
|
11693
|
+
newSigs = inc.sigs.slice();
|
|
11694
|
+
newSigs[changed] = this.blockSig(blocks[changed]);
|
|
11695
|
+
newSigs.splice(changed + 1, 1);
|
|
11696
|
+
firstDirty = changed;
|
|
11697
|
+
__incrStats.hintFastPath = true;
|
|
11698
|
+
__incrStats.blocksHashed = hashed;
|
|
11699
|
+
__incrStats.firstDirty = changed;
|
|
11700
|
+
this.incrBlockDelta = -1;
|
|
11701
|
+
this.incrBlockShiftAfter = changed + 1;
|
|
11702
|
+
}
|
|
11703
|
+
}
|
|
11704
|
+
}
|
|
11502
11705
|
if (newSigs === null && dirtyHint && blocks.length === inc.sigs.length) {
|
|
11503
11706
|
const d = blocks.findIndex((b) => b.src === dirtyHint);
|
|
11504
11707
|
if (d >= 0) {
|
|
@@ -11555,19 +11758,47 @@ var Engine = class {
|
|
|
11555
11758
|
__incrStats.resumePage = rp.pageCount;
|
|
11556
11759
|
__incrStats.convergedBlock = -1;
|
|
11557
11760
|
__incrStats.convergedPage = -1;
|
|
11761
|
+
__incrStats.pageShift = 0;
|
|
11558
11762
|
__incrStats.blocksLaid = 0;
|
|
11559
11763
|
this.restoreIncrState(rp.state, inc.pages[rp.pageCount].items.slice(0, rp.pageItemCount));
|
|
11560
11764
|
this.layoutBlocks(blocks, rp.blockIdx);
|
|
11561
11765
|
if (this.incrAbort) return fallback("layout-abort");
|
|
11562
11766
|
const suffixStart = this.incrConvergePrevPageIdx >= 0 ? this.incrConvergePrevPageIdx : inc.pages.length;
|
|
11563
|
-
const
|
|
11564
|
-
|
|
11767
|
+
const middleCount = this.pages.length;
|
|
11768
|
+
const hasRetainedSuffix = suffixStart < inc.pages.length;
|
|
11769
|
+
const pageShift = hasRetainedSuffix ? prefixCount + middleCount - suffixStart : 0;
|
|
11770
|
+
if (hasRetainedSuffix && pageShift !== this.incrPageShift) return fallback("page-shift");
|
|
11771
|
+
if (pageShift !== 0 && this.bodyHasPageField()) return fallback("body-page-field-shift");
|
|
11772
|
+
const shiftedSuffix = [];
|
|
11773
|
+
if (pageShift !== 0) {
|
|
11774
|
+
for (const page of inc.pages.slice(suffixStart)) {
|
|
11775
|
+
const shifted = this.shiftRetainedPage(page, pageShift);
|
|
11776
|
+
if (!shifted) return fallback("shifted-header-footer");
|
|
11777
|
+
shiftedSuffix.push(shifted);
|
|
11778
|
+
}
|
|
11779
|
+
}
|
|
11565
11780
|
const mergedBookmarks = new Map(inc.bookmarks);
|
|
11566
|
-
const
|
|
11781
|
+
const mergedBookmarkPageIndices = new Map(inc.bookmarkPageIndices);
|
|
11782
|
+
if (pageShift !== 0) {
|
|
11783
|
+
for (const [name, oldPageIndex] of inc.bookmarkPageIndices) {
|
|
11784
|
+
if (oldPageIndex < suffixStart) continue;
|
|
11785
|
+
const page = inc.pages[oldPageIndex];
|
|
11786
|
+
if (!page) continue;
|
|
11787
|
+
mergedBookmarkPageIndices.set(name, oldPageIndex + pageShift);
|
|
11788
|
+
mergedBookmarks.set(
|
|
11789
|
+
name,
|
|
11790
|
+
formatNumber(page.displayNumber + pageShift, PAGE_FMT[page.sp.pageNumberFormat ?? "decimal"] ?? "decimal")
|
|
11791
|
+
);
|
|
11792
|
+
}
|
|
11793
|
+
}
|
|
11567
11794
|
for (const [name, page] of this.bookmarkPages) {
|
|
11568
|
-
if (inc.bookmarks.get(name) !== page) movedBookmarks.add(name);
|
|
11569
11795
|
mergedBookmarks.set(name, page);
|
|
11570
11796
|
}
|
|
11797
|
+
for (const [name, pageIndex] of this.bookmarkPageIndices) mergedBookmarkPageIndices.set(name, pageIndex);
|
|
11798
|
+
const movedBookmarks = /* @__PURE__ */ new Set();
|
|
11799
|
+
for (const [name, page] of mergedBookmarks) {
|
|
11800
|
+
if (inc.bookmarks.get(name) !== page) movedBookmarks.add(name);
|
|
11801
|
+
}
|
|
11571
11802
|
const pageRefUpdates = [];
|
|
11572
11803
|
if (movedBookmarks.size > 0) {
|
|
11573
11804
|
for (const page of inc.pages) {
|
|
@@ -11585,32 +11816,53 @@ var Engine = class {
|
|
|
11585
11816
|
this.placeEndnotes();
|
|
11586
11817
|
this.emitFootnoteAreas();
|
|
11587
11818
|
this.emitColumnSeparators();
|
|
11588
|
-
this.finalizeHeadersFooters();
|
|
11589
11819
|
this.bookmarkPages = mergedBookmarks;
|
|
11590
|
-
this.
|
|
11820
|
+
this.bookmarkPageIndices = mergedBookmarkPageIndices;
|
|
11591
11821
|
this.applySectionVAlign();
|
|
11822
|
+
if (pageShift !== 0) {
|
|
11823
|
+
for (let i = 0; i < middleCount; i++) this.emitPageBorders(this.pages[i]);
|
|
11824
|
+
this.pages.push(...shiftedSuffix);
|
|
11825
|
+
this.finalizeHeadersFooters(false);
|
|
11826
|
+
} else {
|
|
11827
|
+
this.finalizeHeadersFooters();
|
|
11828
|
+
}
|
|
11829
|
+
this.rewritePageRefs(this.pages);
|
|
11592
11830
|
if (this.incrAbort) return fallback("postpass-abort");
|
|
11593
|
-
const middle = this.pages.map((p) => laidOutPage(p));
|
|
11831
|
+
const middle = this.pages.slice(0, middleCount).map((p) => laidOutPage(p));
|
|
11594
11832
|
let structuralPrefixEnd = prefixCount;
|
|
11595
11833
|
if (dirtySource) {
|
|
11596
|
-
const dirtyMiddleIdx = this.pages.findIndex(
|
|
11834
|
+
const dirtyMiddleIdx = this.pages.slice(0, middleCount).findIndex(
|
|
11597
11835
|
(page) => page.items.some((item) => item.kind === "text" && item.src?.t === dirtySource)
|
|
11598
11836
|
);
|
|
11599
11837
|
if (dirtyMiddleIdx > 0) structuralPrefixEnd += dirtyMiddleIdx;
|
|
11600
11838
|
}
|
|
11601
|
-
const outPages = prev.pages.slice(0, prefixCount).concat(
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
|
|
11605
|
-
|
|
11839
|
+
const outPages = prev.pages.slice(0, prefixCount).concat(
|
|
11840
|
+
pageShift !== 0 ? this.pages.map((page) => laidOutPage(page)) : middle.concat(prev.pages.slice(suffixStart))
|
|
11841
|
+
);
|
|
11842
|
+
const outInternal = inc.pages.slice(0, prefixCount).concat(
|
|
11843
|
+
pageShift !== 0 ? this.pages : this.pages.concat(inc.pages.slice(suffixStart))
|
|
11844
|
+
);
|
|
11845
|
+
const shiftPoint = (pt, itemDelta = 0) => ({
|
|
11606
11846
|
...pt,
|
|
11607
11847
|
blockIdx: shiftedBlockIdx(pt.blockIdx),
|
|
11608
|
-
|
|
11609
|
-
|
|
11848
|
+
pageCount: pt.pageCount + pageShift,
|
|
11849
|
+
pageItemCount: pt.pageItemCount + itemDelta,
|
|
11850
|
+
state: {
|
|
11851
|
+
...pt.state,
|
|
11852
|
+
page: {
|
|
11853
|
+
...pt.state.page,
|
|
11854
|
+
physIndex: pt.state.page.physIndex + pageShift,
|
|
11855
|
+
displayNumber: pt.state.page.displayNumber + pageShift
|
|
11856
|
+
}
|
|
11857
|
+
}
|
|
11858
|
+
});
|
|
11859
|
+
const samePageTail = this.incrConvergeBlockIdx >= 0 ? inc.points.filter(
|
|
11860
|
+
(pt) => pt.pageCount === this.incrConvergePrevPointPageIdx && shiftedBlockIdx(pt.blockIdx) > this.incrConvergeBlockIdx
|
|
11861
|
+
).map((pt) => shiftPoint(pt, this.incrConvergeItemDelta)) : [];
|
|
11610
11862
|
const points = inc.points.filter((pt) => pt.pageCount < prefixCount).concat(
|
|
11611
11863
|
this.incrPoints,
|
|
11612
11864
|
samePageTail,
|
|
11613
|
-
inc.points.filter((pt) => pt.pageCount >= suffixStart).map((pt) => (
|
|
11865
|
+
inc.points.filter((pt) => pt.pageCount >= suffixStart).map((pt) => shiftPoint(pt))
|
|
11614
11866
|
);
|
|
11615
11867
|
const perf = globalThis.__dxwPerf;
|
|
11616
11868
|
if (perf) perf.incr = { ...__incrStats };
|
|
@@ -11623,6 +11875,7 @@ var Engine = class {
|
|
|
11623
11875
|
points,
|
|
11624
11876
|
pages: outInternal,
|
|
11625
11877
|
bookmarks: mergedBookmarks,
|
|
11878
|
+
bookmarkPageIndices: mergedBookmarkPageIndices,
|
|
11626
11879
|
modelVersion: this.doc.modelVersion,
|
|
11627
11880
|
seqCounters: this.seqCounters,
|
|
11628
11881
|
seqAssigned: this.seqAssigned,
|
|
@@ -11964,6 +12217,7 @@ var Engine = class {
|
|
|
11964
12217
|
counters: new Map(Array.from(this.counters, ([k, v]) => [k, [...v]])),
|
|
11965
12218
|
seenNumIds: new Set(this.seenNumIds),
|
|
11966
12219
|
bookmarkPages: new Map(this.bookmarkPages),
|
|
12220
|
+
bookmarkPageIndices: new Map(this.bookmarkPageIndices),
|
|
11967
12221
|
placedFootnotes: new Set(this.placedFootnotes),
|
|
11968
12222
|
lnCounter: this.lnCounter,
|
|
11969
12223
|
lnLastPage: this.lnLastPage,
|
|
@@ -12003,6 +12257,7 @@ var Engine = class {
|
|
|
12003
12257
|
this.counters = s.counters;
|
|
12004
12258
|
this.seenNumIds = s.seenNumIds;
|
|
12005
12259
|
this.bookmarkPages = s.bookmarkPages;
|
|
12260
|
+
this.bookmarkPageIndices = s.bookmarkPageIndices;
|
|
12006
12261
|
this.placedFootnotes = s.placedFootnotes;
|
|
12007
12262
|
this.lnCounter = s.lnCounter;
|
|
12008
12263
|
this.lnLastPage = s.lnLastPage;
|
|
@@ -13523,6 +13778,7 @@ var Engine = class {
|
|
|
13523
13778
|
for (const bm of para.bookmarks) {
|
|
13524
13779
|
if (!this.bookmarkPages.has(bm)) {
|
|
13525
13780
|
this.bookmarkPages.set(bm, formatNumber(pg.displayNumber, PAGE_FMT[pg.sp.pageNumberFormat ?? "decimal"] ?? "decimal"));
|
|
13781
|
+
this.bookmarkPageIndices.set(bm, pg.physIndex - 1);
|
|
13526
13782
|
}
|
|
13527
13783
|
}
|
|
13528
13784
|
}
|
|
@@ -16905,7 +17161,7 @@ function renderToDom(doc, layout, container, options = {}, prev) {
|
|
|
16905
17161
|
renderComments(doc, root, handle.bindings, zoom, options.onDeleteComment, options.onReplyComment);
|
|
16906
17162
|
}
|
|
16907
17163
|
};
|
|
16908
|
-
const wantedPages = () => {
|
|
17164
|
+
const wantedPages = (overscan = 2) => {
|
|
16909
17165
|
const wanted = /* @__PURE__ */ new Set();
|
|
16910
17166
|
const top = container.scrollTop;
|
|
16911
17167
|
const bottom = top + Math.max(container.clientHeight, 1);
|
|
@@ -16921,15 +17177,15 @@ function renderToDom(doc, layout, container, options = {}, prev) {
|
|
|
16921
17177
|
y = pageBottom + gap;
|
|
16922
17178
|
}
|
|
16923
17179
|
if (first < 0) first = last = Math.max(0, pages.length - 1);
|
|
16924
|
-
for (let i = Math.max(0, first -
|
|
17180
|
+
for (let i = Math.max(0, first - overscan); i <= Math.min(pages.length - 1, last + overscan); i++) wanted.add(i);
|
|
16925
17181
|
for (let i = 0; i < pages.length; i++) {
|
|
16926
17182
|
if (pages[i].mounted && pages[i].el.querySelector("[data-dxw-caret], .dxw-sel")) wanted.add(i);
|
|
16927
17183
|
}
|
|
16928
17184
|
return wanted;
|
|
16929
17185
|
};
|
|
16930
|
-
const syncViewport = (notify, force = false) => {
|
|
17186
|
+
const syncViewport = (notify, force = false, overscan = 2) => {
|
|
16931
17187
|
if (!virtualized) return;
|
|
16932
|
-
const wanted = wantedPages();
|
|
17188
|
+
const wanted = wantedPages(overscan);
|
|
16933
17189
|
let changed = false;
|
|
16934
17190
|
for (const i of wanted) {
|
|
16935
17191
|
if (pages[i].mounted) continue;
|
|
@@ -16944,14 +17200,30 @@ function renderToDom(doc, layout, container, options = {}, prev) {
|
|
|
16944
17200
|
}
|
|
16945
17201
|
if (!changed && !force) return;
|
|
16946
17202
|
refreshBindings();
|
|
16947
|
-
redrawComments();
|
|
17203
|
+
if (drawComments || force) redrawComments();
|
|
16948
17204
|
if (notify) options.onViewportChange?.();
|
|
16949
17205
|
};
|
|
17206
|
+
let settleTimer;
|
|
17207
|
+
let syncedScrollTop = container.scrollTop;
|
|
17208
|
+
let pendingOverscan = 2;
|
|
16950
17209
|
const scheduleViewport = () => {
|
|
17210
|
+
const fast = Math.abs(container.scrollTop - syncedScrollTop) > Math.max(container.clientHeight, 1) * 2;
|
|
17211
|
+
if (fast) {
|
|
17212
|
+
pendingOverscan = 0;
|
|
17213
|
+
if (settleTimer !== void 0) clearTimeout(settleTimer);
|
|
17214
|
+
settleTimer = setTimeout(() => {
|
|
17215
|
+
settleTimer = void 0;
|
|
17216
|
+
syncedScrollTop = container.scrollTop;
|
|
17217
|
+
syncViewport(true);
|
|
17218
|
+
}, 80);
|
|
17219
|
+
}
|
|
16951
17220
|
if (frame) return;
|
|
16952
17221
|
frame = requestAnimationFrame(() => {
|
|
16953
17222
|
frame = 0;
|
|
16954
|
-
|
|
17223
|
+
const overscan = pendingOverscan;
|
|
17224
|
+
pendingOverscan = 2;
|
|
17225
|
+
syncedScrollTop = container.scrollTop;
|
|
17226
|
+
syncViewport(true, false, overscan);
|
|
16955
17227
|
});
|
|
16956
17228
|
};
|
|
16957
17229
|
const stopVirtualizer = () => {
|
|
@@ -16960,6 +17232,8 @@ function renderToDom(doc, layout, container, options = {}, prev) {
|
|
|
16960
17232
|
window.removeEventListener("resize", scheduleViewport);
|
|
16961
17233
|
if (frame) cancelAnimationFrame(frame);
|
|
16962
17234
|
frame = 0;
|
|
17235
|
+
if (settleTimer !== void 0) clearTimeout(settleTimer);
|
|
17236
|
+
settleTimer = void 0;
|
|
16963
17237
|
};
|
|
16964
17238
|
handle = {
|
|
16965
17239
|
root,
|
|
@@ -18475,6 +18749,10 @@ function mergeParagraphBackward(doc, pEl) {
|
|
|
18475
18749
|
if (idx <= 0) return false;
|
|
18476
18750
|
const prev = parent.children[idx - 1];
|
|
18477
18751
|
if (localName(prev.name) !== "p") return false;
|
|
18752
|
+
const finishMerge = (survivor) => {
|
|
18753
|
+
if (!doc.reparseDirectBodyParagraphMerge(prev, pEl, survivor)) doc.refresh();
|
|
18754
|
+
return true;
|
|
18755
|
+
};
|
|
18478
18756
|
const visible = [];
|
|
18479
18757
|
const collect = (el16) => {
|
|
18480
18758
|
for (const c of el16.children) {
|
|
@@ -18492,6 +18770,7 @@ function mergeParagraphBackward(doc, pEl) {
|
|
|
18492
18770
|
if (type === "page" || type === "column") {
|
|
18493
18771
|
if (visible.length === 1) {
|
|
18494
18772
|
parent.children.splice(idx - 1, 1);
|
|
18773
|
+
return finishMerge(pEl);
|
|
18495
18774
|
} else {
|
|
18496
18775
|
last.parent.children.splice(last.parent.children.indexOf(last.el), 1);
|
|
18497
18776
|
}
|
|
@@ -18501,14 +18780,12 @@ function mergeParagraphBackward(doc, pEl) {
|
|
|
18501
18780
|
}
|
|
18502
18781
|
if (visible.length === 0) {
|
|
18503
18782
|
parent.children.splice(idx - 1, 1);
|
|
18504
|
-
|
|
18505
|
-
return true;
|
|
18783
|
+
return finishMerge(pEl);
|
|
18506
18784
|
}
|
|
18507
18785
|
const moved = pEl.children.filter((c) => localName(c.name) !== "pPr");
|
|
18508
18786
|
prev.children.push(...moved);
|
|
18509
18787
|
parent.children.splice(idx, 1);
|
|
18510
|
-
|
|
18511
|
-
return true;
|
|
18788
|
+
return finishMerge(prev);
|
|
18512
18789
|
}
|
|
18513
18790
|
function firstTextOf(pEl) {
|
|
18514
18791
|
const walk2 = (el16) => {
|
|
@@ -20538,7 +20815,7 @@ function setDrawingWordArtText(doc, drawing, text) {
|
|
|
20538
20815
|
doc.refresh();
|
|
20539
20816
|
return true;
|
|
20540
20817
|
}
|
|
20541
|
-
function insertInkAt(doc, caretT, points, color = "#202124", widthPx = 2, opacity = 1) {
|
|
20818
|
+
function insertInkAt(doc, caretT, points, color = "#202124", widthPx = 2, opacity = 1, refreshModel = true) {
|
|
20542
20819
|
if (points.length < 2) return null;
|
|
20543
20820
|
const caretRun = doc.findParentOf(caretT);
|
|
20544
20821
|
const parent = caretRun && doc.findParentOf(caretRun);
|
|
@@ -20615,7 +20892,7 @@ function insertInkAt(doc, caretT, points, color = "#202124", widthPx = 2, opacit
|
|
|
20615
20892
|
])
|
|
20616
20893
|
]);
|
|
20617
20894
|
parent.children.splice(parent.children.indexOf(caretRun) + 1, 0, el6(`${w}r`, {}, [drawing]));
|
|
20618
|
-
doc.refresh();
|
|
20895
|
+
if (refreshModel) doc.refresh();
|
|
20619
20896
|
return drawing;
|
|
20620
20897
|
}
|
|
20621
20898
|
|
|
@@ -21651,7 +21928,11 @@ var _DocxEditor = class _DocxEditor {
|
|
|
21651
21928
|
this.selection = null;
|
|
21652
21929
|
this.selectionRects = [];
|
|
21653
21930
|
this.selectedAll = false;
|
|
21654
|
-
/**
|
|
21931
|
+
/** Header/footer membership for hit-testing and caret movement. Rebuilt only
|
|
21932
|
+
* when refresh() replaces the parsed model; header/footer trees are tiny. */
|
|
21933
|
+
this.regionModelVersion = -1;
|
|
21934
|
+
this.headerFooterElements = /* @__PURE__ */ new WeakSet();
|
|
21935
|
+
/** A click-and-type placement in body whitespace has already recorded the undo
|
|
21655
21936
|
* snapshot that the following text insertion belongs to. */
|
|
21656
21937
|
this.pendingClickTypeCheckpoint = false;
|
|
21657
21938
|
this.clickTypeCheckpointUntil = 0;
|
|
@@ -22009,7 +22290,7 @@ var _DocxEditor = class _DocxEditor {
|
|
|
22009
22290
|
this.hfPage = null;
|
|
22010
22291
|
}
|
|
22011
22292
|
if (caret && region === "body" && !onGlyph && e.detail === 1 && !e.shiftKey) {
|
|
22012
|
-
caret = this.extendCaretBelowFloatingTable(caret, e.clientX, e.clientY) ?? caret;
|
|
22293
|
+
caret = this.extendCaretBelowFloatingTable(caret, e.clientX, e.clientY) ?? this.extendCaretIntoBodyWhitespace(caret, e.clientX, e.clientY) ?? caret;
|
|
22013
22294
|
}
|
|
22014
22295
|
if (caret && e.shiftKey) {
|
|
22015
22296
|
const anchor = this.anchorPoint();
|
|
@@ -22270,6 +22551,7 @@ var _DocxEditor = class _DocxEditor {
|
|
|
22270
22551
|
/** Focus the hidden text target (keeps IME working); falls back to the
|
|
22271
22552
|
* container if the textarea is not attached yet. */
|
|
22272
22553
|
focusText() {
|
|
22554
|
+
if (!this.imeEl.isConnected) this.host.container.appendChild(this.imeEl);
|
|
22273
22555
|
if (this.imeEl.isConnected) this.imeEl.focus({ preventScroll: true });
|
|
22274
22556
|
else this.host.container.focus({ preventScroll: true });
|
|
22275
22557
|
}
|
|
@@ -22278,6 +22560,14 @@ var _DocxEditor = class _DocxEditor {
|
|
|
22278
22560
|
this.applyHfChrome();
|
|
22279
22561
|
this.paintSelection();
|
|
22280
22562
|
this.positionCaret();
|
|
22563
|
+
if (this.caret || this.selection) this.focusText();
|
|
22564
|
+
}
|
|
22565
|
+
/** Repaint only state affected by virtualized page mounts. Scrolling keeps
|
|
22566
|
+
* the current focus and skips header/footer mode notifications in body mode. */
|
|
22567
|
+
afterViewportChange() {
|
|
22568
|
+
if (this.inHeaderFooter) this.applyHfChrome();
|
|
22569
|
+
if (this.selection) this.paintSelection();
|
|
22570
|
+
if (this.caret) this.positionCaret();
|
|
22281
22571
|
}
|
|
22282
22572
|
// ---------- owned selection ----------
|
|
22283
22573
|
hasSelection() {
|
|
@@ -23034,6 +23324,12 @@ var _DocxEditor = class _DocxEditor {
|
|
|
23034
23324
|
const page = target.closest?.(".dxw-page");
|
|
23035
23325
|
const surface = page?.firstElementChild;
|
|
23036
23326
|
if (!page || !surface || !surface.contains(target)) return false;
|
|
23327
|
+
const zoom = this.host.zoom ?? 1;
|
|
23328
|
+
const rect = surface.getBoundingClientRect();
|
|
23329
|
+
const localY = (e.clientY - rect.top) / zoom;
|
|
23330
|
+
const bodyTop = parseFloat(page.dataset.bodyTop ?? "0");
|
|
23331
|
+
const bodyBottom = parseFloat(page.dataset.bodyBottom ?? "0");
|
|
23332
|
+
if (localY < bodyTop || localY > bodyBottom) return false;
|
|
23037
23333
|
this.deselectInkGroup();
|
|
23038
23334
|
if (tool.kind === "eraser") return this.startInkEraser(e, page, tool.size);
|
|
23039
23335
|
if (tool.kind === "lasso") return this.startInkLasso(e, page, surface);
|
|
@@ -23043,8 +23339,6 @@ var _DocxEditor = class _DocxEditor {
|
|
|
23043
23339
|
this.deselectImage();
|
|
23044
23340
|
this.deselectWordArt();
|
|
23045
23341
|
this.hideCaret();
|
|
23046
|
-
const zoom = this.host.zoom ?? 1;
|
|
23047
|
-
const rect = surface.getBoundingClientRect();
|
|
23048
23342
|
const pointAt = (clientX, clientY) => ({
|
|
23049
23343
|
x: Math.max(0, Math.min((clientX - rect.left) / zoom, rect.width / zoom)),
|
|
23050
23344
|
y: Math.max(0, Math.min((clientY - rect.top) / zoom, rect.height / zoom))
|
|
@@ -23081,9 +23375,18 @@ var _DocxEditor = class _DocxEditor {
|
|
|
23081
23375
|
if (points.length < 2) return;
|
|
23082
23376
|
const anchor = this.nearestCaret(e.clientX, e.clientY, "body") ?? this.nearestCaret(up.clientX, up.clientY, "body");
|
|
23083
23377
|
if (!anchor) return;
|
|
23378
|
+
const paragraph = paragraphOf(this.host.doc, anchor.t);
|
|
23379
|
+
const dirtyBlock = topLevelBlockOf(this.host.doc, anchor.t) ?? paragraph ?? void 0;
|
|
23084
23380
|
this.host.history?.checkpoint();
|
|
23085
|
-
if (insertInkAt(this.host.doc, anchor.t, points, tool.color, tool.width, tool.kind === "highlighter" ? 0.45 : 1)) {
|
|
23086
|
-
this.host.
|
|
23381
|
+
if (insertInkAt(this.host.doc, anchor.t, points, tool.color, tool.width, tool.kind === "highlighter" ? 0.45 : 1, false)) {
|
|
23382
|
+
const reparsed = paragraph ? this.host.doc.reparseBodyParagraph(paragraph) : null;
|
|
23383
|
+
if (reparsed) {
|
|
23384
|
+
invalidateParagraphSignature(paragraph);
|
|
23385
|
+
this.host.rerender(dirtyBlock, "local", anchor.t);
|
|
23386
|
+
} else {
|
|
23387
|
+
this.host.doc.refresh();
|
|
23388
|
+
this.host.rerender(void 0, "global");
|
|
23389
|
+
}
|
|
23087
23390
|
}
|
|
23088
23391
|
};
|
|
23089
23392
|
document.addEventListener("mousemove", onMove);
|
|
@@ -24518,14 +24821,19 @@ var _DocxEditor = class _DocxEditor {
|
|
|
24518
24821
|
return caretAt(t, 0);
|
|
24519
24822
|
}
|
|
24520
24823
|
regionOf(t) {
|
|
24521
|
-
|
|
24522
|
-
|
|
24523
|
-
|
|
24524
|
-
|
|
24525
|
-
|
|
24824
|
+
if (this.regionModelVersion !== this.host.doc.modelVersion) {
|
|
24825
|
+
this.headerFooterElements = /* @__PURE__ */ new WeakSet();
|
|
24826
|
+
const visit = (element) => {
|
|
24827
|
+
this.headerFooterElements.add(element);
|
|
24828
|
+
for (const child4 of element.children) visit(child4);
|
|
24829
|
+
};
|
|
24830
|
+
for (const root of this.host.doc.revisionRoots()) {
|
|
24831
|
+
const name = localName(root.name);
|
|
24832
|
+
if (name === "hdr" || name === "ftr") visit(root);
|
|
24833
|
+
}
|
|
24834
|
+
this.regionModelVersion = this.host.doc.modelVersion;
|
|
24526
24835
|
}
|
|
24527
|
-
|
|
24528
|
-
return ln === "hdr" || ln === "ftr" ? "hf" : "body";
|
|
24836
|
+
return this.headerFooterElements.has(t) ? "hf" : "body";
|
|
24529
24837
|
}
|
|
24530
24838
|
/**
|
|
24531
24839
|
* Snap to the closest character boundary on the clicked line — makes
|
|
@@ -24689,6 +24997,97 @@ var _DocxEditor = class _DocxEditor {
|
|
|
24689
24997
|
this.host.rerender(void 0, "global");
|
|
24690
24998
|
return caret;
|
|
24691
24999
|
}
|
|
25000
|
+
/** Word-style click-and-type: clicking below the final body line on a page
|
|
25001
|
+
* creates the intervening empty paragraphs so vertical arrows visit every
|
|
25002
|
+
* visible line instead of jumping across synthetic paragraph spacing. */
|
|
25003
|
+
extendCaretIntoBodyWhitespace(caret, x, y) {
|
|
25004
|
+
const handle = this.host.getHandle();
|
|
25005
|
+
const page = document.elementFromPoint(x, y)?.closest(".dxw-page");
|
|
25006
|
+
const surface = page?.firstElementChild;
|
|
25007
|
+
if (!handle || !page || !surface) return null;
|
|
25008
|
+
const rect = surface.getBoundingClientRect();
|
|
25009
|
+
const zoom = this.host.zoom ?? 1;
|
|
25010
|
+
const ly = (y - rect.top) / zoom;
|
|
25011
|
+
const bodyTop = parseFloat(page.dataset.bodyTop ?? "0");
|
|
25012
|
+
const bodyBottom = parseFloat(page.dataset.bodyBottom ?? "0");
|
|
25013
|
+
if (ly < bodyTop || ly > bodyBottom) return null;
|
|
25014
|
+
const paragraph = paragraphOf(this.host.doc, caret.t);
|
|
25015
|
+
const parent = paragraph ? this.host.doc.findParentOf(paragraph) : void 0;
|
|
25016
|
+
if (!paragraph || !parent || localName(parent.name) !== "body") return null;
|
|
25017
|
+
const endText = lastTextOf(paragraph);
|
|
25018
|
+
if (!endText) return null;
|
|
25019
|
+
const binding = (handle.bindingsByText.get(endText) ?? []).filter((candidate) => candidate.el.parentElement === surface && candidate.item.src).sort((a, b) => b.item.lineTop - a.item.lineTop)[0];
|
|
25020
|
+
if (!binding) return null;
|
|
25021
|
+
const lineHeight = Math.max(1, binding.item.lineHeight);
|
|
25022
|
+
if (ly <= binding.item.lineTop + lineHeight / 2) return null;
|
|
25023
|
+
const hasLaterLine = handle.bindings.some(
|
|
25024
|
+
(candidate) => candidate.el.parentElement === surface && candidate.item.src?.t && this.regionOf(candidate.item.src.t) === "body" && candidate.item.lineTop > binding.item.lineTop + lineHeight / 2
|
|
25025
|
+
);
|
|
25026
|
+
if (hasLaterLine) return null;
|
|
25027
|
+
const lineCount = Math.max(1, Math.round((ly - binding.item.lineTop) / lineHeight));
|
|
25028
|
+
this.host.history?.checkpoint();
|
|
25029
|
+
this.caret = {
|
|
25030
|
+
t: endText,
|
|
25031
|
+
run: binding.item.src.run,
|
|
25032
|
+
offset: endText.text.length,
|
|
25033
|
+
bias: endText.text.length > 0 ? "end" : void 0
|
|
25034
|
+
};
|
|
25035
|
+
const split = this.splitParagraphCore();
|
|
25036
|
+
if (!split) return null;
|
|
25037
|
+
const afterSources = [split.after];
|
|
25038
|
+
const w = split.after.name.includes(":") ? split.after.name.slice(0, split.after.name.indexOf(":") + 1) : "";
|
|
25039
|
+
const templatePPr = split.after.children.find((child4) => localName(child4.name) === "pPr");
|
|
25040
|
+
const templateRun = split.after.children.find(
|
|
25041
|
+
(child4) => localName(child4.name) === "r" && child4.children.includes(this.caret.t)
|
|
25042
|
+
);
|
|
25043
|
+
const templateRPr = templateRun?.children.find((child4) => localName(child4.name) === "rPr");
|
|
25044
|
+
let previous = split.after;
|
|
25045
|
+
for (let i = 1; i < lineCount; i++) {
|
|
25046
|
+
if (this.suggesting) markParagraphGlyph(previous, "ins", this.revMeta());
|
|
25047
|
+
const t = {
|
|
25048
|
+
name: this.caret.t.name,
|
|
25049
|
+
attrs: { ...this.caret.t.attrs, "xml:space": "preserve" },
|
|
25050
|
+
children: [],
|
|
25051
|
+
text: ""
|
|
25052
|
+
};
|
|
25053
|
+
const run = {
|
|
25054
|
+
name: templateRun?.name ?? `${w}r`,
|
|
25055
|
+
attrs: { ...templateRun?.attrs ?? {} },
|
|
25056
|
+
children: [...templateRPr ? [cloneXml(templateRPr)] : [], t],
|
|
25057
|
+
text: ""
|
|
25058
|
+
};
|
|
25059
|
+
const paragraph2 = {
|
|
25060
|
+
name: split.after.name,
|
|
25061
|
+
attrs: {},
|
|
25062
|
+
children: [...templatePPr ? [cloneXml(templatePPr)] : [], run],
|
|
25063
|
+
text: ""
|
|
25064
|
+
};
|
|
25065
|
+
const previousIndex = parent.children.indexOf(previous);
|
|
25066
|
+
parent.children.splice(previousIndex + 1, 0, paragraph2);
|
|
25067
|
+
afterSources.push(paragraph2);
|
|
25068
|
+
previous = paragraph2;
|
|
25069
|
+
this.caret = { t, run: caret.run, offset: 0 };
|
|
25070
|
+
}
|
|
25071
|
+
const reparsed = this.host.doc.reparseDirectBodyParagraphSplits(split.before, afterSources);
|
|
25072
|
+
if (reparsed) {
|
|
25073
|
+
for (const child4 of reparsed[reparsed.length - 1].children) {
|
|
25074
|
+
const runs = child4.type === "run" ? [child4] : child4.runs;
|
|
25075
|
+
const run = runs.find(
|
|
25076
|
+
(candidate) => candidate.content.some((content) => content.kind === "text" && content.srcT === this.caret.t)
|
|
25077
|
+
);
|
|
25078
|
+
if (run) {
|
|
25079
|
+
this.caret.run = run;
|
|
25080
|
+
break;
|
|
25081
|
+
}
|
|
25082
|
+
}
|
|
25083
|
+
invalidateParagraphSignature(split.before);
|
|
25084
|
+
for (const source of afterSources) invalidateParagraphSignature(source);
|
|
25085
|
+
}
|
|
25086
|
+
this.pendingClickTypeCheckpoint = true;
|
|
25087
|
+
this.commit(false, "local", !!reparsed);
|
|
25088
|
+
this.focusText();
|
|
25089
|
+
return this.caret;
|
|
25090
|
+
}
|
|
24692
25091
|
caretFromPoint(x, y) {
|
|
24693
25092
|
const doc = document;
|
|
24694
25093
|
let node = null;
|
|
@@ -24991,7 +25390,8 @@ var _DocxEditor = class _DocxEditor {
|
|
|
24991
25390
|
if (mergeParagraphBackward(this.host.doc, pEl)) {
|
|
24992
25391
|
const target = junction && paragraphOf(this.host.doc, junction) ? junction : caret.t;
|
|
24993
25392
|
this.caret = { t: target, run: caret.run, offset: target === junction ? target.text.length : 0 };
|
|
24994
|
-
this.
|
|
25393
|
+
invalidateParagraphSignature(paragraphOf(this.host.doc, target) ?? pEl);
|
|
25394
|
+
this.commit(false, "local", true);
|
|
24995
25395
|
}
|
|
24996
25396
|
return;
|
|
24997
25397
|
}
|
|
@@ -25011,7 +25411,10 @@ var _DocxEditor = class _DocxEditor {
|
|
|
25011
25411
|
const next = siblingParagraph(this.host.doc, pEl, 1);
|
|
25012
25412
|
if (!next) return;
|
|
25013
25413
|
this.host.history?.checkpoint();
|
|
25014
|
-
if (mergeParagraphBackward(this.host.doc, next))
|
|
25414
|
+
if (mergeParagraphBackward(this.host.doc, next)) {
|
|
25415
|
+
invalidateParagraphSignature(pEl);
|
|
25416
|
+
this.commit(false, "local", true);
|
|
25417
|
+
}
|
|
25015
25418
|
return;
|
|
25016
25419
|
}
|
|
25017
25420
|
if (!this.stepToNeighbor(1)) return;
|
|
@@ -25241,6 +25644,7 @@ var _DocxEditor = class _DocxEditor {
|
|
|
25241
25644
|
invalidateParagraphSignature(split.after);
|
|
25242
25645
|
}
|
|
25243
25646
|
this.commit(false, "local", !!reparsed);
|
|
25647
|
+
this.focusText();
|
|
25244
25648
|
}
|
|
25245
25649
|
/** Split the paragraph at the caret without history or commit — shared by
|
|
25246
25650
|
* Enter and multi-line paste. */
|
|
@@ -29822,7 +30226,7 @@ function DocxView({
|
|
|
29822
30226
|
comments: showComments,
|
|
29823
30227
|
onDeleteComment,
|
|
29824
30228
|
onReplyComment,
|
|
29825
|
-
onViewportChange: () => editor?.
|
|
30229
|
+
onViewportChange: () => editor?.afterViewportChange()
|
|
29826
30230
|
}, prev ?? void 0);
|
|
29827
30231
|
container.scrollTop = scrollTop;
|
|
29828
30232
|
container.scrollLeft = scrollLeft;
|