wordinweb 0.1.8 → 0.1.10
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 +44 -1
- package/dist/index.d.ts +44 -12
- package/dist/index.js +1742 -286
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -3955,10 +3955,12 @@ function parseRun(r, ctx, field, suppressedObjects) {
|
|
|
3955
3955
|
case "endnoteReference": {
|
|
3956
3956
|
const id = intAttr(el16, "id");
|
|
3957
3957
|
if (id !== void 0) {
|
|
3958
|
+
const customMark = attr(el16, "customMarkFollows");
|
|
3958
3959
|
run.content.push({
|
|
3959
3960
|
kind: "noteRef",
|
|
3960
3961
|
noteType: ln === "footnoteReference" ? "footnote" : "endnote",
|
|
3961
|
-
id
|
|
3962
|
+
id,
|
|
3963
|
+
customMarkFollows: customMark !== void 0 && customMark !== "0" && customMark !== "false" && customMark !== "off"
|
|
3962
3964
|
});
|
|
3963
3965
|
}
|
|
3964
3966
|
break;
|
|
@@ -4361,6 +4363,7 @@ function parseDrawing(drawing, ctx) {
|
|
|
4361
4363
|
const rot = intAttr(xfrm, "rot");
|
|
4362
4364
|
const lnEl = child(spPr, "ln");
|
|
4363
4365
|
const strokeColor = lnEl && !child(lnEl, "noFill") ? fillColorOf(lnEl) : void 0;
|
|
4366
|
+
const fill = child(spPr, "noFill") ? void 0 : fillColorOf(spPr) ?? styleFillOf(textboxEl);
|
|
4364
4367
|
const bodyPr = child(textboxEl, "bodyPr");
|
|
4365
4368
|
const insetOf = (name, dflt) => {
|
|
4366
4369
|
const v = bodyPr ? intAttr(bodyPr, name) : void 0;
|
|
@@ -4404,7 +4407,7 @@ function parseDrawing(drawing, ctx) {
|
|
|
4404
4407
|
vAlign: vAlignOf(posV),
|
|
4405
4408
|
blocks: txbxContent ? parseBlocks(txbxContent, ctx) : [],
|
|
4406
4409
|
...textboxChainId !== void 0 ? { chainId: textboxChainId, chainSeq: textboxChainSeq ?? 0 } : {},
|
|
4407
|
-
...
|
|
4410
|
+
...fill ? { fill } : {},
|
|
4408
4411
|
...strokeColor ? { stroke: { color: strokeColor, weight: Math.max(emuToPx(intAttr(lnEl, "w") ?? 0), 0.75) } } : {},
|
|
4409
4412
|
textAnchor: anchorAttr === "ctr" ? "middle" : anchorAttr === "b" ? "bottom" : anchorAttr === "t" ? "top" : void 0,
|
|
4410
4413
|
insets: {
|
|
@@ -6111,23 +6114,49 @@ var DocxDocument = class _DocxDocument {
|
|
|
6111
6114
|
}
|
|
6112
6115
|
this._modelVersion++;
|
|
6113
6116
|
}
|
|
6114
|
-
/**
|
|
6115
|
-
*
|
|
6116
|
-
*
|
|
6117
|
-
*
|
|
6118
|
-
* containers, revisions, bookmarks, and section breaks use refresh().
|
|
6119
|
-
*/
|
|
6117
|
+
/** Reparse the two sibling body-story paragraphs created by Enter without
|
|
6118
|
+
* rebuilding the complete document model. Paragraphs nested in table cells
|
|
6119
|
+
* are included because legal documents spend most of their body inside
|
|
6120
|
+
* tables; revisions, bookmarks, fields, and section breaks use refresh(). */
|
|
6120
6121
|
reparseDirectBodyParagraphSplit(beforeSource, afterSource) {
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6122
|
+
const parsed = this.reparseDirectBodyParagraphSplits(beforeSource, [afterSource]);
|
|
6123
|
+
return parsed ? { before: parsed[0], after: parsed[1] } : null;
|
|
6124
|
+
}
|
|
6125
|
+
/** Reparse a body paragraph plus several new siblings created by
|
|
6126
|
+
* click-and-type without rebuilding the complete document model. */
|
|
6127
|
+
reparseDirectBodyParagraphSplits(beforeSource, afterSources) {
|
|
6128
|
+
if (afterSources.length === 0) return null;
|
|
6129
|
+
const parent = this.findParentOf(beforeSource);
|
|
6130
|
+
if (!parent) return null;
|
|
6131
|
+
const beforeIndex = parent.children.indexOf(beforeSource);
|
|
6132
|
+
if (beforeIndex < 0 || afterSources.some((source, i) => parent.children[beforeIndex + i + 1] !== source)) {
|
|
6133
|
+
return null;
|
|
6134
|
+
}
|
|
6135
|
+
if (localName(beforeSource.name) !== "p" || afterSources.some((source) => localName(source.name) !== "p")) {
|
|
6136
|
+
return null;
|
|
6137
|
+
}
|
|
6138
|
+
const findBlockList = (blocks2) => {
|
|
6139
|
+
const index = blocks2.findIndex((block) => block.type === "paragraph" && block.src === beforeSource);
|
|
6140
|
+
if (index >= 0) return { blocks: blocks2, index };
|
|
6141
|
+
for (const block of blocks2) {
|
|
6142
|
+
if (block.type !== "table") continue;
|
|
6143
|
+
for (const row of block.rows) {
|
|
6144
|
+
for (const cell of row.cells) {
|
|
6145
|
+
const found = findBlockList(cell.blocks);
|
|
6146
|
+
if (found) return found;
|
|
6147
|
+
}
|
|
6148
|
+
}
|
|
6149
|
+
}
|
|
6150
|
+
return null;
|
|
6151
|
+
};
|
|
6152
|
+
let location = null;
|
|
6153
|
+
for (const section of this.sections) {
|
|
6154
|
+
location = findBlockList(section.blocks);
|
|
6155
|
+
if (location) break;
|
|
6156
|
+
}
|
|
6157
|
+
if (!location) return null;
|
|
6158
|
+
const { blocks, index: blockIndex } = location;
|
|
6159
|
+
if (afterSources.some((source) => blocks.some((block) => block.src === source))) return null;
|
|
6131
6160
|
const old = blocks[blockIndex];
|
|
6132
6161
|
if (old.type !== "paragraph" || old.sectionBreak) return null;
|
|
6133
6162
|
const unsafe = (element) => {
|
|
@@ -6135,7 +6164,7 @@ var DocxDocument = class _DocxDocument {
|
|
|
6135
6164
|
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
6165
|
return element.children.some(unsafe);
|
|
6137
6166
|
};
|
|
6138
|
-
if (unsafe(beforeSource) || unsafe
|
|
6167
|
+
if (unsafe(beforeSource) || afterSources.some(unsafe)) return null;
|
|
6139
6168
|
const readPart = (part) => this.readXmlOptional(part);
|
|
6140
6169
|
const ctx = {
|
|
6141
6170
|
...this.ctxBase,
|
|
@@ -6143,11 +6172,103 @@ var DocxDocument = class _DocxDocument {
|
|
|
6143
6172
|
readPart,
|
|
6144
6173
|
independentTextboxStories: true
|
|
6145
6174
|
};
|
|
6146
|
-
const
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6175
|
+
const parsed = [beforeSource, ...afterSources].map((source) => parseParagraph(source, ctx));
|
|
6176
|
+
if (parsed.some((paragraph) => paragraph.revisionHidden || paragraph.sectionBreak)) return null;
|
|
6177
|
+
blocks.splice(blockIndex, 1, ...parsed);
|
|
6178
|
+
return parsed;
|
|
6179
|
+
}
|
|
6180
|
+
/** Reparse one retained body-story paragraph after a structural edit that
|
|
6181
|
+
* leaves its surrounding block list unchanged, such as inserting ink. */
|
|
6182
|
+
reparseBodyParagraph(source) {
|
|
6183
|
+
if (localName(source.name) !== "p") return null;
|
|
6184
|
+
const findBlockList = (blocks) => {
|
|
6185
|
+
const index = blocks.findIndex((block) => block.type === "paragraph" && block.src === source);
|
|
6186
|
+
if (index >= 0) return { blocks, index };
|
|
6187
|
+
for (const block of blocks) {
|
|
6188
|
+
if (block.type !== "table") continue;
|
|
6189
|
+
for (const row of block.rows) {
|
|
6190
|
+
for (const cell of row.cells) {
|
|
6191
|
+
const found = findBlockList(cell.blocks);
|
|
6192
|
+
if (found) return found;
|
|
6193
|
+
}
|
|
6194
|
+
}
|
|
6195
|
+
}
|
|
6196
|
+
return null;
|
|
6197
|
+
};
|
|
6198
|
+
let location = null;
|
|
6199
|
+
for (const section of this.sections) {
|
|
6200
|
+
location = findBlockList(section.blocks);
|
|
6201
|
+
if (location) break;
|
|
6202
|
+
}
|
|
6203
|
+
if (!location) return null;
|
|
6204
|
+
const old = location.blocks[location.index];
|
|
6205
|
+
if (old.type !== "paragraph" || old.sectionBreak) return null;
|
|
6206
|
+
const unsafe = (element) => {
|
|
6207
|
+
const name = localName(element.name);
|
|
6208
|
+
if (name === "sectPr" || name === "bookmarkStart" || name === "bookmarkEnd") return true;
|
|
6209
|
+
return element.children.some(unsafe);
|
|
6210
|
+
};
|
|
6211
|
+
if (unsafe(source)) return null;
|
|
6212
|
+
const paragraph = parseParagraph(source, {
|
|
6213
|
+
...this.ctxBase,
|
|
6214
|
+
rels: this.documentRels,
|
|
6215
|
+
readPart: (part) => this.readXmlOptional(part),
|
|
6216
|
+
independentTextboxStories: true
|
|
6217
|
+
});
|
|
6218
|
+
if (paragraph.revisionHidden || paragraph.sectionBreak) return null;
|
|
6219
|
+
location.blocks[location.index] = paragraph;
|
|
6220
|
+
return paragraph;
|
|
6221
|
+
}
|
|
6222
|
+
/** Reparse two sibling body-story paragraphs after Backspace/Delete merged
|
|
6223
|
+
* their XML into one. Keeps the parsed model generation stable so long
|
|
6224
|
+
* documents can use incremental layout instead of repaginating in full. */
|
|
6225
|
+
reparseDirectBodyParagraphMerge(beforeSource, afterSource, survivorSource) {
|
|
6226
|
+
if (survivorSource !== beforeSource && survivorSource !== afterSource) return null;
|
|
6227
|
+
if (localName(beforeSource.name) !== "p" || localName(afterSource.name) !== "p") return null;
|
|
6228
|
+
const parent = this.findParentOf(survivorSource);
|
|
6229
|
+
if (!parent || parent.children.includes(survivorSource === beforeSource ? afterSource : beforeSource)) return null;
|
|
6230
|
+
const findBlockList = (blocks2) => {
|
|
6231
|
+
const index2 = blocks2.findIndex(
|
|
6232
|
+
(block, i) => block.type === "paragraph" && block.src === beforeSource && blocks2[i + 1]?.type === "paragraph" && blocks2[i + 1].src === afterSource
|
|
6233
|
+
);
|
|
6234
|
+
if (index2 >= 0) return { blocks: blocks2, index: index2 };
|
|
6235
|
+
for (const block of blocks2) {
|
|
6236
|
+
if (block.type !== "table") continue;
|
|
6237
|
+
for (const row of block.rows) {
|
|
6238
|
+
for (const cell of row.cells) {
|
|
6239
|
+
const found = findBlockList(cell.blocks);
|
|
6240
|
+
if (found) return found;
|
|
6241
|
+
}
|
|
6242
|
+
}
|
|
6243
|
+
}
|
|
6244
|
+
return null;
|
|
6245
|
+
};
|
|
6246
|
+
let location = null;
|
|
6247
|
+
for (const section of this.sections) {
|
|
6248
|
+
location = findBlockList(section.blocks);
|
|
6249
|
+
if (location) break;
|
|
6250
|
+
}
|
|
6251
|
+
if (!location) return null;
|
|
6252
|
+
const { blocks, index } = location;
|
|
6253
|
+
const before = blocks[index];
|
|
6254
|
+
const after = blocks[index + 1];
|
|
6255
|
+
if (before.type !== "paragraph" || after.type !== "paragraph" || before.sectionBreak || after.sectionBreak) return null;
|
|
6256
|
+
const unsafe = (element) => {
|
|
6257
|
+
const name = localName(element.name);
|
|
6258
|
+
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;
|
|
6259
|
+
return element.children.some(unsafe);
|
|
6260
|
+
};
|
|
6261
|
+
if (unsafe(beforeSource) || unsafe(afterSource)) return null;
|
|
6262
|
+
const readPart = (part) => this.readXmlOptional(part);
|
|
6263
|
+
const merged = parseParagraph(survivorSource, {
|
|
6264
|
+
...this.ctxBase,
|
|
6265
|
+
rels: this.documentRels,
|
|
6266
|
+
readPart,
|
|
6267
|
+
independentTextboxStories: true
|
|
6268
|
+
});
|
|
6269
|
+
if (merged.revisionHidden || merged.sectionBreak) return null;
|
|
6270
|
+
blocks.splice(index, 2, merged);
|
|
6271
|
+
return merged;
|
|
6151
6272
|
}
|
|
6152
6273
|
deriveComments() {
|
|
6153
6274
|
const out = [];
|
|
@@ -7974,7 +8095,10 @@ var WORD_FONT_METRICS = {
|
|
|
7974
8095
|
// baselines 118.80 + n x 20.00; first attempt baked the multiple into the
|
|
7975
8096
|
// profile and over-pitched every line by 1.08x).
|
|
7976
8097
|
mangal: { asc: 1.245, desc: 0.4399, gap: 0 },
|
|
7977
|
-
latha: { asc: 0.9266, desc: 0.3369, gap: 0 }
|
|
8098
|
+
latha: { asc: 0.9266, desc: 0.3369, gap: 0 },
|
|
8099
|
+
// Word substitutes Lao text to DokChampa. Its hhea box is 2850/-1117 at
|
|
8100
|
+
// 2048 UPEM; this is also the line profile Word uses in the reference PDF.
|
|
8101
|
+
"noto sans lao looped": { asc: 1.391602, desc: 0.54541, gap: 0 }
|
|
7978
8102
|
};
|
|
7979
8103
|
var QUARTER_PT_PX = 1 / 3;
|
|
7980
8104
|
function quantizeQuarterPt(px) {
|
|
@@ -9066,6 +9190,7 @@ var JUSTIFY_MAX_COMPRESS = 0.25;
|
|
|
9066
9190
|
var JUSTIFY_STRETCH_FACTOR = 0.5;
|
|
9067
9191
|
var TAMIL_GLYPH_SCALE = 0.735;
|
|
9068
9192
|
var TAMIL_BASELINE_DY_EM = 0.136;
|
|
9193
|
+
var LAO_GLYPH_SCALE = 1.048;
|
|
9069
9194
|
var KASHIDA_LOW_EM = 0;
|
|
9070
9195
|
var KASHIDA_MEDIUM_EM = 0.032;
|
|
9071
9196
|
var KASHIDA_HIGH_EM = 0.04;
|
|
@@ -9420,6 +9545,7 @@ function breakParagraphImpl(doc, measurer, para, contentWidth, fields, numbering
|
|
|
9420
9545
|
href: atom.href,
|
|
9421
9546
|
src: atom.src ? { ...atom.src, offset: atom.src.offset + sliceOff } : void 0,
|
|
9422
9547
|
metricsFont: atom.metricsFont,
|
|
9548
|
+
metricsStrut: atom.metricsStrut,
|
|
9423
9549
|
rtl: atom.rtl,
|
|
9424
9550
|
rtlLevel: levelOf(atom.rtl)
|
|
9425
9551
|
});
|
|
@@ -9543,6 +9669,44 @@ function breakParagraphImpl(doc, measurer, para, contentWidth, fields, numbering
|
|
|
9543
9669
|
if (found) target = stop.pos - pre;
|
|
9544
9670
|
}
|
|
9545
9671
|
}
|
|
9672
|
+
if (doc.compatibilityMode < 15 && stop.align === "left" && !bidiPara && curLineWidth > 0) {
|
|
9673
|
+
let nextAtom = ai + 1;
|
|
9674
|
+
let probeX = Math.max(target, x + 2);
|
|
9675
|
+
while (atoms[nextAtom]?.kind === "tab") {
|
|
9676
|
+
let probeStop = nextTabStop(
|
|
9677
|
+
probeX + offset,
|
|
9678
|
+
props.tabs,
|
|
9679
|
+
contentWidth - indentRight,
|
|
9680
|
+
doc.defaultTabStop
|
|
9681
|
+
);
|
|
9682
|
+
if (opts?.inTableCell) {
|
|
9683
|
+
let guard = 0;
|
|
9684
|
+
while (probeStop.align === "decimal" && guard++ < 8) {
|
|
9685
|
+
probeStop = nextTabStop(
|
|
9686
|
+
probeStop.pos,
|
|
9687
|
+
props.tabs,
|
|
9688
|
+
contentWidth - indentRight,
|
|
9689
|
+
doc.defaultTabStop
|
|
9690
|
+
);
|
|
9691
|
+
}
|
|
9692
|
+
}
|
|
9693
|
+
if (probeStop.align !== "left") break;
|
|
9694
|
+
probeX = Math.max(probeStop.pos - offset, probeX + 2);
|
|
9695
|
+
nextAtom++;
|
|
9696
|
+
}
|
|
9697
|
+
let firstWordWidth = 0;
|
|
9698
|
+
for (let j = nextAtom; j < atoms.length; j++) {
|
|
9699
|
+
const a = atoms[j];
|
|
9700
|
+
if (a.kind !== "frag") break;
|
|
9701
|
+
firstWordWidth += a.width;
|
|
9702
|
+
}
|
|
9703
|
+
const lineEnd2 = lineStartX(lineIndex) + availFor(lineIndex);
|
|
9704
|
+
if (firstWordWidth > 0 && probeX + firstWordWidth > lineEnd2 + 0.01) {
|
|
9705
|
+
flush(false, false);
|
|
9706
|
+
ai--;
|
|
9707
|
+
continue;
|
|
9708
|
+
}
|
|
9709
|
+
}
|
|
9546
9710
|
const aligned = (stop.align === "right" || stop.align === "decimal") && !bidiPara;
|
|
9547
9711
|
if (aligned && curLineWidth > 0 && x > target + 0.75) {
|
|
9548
9712
|
flush(false, false);
|
|
@@ -9808,7 +9972,7 @@ function breakParagraphImpl(doc, measurer, para, contentWidth, fields, numbering
|
|
|
9808
9972
|
}
|
|
9809
9973
|
const padL = bdrPad && (!sameBdrAtom(atoms[ai - 1], atom) || curLineWidth === 0) ? bdrPad : 0;
|
|
9810
9974
|
x += padL;
|
|
9811
|
-
cur.push({ x, width: atom.width, text: atom.text, props: atom.props, font: atom.font, href: atom.href, src: atom.src, noteId: atom.noteId, metricsFont: atom.metricsFont, breakAfter: atom.breakAfter, pageRef: atom.pageRef, rtl: atom.rtl, rtlLevel: levelOf(atom.rtl), ruby: atom.ruby });
|
|
9975
|
+
cur.push({ x, width: atom.width, text: atom.text, props: atom.props, font: atom.font, href: atom.href, src: atom.src, noteId: atom.noteId, metricsFont: atom.metricsFont, metricsStrut: atom.metricsStrut, breakAfter: atom.breakAfter, pageRef: atom.pageRef, rtl: atom.rtl, rtlLevel: levelOf(atom.rtl), ruby: atom.ruby });
|
|
9812
9976
|
curLineWidth += padL + atom.width + bdrPadR;
|
|
9813
9977
|
x += atom.width + bdrPadR;
|
|
9814
9978
|
if (atom.text.trim().length > 0) prevContentCJK = fragIsCJK;
|
|
@@ -9965,6 +10129,7 @@ function finishLine(spans, width, props, measurer, fallbackFamily, para, doc, is
|
|
|
9965
10129
|
let maxBorderedAscent = 0;
|
|
9966
10130
|
let maxBorderedDescent = 0;
|
|
9967
10131
|
let tallestTextIsEa = false;
|
|
10132
|
+
let metricsStrutHeight = 0;
|
|
9968
10133
|
const consider = (font, imageHeight, objRaise = 0, descShift = 0) => {
|
|
9969
10134
|
if (imageHeight !== void 0) {
|
|
9970
10135
|
maxAscent = Math.max(maxAscent, imageHeight + objRaise);
|
|
@@ -10005,7 +10170,7 @@ function finishLine(spans, width, props, measurer, fallbackFamily, para, doc, is
|
|
|
10005
10170
|
};
|
|
10006
10171
|
let metricSpans = spans.filter((s) => !(s.text === " " && !s.leader));
|
|
10007
10172
|
const solidSpans = metricSpans.filter(
|
|
10008
|
-
(s) => s.image || s.drawing || s.math || s.leader || s.text === void 0 || !/^[ \t]*$/.test(s.text)
|
|
10173
|
+
(s) => s.metricsStrut || s.image || s.drawing || s.math || s.leader || s.text === void 0 || !/^[ \t]*$/.test(s.text)
|
|
10009
10174
|
);
|
|
10010
10175
|
if (solidSpans.length > 0) metricSpans = solidSpans;
|
|
10011
10176
|
if (metricSpans.some((s) => s.numLabel) && metricSpans.some((s) => !s.numLabel)) {
|
|
@@ -10038,7 +10203,13 @@ function finishLine(spans, width, props, measurer, fallbackFamily, para, doc, is
|
|
|
10038
10203
|
const lineHasObject = metricSpans.some((s) => s.image || s.drawing);
|
|
10039
10204
|
for (const s of metricSpans) {
|
|
10040
10205
|
let textMetrics;
|
|
10041
|
-
if (s.
|
|
10206
|
+
if (s.metricsStrut) {
|
|
10207
|
+
metricsStrutHeight = Math.max(
|
|
10208
|
+
metricsStrutHeight,
|
|
10209
|
+
measurer.metrics(s.metricsFont ?? s.font).lineHeight
|
|
10210
|
+
);
|
|
10211
|
+
consider(s.metricsFont ?? s.font);
|
|
10212
|
+
} else if (s.image || s.drawing) {
|
|
10042
10213
|
const objectMetrics = measurer.metrics(s.metricsFont ?? s.font);
|
|
10043
10214
|
const objectHeight = s.image?.height ?? s.drawing.height;
|
|
10044
10215
|
const objRaise = s.props.raise ?? 0;
|
|
@@ -10093,6 +10264,14 @@ function finishLine(spans, width, props, measurer, fallbackFamily, para, doc, is
|
|
|
10093
10264
|
const commonLower = metricSpans.length > 0 && metricSpans.every(
|
|
10094
10265
|
(s) => !s.image && !s.drawing && !s.math && (s.props.raise ?? 0) < 0
|
|
10095
10266
|
) ? Math.min(...metricSpans.map((s) => -s.props.raise)) : 0;
|
|
10267
|
+
if (metricsStrutHeight > 0) {
|
|
10268
|
+
for (const s of spans) {
|
|
10269
|
+
if (s.metricsStrut || s.image || s.drawing || s.math) continue;
|
|
10270
|
+
const spanHeight = measurer.metrics(s.font).lineHeight;
|
|
10271
|
+
const paintDY = Math.max(0, (metricsStrutHeight - spanHeight) / 2);
|
|
10272
|
+
if (paintDY > 0) s.font = { ...s.font, paintDY: (s.font.paintDY ?? 0) + paintDY };
|
|
10273
|
+
}
|
|
10274
|
+
}
|
|
10096
10275
|
const natural = Math.max(maxNatural, maxAscent + maxDescent, minLineHeight ?? 0);
|
|
10097
10276
|
let height = natural;
|
|
10098
10277
|
let baselineH;
|
|
@@ -10253,11 +10432,22 @@ function resolveBidiRtl(text) {
|
|
|
10253
10432
|
function buildAtoms(doc, para, measurer, fields, fallbackFamily, gridPitch) {
|
|
10254
10433
|
const atoms = [];
|
|
10255
10434
|
const anchors = [];
|
|
10435
|
+
const stylelessOleParagraph = doc.styles.defaultRPr.font === void 0 && doc.styles.defaultRPr.size === void 0 && para.children.some((child4) => {
|
|
10436
|
+
const runs = child4.type === "run" ? [child4] : child4.runs;
|
|
10437
|
+
return runs.some(
|
|
10438
|
+
(run) => run.content.some(
|
|
10439
|
+
(content) => content.kind === "image" && content.embeddedObject !== void 0
|
|
10440
|
+
)
|
|
10441
|
+
);
|
|
10442
|
+
});
|
|
10256
10443
|
const bidiPara = doc.effectiveParaProps(para).bidi === true;
|
|
10257
10444
|
const kashidaKind = doc.effectiveParaProps(para).justifyKind;
|
|
10258
10445
|
const kashidaEm = kashidaKind === "highKashida" ? KASHIDA_HIGH_EM : kashidaKind === "mediumKashida" ? KASHIDA_MEDIUM_EM : kashidaKind === "lowKashida" ? KASHIDA_LOW_EM : 0;
|
|
10259
10446
|
const pushRun = (run, href) => {
|
|
10260
|
-
|
|
10447
|
+
let baseProps = doc.effectiveRunProps(para, run.props);
|
|
10448
|
+
if (stylelessOleParagraph && baseProps.size === void 0) {
|
|
10449
|
+
baseProps = { ...baseProps, size: 16 };
|
|
10450
|
+
}
|
|
10261
10451
|
if (baseProps.vanish) return;
|
|
10262
10452
|
const font = fontOf(baseProps, fallbackFamily);
|
|
10263
10453
|
let props = kashidaEm > 0 && baseProps.rtl ? { ...baseProps, letterSpacing: (baseProps.letterSpacing ?? 0) + kashidaEm * font.size } : baseProps;
|
|
@@ -10327,6 +10517,20 @@ function buildAtoms(doc, para, measurer, fields, fallbackFamily, gridPitch) {
|
|
|
10327
10517
|
});
|
|
10328
10518
|
break;
|
|
10329
10519
|
}
|
|
10520
|
+
if (!text && /^\s*SEQ\b/i.test(content.instruction) && /\\h(\s|$)/i.test(content.instruction)) {
|
|
10521
|
+
atoms.push({
|
|
10522
|
+
kind: "frag",
|
|
10523
|
+
text: "",
|
|
10524
|
+
props,
|
|
10525
|
+
font,
|
|
10526
|
+
width: 0,
|
|
10527
|
+
href,
|
|
10528
|
+
src: { run, t: null, offset: 0 },
|
|
10529
|
+
metricsFont: vertMetricsFont,
|
|
10530
|
+
metricsStrut: true
|
|
10531
|
+
});
|
|
10532
|
+
break;
|
|
10533
|
+
}
|
|
10330
10534
|
if (text) pushStyled(displayText(text, props), props, font, href, { run, t: null, offset: 0 }, vertMetricsFont);
|
|
10331
10535
|
break;
|
|
10332
10536
|
}
|
|
@@ -10371,7 +10575,7 @@ function buildAtoms(doc, para, measurer, fields, fallbackFamily, gridPitch) {
|
|
|
10371
10575
|
break;
|
|
10372
10576
|
}
|
|
10373
10577
|
case "noteRef": {
|
|
10374
|
-
const text = content.self ? fields.selfNoteMark?.() ?? "" : fields.noteMark?.(content.noteType, content.id) ?? "";
|
|
10578
|
+
const text = content.self ? fields.selfNoteMark?.() ?? "" : content.customMarkFollows ? "" : fields.noteMark?.(content.noteType, content.id) ?? "";
|
|
10375
10579
|
if (!text) break;
|
|
10376
10580
|
const markProps = props.verticalAlign ? props : { ...props, verticalAlign: "superscript" };
|
|
10377
10581
|
const markFont = fontOf(markProps, fallbackFamily);
|
|
@@ -10427,6 +10631,7 @@ function buildAtoms(doc, para, measurer, fields, fallbackFamily, gridPitch) {
|
|
|
10427
10631
|
const hasLao = /[-]/.test(text);
|
|
10428
10632
|
const indicFace = hasDeva && !hasTamil && !hasLao ? "Mangal" : hasTamil && !hasDeva && !hasLao ? "Latha" : hasLao && !hasDeva && !hasTamil ? "Noto Sans Lao Looped" : null;
|
|
10429
10633
|
if (indicFace && font.family.toLowerCase() !== indicFace.toLowerCase()) {
|
|
10634
|
+
const scriptProps = indicFace === "Noto Sans Lao Looped" ? { ...props, textScale: (props.textScale ?? 1) * LAO_GLYPH_SCALE } : props;
|
|
10430
10635
|
const indicScale = indicFace === "Latha" ? TAMIL_GLYPH_SCALE : 1;
|
|
10431
10636
|
const indicFont = indicScale === 1 ? { ...font, family: indicFace } : {
|
|
10432
10637
|
...font,
|
|
@@ -10446,7 +10651,7 @@ function buildAtoms(doc, para, measurer, fields, fallbackFamily, gridPitch) {
|
|
|
10446
10651
|
const seg = text.slice(i2, j);
|
|
10447
10652
|
const src = srcBase ? { ...srcBase, offset: srcBase.offset + i2 } : void 0;
|
|
10448
10653
|
if (isSpace) pushText(seg, props, font, href, src, metricsFont);
|
|
10449
|
-
else pushText(seg,
|
|
10654
|
+
else pushText(seg, scriptProps, indicFont, href, src, indicMetrics);
|
|
10450
10655
|
i2 = j;
|
|
10451
10656
|
}
|
|
10452
10657
|
return;
|
|
@@ -10669,8 +10874,8 @@ function resolveField(instruction, cachedResult, ctx, fieldKey) {
|
|
|
10669
10874
|
}
|
|
10670
10875
|
case "SEQ": {
|
|
10671
10876
|
const ident = instr.split(/\s+/)[1];
|
|
10672
|
-
|
|
10673
|
-
return
|
|
10877
|
+
const value = ident && ctx.seq && fieldKey ? ctx.seq(ident, fieldKey, instr) : cachedResult || "";
|
|
10878
|
+
return /\\h(\s|$)/i.test(instr) ? "" : value;
|
|
10674
10879
|
}
|
|
10675
10880
|
case "REF": {
|
|
10676
10881
|
const bookmark = instr.split(/\s+/)[1];
|
|
@@ -10833,6 +11038,7 @@ var __incrStats = {
|
|
|
10833
11038
|
resumePage: -1,
|
|
10834
11039
|
convergedBlock: -1,
|
|
10835
11040
|
convergedPage: -1,
|
|
11041
|
+
pageShift: 0,
|
|
10836
11042
|
blocksLaid: 0,
|
|
10837
11043
|
fallbackReason: ""
|
|
10838
11044
|
};
|
|
@@ -10892,6 +11098,7 @@ var MULTI_COL_NOTE_SEP_RESERVE = 26;
|
|
|
10892
11098
|
var NOTE_SEP_LEN = 192;
|
|
10893
11099
|
var NOTE_SEP_GAP = 4.4;
|
|
10894
11100
|
var ROW_OVERHANG_TOL = 3;
|
|
11101
|
+
var CUSTOM_NOTE_BANNER_OVERHANG = 3;
|
|
10895
11102
|
var CHICAGO = ["*", "\u2020", "\u2021", "\xA7"];
|
|
10896
11103
|
var AUTO_PARA_SPACING_PX = 14 * (96 / 72);
|
|
10897
11104
|
var FRAME_WRAP_HSPACE_PX = 6 * (96 / 72);
|
|
@@ -10933,6 +11140,7 @@ var Engine = class {
|
|
|
10933
11140
|
this.trailingSectionBreakMarkGap = 0;
|
|
10934
11141
|
/** Bookmark name -> formatted display page number (PAGEREF rewrite). */
|
|
10935
11142
|
this.bookmarkPages = /* @__PURE__ */ new Map();
|
|
11143
|
+
this.bookmarkPageIndices = /* @__PURE__ */ new Map();
|
|
10936
11144
|
/** STYLEREF page-awareness: styleIds whose paragraphs a header/footer STYLEREF
|
|
10937
11145
|
* references (null until precomputed; empty set = no STYLEREF, tracking off). */
|
|
10938
11146
|
this.styleRefTrack = null;
|
|
@@ -10998,6 +11206,7 @@ var Engine = class {
|
|
|
10998
11206
|
/** Vertical flow already consumed in the current later-column pre-banner
|
|
10999
11207
|
* slot. It reduces the below-banner capacity by the same amount. */
|
|
11000
11208
|
this.bannerSlotUsed = 0;
|
|
11209
|
+
this.customNoteBannerFit = false;
|
|
11001
11210
|
/** True while a section-level tbRl vertical flow is being laid: paragraphs
|
|
11002
11211
|
* re-establish the vertical grid after embedded Western runs (see
|
|
11003
11212
|
* breakParagraph's verticalGridResync). */
|
|
@@ -11025,6 +11234,8 @@ var Engine = class {
|
|
|
11025
11234
|
this.incrConvergeBlockIdx = -1;
|
|
11026
11235
|
this.incrConvergePageIdx = -1;
|
|
11027
11236
|
this.incrConvergeItemDelta = 0;
|
|
11237
|
+
this.incrConvergePrevPointPageIdx = -1;
|
|
11238
|
+
this.incrPageShift = 0;
|
|
11028
11239
|
/** New block indices are old indices plus this value after a structural
|
|
11029
11240
|
* split, so convergence compares the same semantic suffix boundary. */
|
|
11030
11241
|
this.incrBlockDelta = 0;
|
|
@@ -11113,7 +11324,7 @@ var Engine = class {
|
|
|
11113
11324
|
const contentWidth = page.sp.pageWidth - page.sp.marginLeft - page.sp.marginRight - page.sp.gutter;
|
|
11114
11325
|
const header = this.doc.headers.get(page.headerRel ?? "");
|
|
11115
11326
|
const footer = this.doc.footers.get(page.footerRel ?? "");
|
|
11116
|
-
const headerHeight = this.measureHeaderFooter(header, page, contentWidth, this.pageFieldFrameOverlay(header));
|
|
11327
|
+
const headerHeight = this.measureHeaderFooter(header, page, contentWidth, this.pageFieldFrameOverlay(header), true);
|
|
11117
11328
|
const footerHeight = this.measureHeaderFooter(footer, page, contentWidth, this.pageFieldFrameOverlay(footer));
|
|
11118
11329
|
if (headerHeight !== page.headerHeight || footerHeight !== page.footerHeight) return null;
|
|
11119
11330
|
}
|
|
@@ -11213,6 +11424,7 @@ var Engine = class {
|
|
|
11213
11424
|
if (this.pages.length === 0) {
|
|
11214
11425
|
this.sp = sections[0]?.props ?? {};
|
|
11215
11426
|
}
|
|
11427
|
+
this.applyOpeningFlowOverlap();
|
|
11216
11428
|
this.placeEndnotes();
|
|
11217
11429
|
this.emitFootnoteAreas();
|
|
11218
11430
|
this.emitColumnSeparators();
|
|
@@ -11231,6 +11443,7 @@ var Engine = class {
|
|
|
11231
11443
|
points: this.incrPoints,
|
|
11232
11444
|
pages: this.pages,
|
|
11233
11445
|
bookmarks: this.bookmarkPages,
|
|
11446
|
+
bookmarkPageIndices: this.bookmarkPageIndices,
|
|
11234
11447
|
modelVersion: this.doc.modelVersion,
|
|
11235
11448
|
seqCounters: this.seqCounters,
|
|
11236
11449
|
seqAssigned: this.seqAssigned,
|
|
@@ -11240,6 +11453,43 @@ var Engine = class {
|
|
|
11240
11453
|
}
|
|
11241
11454
|
return result;
|
|
11242
11455
|
}
|
|
11456
|
+
/** Some document-opening empty paragraphs reserve a second mark line for
|
|
11457
|
+
* pagination while the following content paints over it on page one. Keep
|
|
11458
|
+
* the reservation in flow so later page breaks stay unchanged, then lift
|
|
11459
|
+
* only the painted first-page body. */
|
|
11460
|
+
applyOpeningFlowOverlap() {
|
|
11461
|
+
const opening = this.doc.sections[0]?.blocks[0];
|
|
11462
|
+
const next = this.doc.sections[0]?.blocks[1];
|
|
11463
|
+
const page = this.pages[0];
|
|
11464
|
+
if (!page || page.openingFlowOverlapApplied || opening?.type !== "paragraph" || opening.sectionBreak || paragraphHasContent(opening)) {
|
|
11465
|
+
return;
|
|
11466
|
+
}
|
|
11467
|
+
const beforeNegativeTable = next?.type === "table" && (next.props.indent ?? 0) < 0;
|
|
11468
|
+
const header = this.doc.headers.get(page.headerRel ?? "");
|
|
11469
|
+
const headerAnchors = header?.blocks.flatMap(
|
|
11470
|
+
(block) => block.type === "paragraph" ? this.collectAnchors(block) : []
|
|
11471
|
+
) ?? [];
|
|
11472
|
+
const beforeParagraphUnderUnwrappedHeader = next?.type === "paragraph" && page.headerGrown === true && headerAnchors.length > 0 && headerAnchors.every(
|
|
11473
|
+
(shape) => !("wrap" in shape) || shape.wrap === void 0 || shape.wrap === "none"
|
|
11474
|
+
);
|
|
11475
|
+
if (!beforeNegativeTable && !beforeParagraphUnderUnwrappedHeader) return;
|
|
11476
|
+
const firstBodyItem = page.items.findIndex(
|
|
11477
|
+
(item) => item.kind !== "text" || item.text.length > 0
|
|
11478
|
+
);
|
|
11479
|
+
if (firstBodyItem < 0) return;
|
|
11480
|
+
const paraProps = this.doc.effectiveParaProps(opening);
|
|
11481
|
+
const markProps = this.doc.effectiveRunProps(opening, paraProps.markRunProps ?? {});
|
|
11482
|
+
let overlap = this.measurer.metrics(
|
|
11483
|
+
fontOf(markProps, this.doc.styles.defaultRPr.font ?? "Calibri")
|
|
11484
|
+
).lineHeight;
|
|
11485
|
+
if (beforeParagraphUnderUnwrappedHeader) {
|
|
11486
|
+
overlap += paraProps.spacingAfter ?? 0;
|
|
11487
|
+
}
|
|
11488
|
+
for (let i = firstBodyItem; i < page.items.length; i++) {
|
|
11489
|
+
offsetItem(page.items[i], 0, -overlap);
|
|
11490
|
+
}
|
|
11491
|
+
page.openingFlowOverlapApplied = true;
|
|
11492
|
+
}
|
|
11243
11493
|
/** Whether this document is in the envelope the incremental path handles:
|
|
11244
11494
|
* one section, no notes, single column, upright flow, no line numbering /
|
|
11245
11495
|
* mirror margins / vertical alignment, and no positioned/floating content or
|
|
@@ -11367,9 +11617,13 @@ var Engine = class {
|
|
|
11367
11617
|
});
|
|
11368
11618
|
if (this.incrPrevPoints && blockIdx > this.incrFirstDirty) {
|
|
11369
11619
|
const pp = this.incrPrevPoints.get(blockIdx);
|
|
11370
|
-
|
|
11620
|
+
const pageShift = pp ? globalPageIdx - pp.pageCount : 0;
|
|
11621
|
+
if (pp && this.statesMatch(pp.state, pageShift)) {
|
|
11371
11622
|
__incrStats.convergedBlock = blockIdx;
|
|
11372
11623
|
__incrStats.convergedPage = globalPageIdx;
|
|
11624
|
+
__incrStats.pageShift = pageShift;
|
|
11625
|
+
this.incrPageShift = pageShift;
|
|
11626
|
+
this.incrConvergePrevPointPageIdx = pp.pageCount;
|
|
11373
11627
|
this.incrPoints.push(snapshot());
|
|
11374
11628
|
const reuseWholePage = p.items.length === 0 && pp.pageItemCount === 0 && Math.abs(this.y - p.bodyTop) < 1e-6;
|
|
11375
11629
|
if (reuseWholePage) {
|
|
@@ -11394,9 +11648,9 @@ var Engine = class {
|
|
|
11394
11648
|
/** True when the current engine state at a clean page top exactly matches a
|
|
11395
11649
|
* prev-layout capture point — i.e. the relaid tail has re-converged and the
|
|
11396
11650
|
* rest of the layout is guaranteed identical. */
|
|
11397
|
-
statesMatch(s) {
|
|
11651
|
+
statesMatch(s, pageShift = 0) {
|
|
11398
11652
|
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) {
|
|
11653
|
+
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
11654
|
return false;
|
|
11401
11655
|
}
|
|
11402
11656
|
if (this.seenNumIds.size !== s.seenNumIds.length) return false;
|
|
@@ -11453,11 +11707,60 @@ var Engine = class {
|
|
|
11453
11707
|
this.counters = new Map(s.counters.map(([k, v]) => [k, [...v]]));
|
|
11454
11708
|
this.seenNumIds = new Set(s.seenNumIds);
|
|
11455
11709
|
}
|
|
11710
|
+
bodyHasPageField(el16 = this.doc.docRoot) {
|
|
11711
|
+
const name = el16.name.includes(":") ? el16.name.slice(el16.name.indexOf(":") + 1) : el16.name;
|
|
11712
|
+
const instruction = name === "instrText" ? el16.text : name === "fldSimple" ? el16.attrs["w:instr"] ?? "" : "";
|
|
11713
|
+
if (/\bPAGE\b/i.test(instruction)) return true;
|
|
11714
|
+
return el16.children.some((child4) => this.bodyHasPageField(child4));
|
|
11715
|
+
}
|
|
11716
|
+
/** Clone a retained suffix page onto its new physical/display number. Body
|
|
11717
|
+
* items and page-border items stay identical; headers and footers are removed
|
|
11718
|
+
* so the final pass can rebuild PAGE fields against the shifted number. */
|
|
11719
|
+
shiftRetainedPage(page, pageShift) {
|
|
11720
|
+
if (page.hfStart === void 0) return null;
|
|
11721
|
+
const physIndex = page.physIndex + pageShift;
|
|
11722
|
+
const displayNumber = page.displayNumber + pageShift;
|
|
11723
|
+
const isFirstOfSection = physIndex === this.sectionFirstPagePhys;
|
|
11724
|
+
const useEven = this.doc.evenAndOddHeaders && displayNumber % 2 === 0;
|
|
11725
|
+
const headerRel = page.sp.titlePage && isFirstOfSection ? page.sp.headerRefs.first : useEven ? page.sp.headerRefs.even : page.sp.headerRefs.default;
|
|
11726
|
+
const footerRel = page.sp.titlePage && isFirstOfSection ? page.sp.footerRefs.first : useEven ? page.sp.footerRefs.even : page.sp.footerRefs.default;
|
|
11727
|
+
const shifted = {
|
|
11728
|
+
...page,
|
|
11729
|
+
items: page.items.slice(0, page.hfStart),
|
|
11730
|
+
physIndex,
|
|
11731
|
+
displayNumber,
|
|
11732
|
+
headerRel,
|
|
11733
|
+
footerRel,
|
|
11734
|
+
hfStart: void 0,
|
|
11735
|
+
colXs: [...page.colXs],
|
|
11736
|
+
colWidths: [...page.colWidths],
|
|
11737
|
+
footnotes: page.footnotes.map((note) => ({ ...note, items: [...note.items] })),
|
|
11738
|
+
footnoteH: [...page.footnoteH],
|
|
11739
|
+
bands: page.bands.map((band) => ({
|
|
11740
|
+
...band,
|
|
11741
|
+
colXs: [...band.colXs],
|
|
11742
|
+
colWidths: [...band.colWidths],
|
|
11743
|
+
bottoms: [...band.bottoms]
|
|
11744
|
+
}))
|
|
11745
|
+
};
|
|
11746
|
+
if (headerRel === page.headerRel && footerRel === page.footerRel) return shifted;
|
|
11747
|
+
this.sp = shifted.sp;
|
|
11748
|
+
const contentWidth = shifted.sp.pageWidth - shifted.sp.marginLeft - shifted.sp.marginRight - shifted.sp.gutter;
|
|
11749
|
+
const header = this.doc.headers.get(headerRel ?? "");
|
|
11750
|
+
const footer = this.doc.footers.get(footerRel ?? "");
|
|
11751
|
+
const headerHeight = this.measureHeaderFooter(header, shifted, contentWidth, this.pageFieldFrameOverlay(header), true);
|
|
11752
|
+
const footerHeight = this.measureHeaderFooter(footer, shifted, contentWidth, this.pageFieldFrameOverlay(footer));
|
|
11753
|
+
if (headerHeight !== page.headerHeight || footerHeight !== page.footerHeight) return null;
|
|
11754
|
+
shifted.headerHeight = headerHeight;
|
|
11755
|
+
shifted.footerHeight = footerHeight;
|
|
11756
|
+
return shifted;
|
|
11757
|
+
}
|
|
11456
11758
|
/** Attempt an incremental layout; return null (and leave a discarded, dirty
|
|
11457
11759
|
* engine) if reuse can't be proven safe, so the caller does a full layout in a
|
|
11458
11760
|
* fresh engine. */
|
|
11459
11761
|
runIncremental(prev, dirtyHint, dirtySource) {
|
|
11460
11762
|
__incrStats.fallbackReason = "";
|
|
11763
|
+
__incrStats.pageShift = 0;
|
|
11461
11764
|
const fallback = (reason) => {
|
|
11462
11765
|
__incrStats.fallbackReason = reason;
|
|
11463
11766
|
const perf2 = globalThis.__dxwPerf;
|
|
@@ -11472,11 +11775,12 @@ var Engine = class {
|
|
|
11472
11775
|
const blocks = this.doc.sections[0].blocks;
|
|
11473
11776
|
let newSigs = null;
|
|
11474
11777
|
let firstDirty = 0;
|
|
11475
|
-
if (dirtyHint && blocks.length
|
|
11778
|
+
if (dirtyHint && blocks.length > inc.sigs.length) {
|
|
11779
|
+
const delta = blocks.length - inc.sigs.length;
|
|
11476
11780
|
const inserted = blocks.findIndex((block) => block.src === dirtyHint);
|
|
11477
|
-
const changed = inserted -
|
|
11781
|
+
const changed = inserted - delta;
|
|
11478
11782
|
if (changed >= 0) {
|
|
11479
|
-
let hashed =
|
|
11783
|
+
let hashed = delta + 1;
|
|
11480
11784
|
let neighborsOk = true;
|
|
11481
11785
|
if (changed > 0) {
|
|
11482
11786
|
hashed++;
|
|
@@ -11484,21 +11788,47 @@ var Engine = class {
|
|
|
11484
11788
|
}
|
|
11485
11789
|
if (neighborsOk && inserted < blocks.length - 1) {
|
|
11486
11790
|
hashed++;
|
|
11487
|
-
neighborsOk = this.blockSig(blocks[inserted + 1]) === inc.sigs[
|
|
11791
|
+
neighborsOk = this.blockSig(blocks[inserted + 1]) === inc.sigs[changed + 1];
|
|
11488
11792
|
}
|
|
11489
11793
|
if (neighborsOk) {
|
|
11490
11794
|
newSigs = inc.sigs.slice();
|
|
11491
11795
|
newSigs[changed] = this.blockSig(blocks[changed]);
|
|
11492
|
-
newSigs.splice(
|
|
11796
|
+
newSigs.splice(changed + 1, 0, ...blocks.slice(changed + 1, inserted + 1).map((block) => this.blockSig(block)));
|
|
11493
11797
|
firstDirty = changed;
|
|
11494
11798
|
__incrStats.hintFastPath = true;
|
|
11495
11799
|
__incrStats.blocksHashed = hashed;
|
|
11496
11800
|
__incrStats.firstDirty = changed;
|
|
11497
|
-
this.incrBlockDelta =
|
|
11801
|
+
this.incrBlockDelta = delta;
|
|
11498
11802
|
this.incrBlockShiftAfter = changed;
|
|
11499
11803
|
}
|
|
11500
11804
|
}
|
|
11501
11805
|
}
|
|
11806
|
+
if (newSigs === null && dirtyHint && blocks.length === inc.sigs.length - 1) {
|
|
11807
|
+
const changed = blocks.findIndex((block) => block.src === dirtyHint);
|
|
11808
|
+
if (changed >= 0) {
|
|
11809
|
+
let hashed = 1;
|
|
11810
|
+
let neighborsOk = true;
|
|
11811
|
+
if (changed > 0) {
|
|
11812
|
+
hashed++;
|
|
11813
|
+
neighborsOk = this.blockSig(blocks[changed - 1]) === inc.sigs[changed - 1];
|
|
11814
|
+
}
|
|
11815
|
+
if (neighborsOk && changed < blocks.length - 1) {
|
|
11816
|
+
hashed++;
|
|
11817
|
+
neighborsOk = this.blockSig(blocks[changed + 1]) === inc.sigs[changed + 2];
|
|
11818
|
+
}
|
|
11819
|
+
if (neighborsOk) {
|
|
11820
|
+
newSigs = inc.sigs.slice();
|
|
11821
|
+
newSigs[changed] = this.blockSig(blocks[changed]);
|
|
11822
|
+
newSigs.splice(changed + 1, 1);
|
|
11823
|
+
firstDirty = changed;
|
|
11824
|
+
__incrStats.hintFastPath = true;
|
|
11825
|
+
__incrStats.blocksHashed = hashed;
|
|
11826
|
+
__incrStats.firstDirty = changed;
|
|
11827
|
+
this.incrBlockDelta = -1;
|
|
11828
|
+
this.incrBlockShiftAfter = changed + 1;
|
|
11829
|
+
}
|
|
11830
|
+
}
|
|
11831
|
+
}
|
|
11502
11832
|
if (newSigs === null && dirtyHint && blocks.length === inc.sigs.length) {
|
|
11503
11833
|
const d = blocks.findIndex((b) => b.src === dirtyHint);
|
|
11504
11834
|
if (d >= 0) {
|
|
@@ -11555,19 +11885,47 @@ var Engine = class {
|
|
|
11555
11885
|
__incrStats.resumePage = rp.pageCount;
|
|
11556
11886
|
__incrStats.convergedBlock = -1;
|
|
11557
11887
|
__incrStats.convergedPage = -1;
|
|
11888
|
+
__incrStats.pageShift = 0;
|
|
11558
11889
|
__incrStats.blocksLaid = 0;
|
|
11559
11890
|
this.restoreIncrState(rp.state, inc.pages[rp.pageCount].items.slice(0, rp.pageItemCount));
|
|
11560
11891
|
this.layoutBlocks(blocks, rp.blockIdx);
|
|
11561
11892
|
if (this.incrAbort) return fallback("layout-abort");
|
|
11562
11893
|
const suffixStart = this.incrConvergePrevPageIdx >= 0 ? this.incrConvergePrevPageIdx : inc.pages.length;
|
|
11563
|
-
const
|
|
11564
|
-
|
|
11894
|
+
const middleCount = this.pages.length;
|
|
11895
|
+
const hasRetainedSuffix = suffixStart < inc.pages.length;
|
|
11896
|
+
const pageShift = hasRetainedSuffix ? prefixCount + middleCount - suffixStart : 0;
|
|
11897
|
+
if (hasRetainedSuffix && pageShift !== this.incrPageShift) return fallback("page-shift");
|
|
11898
|
+
if (pageShift !== 0 && this.bodyHasPageField()) return fallback("body-page-field-shift");
|
|
11899
|
+
const shiftedSuffix = [];
|
|
11900
|
+
if (pageShift !== 0) {
|
|
11901
|
+
for (const page of inc.pages.slice(suffixStart)) {
|
|
11902
|
+
const shifted = this.shiftRetainedPage(page, pageShift);
|
|
11903
|
+
if (!shifted) return fallback("shifted-header-footer");
|
|
11904
|
+
shiftedSuffix.push(shifted);
|
|
11905
|
+
}
|
|
11906
|
+
}
|
|
11565
11907
|
const mergedBookmarks = new Map(inc.bookmarks);
|
|
11566
|
-
const
|
|
11908
|
+
const mergedBookmarkPageIndices = new Map(inc.bookmarkPageIndices);
|
|
11909
|
+
if (pageShift !== 0) {
|
|
11910
|
+
for (const [name, oldPageIndex] of inc.bookmarkPageIndices) {
|
|
11911
|
+
if (oldPageIndex < suffixStart) continue;
|
|
11912
|
+
const page = inc.pages[oldPageIndex];
|
|
11913
|
+
if (!page) continue;
|
|
11914
|
+
mergedBookmarkPageIndices.set(name, oldPageIndex + pageShift);
|
|
11915
|
+
mergedBookmarks.set(
|
|
11916
|
+
name,
|
|
11917
|
+
formatNumber(page.displayNumber + pageShift, PAGE_FMT[page.sp.pageNumberFormat ?? "decimal"] ?? "decimal")
|
|
11918
|
+
);
|
|
11919
|
+
}
|
|
11920
|
+
}
|
|
11567
11921
|
for (const [name, page] of this.bookmarkPages) {
|
|
11568
|
-
if (inc.bookmarks.get(name) !== page) movedBookmarks.add(name);
|
|
11569
11922
|
mergedBookmarks.set(name, page);
|
|
11570
11923
|
}
|
|
11924
|
+
for (const [name, pageIndex] of this.bookmarkPageIndices) mergedBookmarkPageIndices.set(name, pageIndex);
|
|
11925
|
+
const movedBookmarks = /* @__PURE__ */ new Set();
|
|
11926
|
+
for (const [name, page] of mergedBookmarks) {
|
|
11927
|
+
if (inc.bookmarks.get(name) !== page) movedBookmarks.add(name);
|
|
11928
|
+
}
|
|
11571
11929
|
const pageRefUpdates = [];
|
|
11572
11930
|
if (movedBookmarks.size > 0) {
|
|
11573
11931
|
for (const page of inc.pages) {
|
|
@@ -11585,32 +11943,53 @@ var Engine = class {
|
|
|
11585
11943
|
this.placeEndnotes();
|
|
11586
11944
|
this.emitFootnoteAreas();
|
|
11587
11945
|
this.emitColumnSeparators();
|
|
11588
|
-
this.finalizeHeadersFooters();
|
|
11589
11946
|
this.bookmarkPages = mergedBookmarks;
|
|
11590
|
-
this.
|
|
11947
|
+
this.bookmarkPageIndices = mergedBookmarkPageIndices;
|
|
11591
11948
|
this.applySectionVAlign();
|
|
11949
|
+
if (pageShift !== 0) {
|
|
11950
|
+
for (let i = 0; i < middleCount; i++) this.emitPageBorders(this.pages[i]);
|
|
11951
|
+
this.pages.push(...shiftedSuffix);
|
|
11952
|
+
this.finalizeHeadersFooters(false);
|
|
11953
|
+
} else {
|
|
11954
|
+
this.finalizeHeadersFooters();
|
|
11955
|
+
}
|
|
11956
|
+
this.rewritePageRefs(this.pages);
|
|
11592
11957
|
if (this.incrAbort) return fallback("postpass-abort");
|
|
11593
|
-
const middle = this.pages.map((p) => laidOutPage(p));
|
|
11958
|
+
const middle = this.pages.slice(0, middleCount).map((p) => laidOutPage(p));
|
|
11594
11959
|
let structuralPrefixEnd = prefixCount;
|
|
11595
11960
|
if (dirtySource) {
|
|
11596
|
-
const dirtyMiddleIdx = this.pages.findIndex(
|
|
11961
|
+
const dirtyMiddleIdx = this.pages.slice(0, middleCount).findIndex(
|
|
11597
11962
|
(page) => page.items.some((item) => item.kind === "text" && item.src?.t === dirtySource)
|
|
11598
11963
|
);
|
|
11599
11964
|
if (dirtyMiddleIdx > 0) structuralPrefixEnd += dirtyMiddleIdx;
|
|
11600
11965
|
}
|
|
11601
|
-
const outPages = prev.pages.slice(0, prefixCount).concat(
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
|
|
11605
|
-
|
|
11966
|
+
const outPages = prev.pages.slice(0, prefixCount).concat(
|
|
11967
|
+
pageShift !== 0 ? this.pages.map((page) => laidOutPage(page)) : middle.concat(prev.pages.slice(suffixStart))
|
|
11968
|
+
);
|
|
11969
|
+
const outInternal = inc.pages.slice(0, prefixCount).concat(
|
|
11970
|
+
pageShift !== 0 ? this.pages : this.pages.concat(inc.pages.slice(suffixStart))
|
|
11971
|
+
);
|
|
11972
|
+
const shiftPoint = (pt, itemDelta = 0) => ({
|
|
11606
11973
|
...pt,
|
|
11607
11974
|
blockIdx: shiftedBlockIdx(pt.blockIdx),
|
|
11608
|
-
|
|
11609
|
-
|
|
11975
|
+
pageCount: pt.pageCount + pageShift,
|
|
11976
|
+
pageItemCount: pt.pageItemCount + itemDelta,
|
|
11977
|
+
state: {
|
|
11978
|
+
...pt.state,
|
|
11979
|
+
page: {
|
|
11980
|
+
...pt.state.page,
|
|
11981
|
+
physIndex: pt.state.page.physIndex + pageShift,
|
|
11982
|
+
displayNumber: pt.state.page.displayNumber + pageShift
|
|
11983
|
+
}
|
|
11984
|
+
}
|
|
11985
|
+
});
|
|
11986
|
+
const samePageTail = this.incrConvergeBlockIdx >= 0 ? inc.points.filter(
|
|
11987
|
+
(pt) => pt.pageCount === this.incrConvergePrevPointPageIdx && shiftedBlockIdx(pt.blockIdx) > this.incrConvergeBlockIdx
|
|
11988
|
+
).map((pt) => shiftPoint(pt, this.incrConvergeItemDelta)) : [];
|
|
11610
11989
|
const points = inc.points.filter((pt) => pt.pageCount < prefixCount).concat(
|
|
11611
11990
|
this.incrPoints,
|
|
11612
11991
|
samePageTail,
|
|
11613
|
-
inc.points.filter((pt) => pt.pageCount >= suffixStart).map((pt) => (
|
|
11992
|
+
inc.points.filter((pt) => pt.pageCount >= suffixStart).map((pt) => shiftPoint(pt))
|
|
11614
11993
|
);
|
|
11615
11994
|
const perf = globalThis.__dxwPerf;
|
|
11616
11995
|
if (perf) perf.incr = { ...__incrStats };
|
|
@@ -11623,6 +12002,7 @@ var Engine = class {
|
|
|
11623
12002
|
points,
|
|
11624
12003
|
pages: outInternal,
|
|
11625
12004
|
bookmarks: mergedBookmarks,
|
|
12005
|
+
bookmarkPageIndices: mergedBookmarkPageIndices,
|
|
11626
12006
|
modelVersion: this.doc.modelVersion,
|
|
11627
12007
|
seqCounters: this.seqCounters,
|
|
11628
12008
|
seqAssigned: this.seqAssigned,
|
|
@@ -11746,8 +12126,8 @@ var Engine = class {
|
|
|
11746
12126
|
displayNumber,
|
|
11747
12127
|
headerHeight: 0,
|
|
11748
12128
|
footerHeight: 0,
|
|
11749
|
-
bodyTop:
|
|
11750
|
-
bandTop:
|
|
12129
|
+
bodyTop: sp.marginTop,
|
|
12130
|
+
bandTop: sp.marginTop,
|
|
11751
12131
|
softTop: !sectionStart,
|
|
11752
12132
|
bodyBottom: sp.pageHeight - Math.abs(sp.marginBottom),
|
|
11753
12133
|
colXs,
|
|
@@ -11771,13 +12151,17 @@ var Engine = class {
|
|
|
11771
12151
|
}
|
|
11772
12152
|
const header = this.doc.headers.get(page.headerRel ?? "");
|
|
11773
12153
|
const footer = this.doc.footers.get(page.footerRel ?? "");
|
|
11774
|
-
const headerH = this.measureHeaderFooter(header, page, contentWidth, this.pageFieldFrameOverlay(header));
|
|
12154
|
+
const headerH = this.measureHeaderFooter(header, page, contentWidth, this.pageFieldFrameOverlay(header), true);
|
|
11775
12155
|
const footerOverlay = this.pageFieldFrameOverlay(footer);
|
|
11776
12156
|
const footerH = this.measureHeaderFooter(footer, page, contentWidth, footerOverlay);
|
|
11777
12157
|
page.headerHeight = headerH;
|
|
11778
12158
|
page.footerHeight = footerH;
|
|
11779
12159
|
if (sp.marginTop >= 0) {
|
|
11780
|
-
|
|
12160
|
+
const headerBodyHeight = this.doc.compatibilityMode < 15 && header?.blocks.every((block) => block.type === "paragraph" && !paragraphHasContent(block)) ? ptToPx(7) : headerH;
|
|
12161
|
+
page.bodyTop = Math.max(
|
|
12162
|
+
sp.marginTop,
|
|
12163
|
+
headerBodyHeight > 0 ? sp.headerDistance + headerBodyHeight : 0
|
|
12164
|
+
);
|
|
11781
12165
|
page.bandTop = page.bodyTop;
|
|
11782
12166
|
page.headerGrown = page.bodyTop > sp.marginTop;
|
|
11783
12167
|
}
|
|
@@ -11964,6 +12348,7 @@ var Engine = class {
|
|
|
11964
12348
|
counters: new Map(Array.from(this.counters, ([k, v]) => [k, [...v]])),
|
|
11965
12349
|
seenNumIds: new Set(this.seenNumIds),
|
|
11966
12350
|
bookmarkPages: new Map(this.bookmarkPages),
|
|
12351
|
+
bookmarkPageIndices: new Map(this.bookmarkPageIndices),
|
|
11967
12352
|
placedFootnotes: new Set(this.placedFootnotes),
|
|
11968
12353
|
lnCounter: this.lnCounter,
|
|
11969
12354
|
lnLastPage: this.lnLastPage,
|
|
@@ -12003,6 +12388,7 @@ var Engine = class {
|
|
|
12003
12388
|
this.counters = s.counters;
|
|
12004
12389
|
this.seenNumIds = s.seenNumIds;
|
|
12005
12390
|
this.bookmarkPages = s.bookmarkPages;
|
|
12391
|
+
this.bookmarkPageIndices = s.bookmarkPageIndices;
|
|
12006
12392
|
this.placedFootnotes = s.placedFootnotes;
|
|
12007
12393
|
this.lnCounter = s.lnCounter;
|
|
12008
12394
|
this.lnLastPage = s.lnLastPage;
|
|
@@ -12015,7 +12401,7 @@ var Engine = class {
|
|
|
12015
12401
|
if (this.col + 1 < this.cur.colXs.length) {
|
|
12016
12402
|
this.col++;
|
|
12017
12403
|
this.y = this.columnStartY(this.col);
|
|
12018
|
-
this.bannerSlotUsed = 0;
|
|
12404
|
+
this.bannerSlotUsed = this.cur.bannerTop !== void 0 ? this.cur.openingColumnReserve ?? 0 : 0;
|
|
12019
12405
|
this.lastParaSpacingAfter = 0;
|
|
12020
12406
|
this.lastParaAfterPad = 0;
|
|
12021
12407
|
this.lastParaAfterPad = 0;
|
|
@@ -12352,7 +12738,7 @@ var Engine = class {
|
|
|
12352
12738
|
const runs = c.type === "run" ? [c] : c.runs;
|
|
12353
12739
|
for (const r of runs) {
|
|
12354
12740
|
for (const rc of r.content) {
|
|
12355
|
-
if (rc.kind !== "noteRef" || rc.self) continue;
|
|
12741
|
+
if (rc.kind !== "noteRef" || rc.self || rc.customMarkFollows) continue;
|
|
12356
12742
|
if (rc.noteType === "footnote" && this.doc.footnotes.has(rc.id) && !this.footnoteNumbers.has(rc.id)) {
|
|
12357
12743
|
this.footnoteNumbers.set(rc.id, fnStart + fn++);
|
|
12358
12744
|
} else if (rc.noteType === "endnote" && this.doc.endnotes.has(rc.id) && !this.endnoteNumbers.has(rc.id)) {
|
|
@@ -12865,6 +13251,20 @@ var Engine = class {
|
|
|
12865
13251
|
}
|
|
12866
13252
|
placeParagraph(para, prev, next, siblings, index) {
|
|
12867
13253
|
const props = this.doc.effectiveParaProps(para);
|
|
13254
|
+
const detachedFootnotes = customFootnoteAnchorIds(para);
|
|
13255
|
+
if (detachedFootnotes && next?.type === "paragraph") {
|
|
13256
|
+
const nextProps2 = this.doc.effectiveParaProps(next);
|
|
13257
|
+
const nextFrame = nextProps2.frame ? this.resolveFrame(nextProps2.frame) : void 0;
|
|
13258
|
+
if (nextFrame?.wrap === "notBeside" && nextFrame.w !== void 0 && this.cur.colXs.length > 1 && nextFrame.w > this.colWidth + 1) {
|
|
13259
|
+
for (const id of detachedFootnotes) this.registerFootnote(id, this.cur);
|
|
13260
|
+
const markProps = this.doc.effectiveRunProps(para, props.markRunProps ?? {});
|
|
13261
|
+
this.cur.openingColumnReserve = this.measurer.metrics(
|
|
13262
|
+
fontOf(markProps, this.doc.styles.defaultRPr.font ?? "Calibri")
|
|
13263
|
+
).lineHeight;
|
|
13264
|
+
this.customNoteBannerFit = true;
|
|
13265
|
+
return;
|
|
13266
|
+
}
|
|
13267
|
+
}
|
|
12868
13268
|
if (this.consumedFrames.has(para)) return;
|
|
12869
13269
|
if (props.frame && !props.dropCap && this.cur.physIndex !== -1) {
|
|
12870
13270
|
const fr = this.resolveFrame(props.frame);
|
|
@@ -12997,12 +13397,18 @@ var Engine = class {
|
|
|
12997
13397
|
if (breakBeforeForced && !(isLeadingPageBreak && keepSpBeforeAtPageTop)) dropSpaceBefore = true;
|
|
12998
13398
|
if (this.docGridDropBefore) {
|
|
12999
13399
|
if (props.snapToGrid === false && this.sp.docGridLinePitch) {
|
|
13000
|
-
const reduction = 2 * this.sp.docGridLinePitch;
|
|
13400
|
+
const reduction = (props.spacingBefore ?? 0) > 0 ? 4 * this.sp.docGridLinePitch : 2 * this.sp.docGridLinePitch;
|
|
13401
|
+
this.cur.bodyTop -= reduction;
|
|
13402
|
+
this.y -= reduction;
|
|
13403
|
+
} else if (para.props.styleId === "Heading1" && this.sp.docGridLinePitch) {
|
|
13404
|
+
const reduction = 3 * this.sp.docGridLinePitch - ptToPx(1.5);
|
|
13001
13405
|
this.cur.bodyTop -= reduction;
|
|
13002
13406
|
this.y -= reduction;
|
|
13407
|
+
dropSpaceBefore = true;
|
|
13408
|
+
} else {
|
|
13409
|
+
dropSpaceBefore = true;
|
|
13003
13410
|
}
|
|
13004
13411
|
this.docGridDropBefore = false;
|
|
13005
|
-
dropSpaceBefore = true;
|
|
13006
13412
|
}
|
|
13007
13413
|
const rawSpacingBefore = dropSpaceBefore ? 0 : props.spacingBefore ?? 0;
|
|
13008
13414
|
let paraTopEstimate = this.y + rawSpacingBefore;
|
|
@@ -13176,7 +13582,7 @@ var Engine = class {
|
|
|
13176
13582
|
const nextProps = nextPara ? this.doc.effectiveParaProps(nextPara) : void 0;
|
|
13177
13583
|
const nextLeadBreak = nextPara ? leadingBreakOf(nextPara) : void 0;
|
|
13178
13584
|
let legacyBreakChain = false;
|
|
13179
|
-
if (lines.length > 0 && this.pageIsEmptyAtCursor() && this.doc.compatibilityMode < 15 && this.sp.docGridType === "default" && props.keepNext && nextPara && nextProps?.keepNext && nextLeadBreak?.type === "page") {
|
|
13585
|
+
if (lines.length > 0 && this.pageIsEmptyAtCursor() && this.doc.compatibilityMode < 15 && this.sp.docGridType === "default" && !this.cur.footerRel && props.keepNext && nextPara && nextProps?.keepNext && nextLeadBreak?.type === "page") {
|
|
13180
13586
|
const breakProps = this.doc.effectiveRunProps(nextPara, nextLeadBreak.run.props);
|
|
13181
13587
|
const breakFont = fontOf(breakProps, this.doc.styles.defaultRPr.font ?? "Calibri");
|
|
13182
13588
|
let breakHeight = this.measurer.metrics(breakFont).lineHeight;
|
|
@@ -13347,6 +13753,7 @@ var Engine = class {
|
|
|
13347
13753
|
let simCol = this.col;
|
|
13348
13754
|
let simOnCurrentPage = true;
|
|
13349
13755
|
let simBannerUsed = this.bannerSlotUsed;
|
|
13756
|
+
const paragraphOverhang = this.customNoteBannerFit ? CUSTOM_NOTE_BANNER_OVERHANG : 0;
|
|
13350
13757
|
const updateBottom = () => {
|
|
13351
13758
|
bottom = simOnCurrentPage && this.balanceBottom !== void 0 && simCol + 1 < this.cur.colXs.length ? this.balanceBottom - simBannerUsed : this.cur.bodyBottom - (simOnCurrentPage ? this.footnoteReserve(this.cur, simCol) + simBannerUsed : 0);
|
|
13352
13759
|
};
|
|
@@ -13369,16 +13776,17 @@ var Engine = class {
|
|
|
13369
13776
|
}
|
|
13370
13777
|
};
|
|
13371
13778
|
const nextSimColumn = () => {
|
|
13372
|
-
simBannerUsed = 0;
|
|
13373
13779
|
simNotes = 0;
|
|
13374
13780
|
simNoted.clear();
|
|
13375
13781
|
if (simCol + 1 < this.cur.colXs.length) {
|
|
13376
13782
|
simCol++;
|
|
13377
13783
|
simY = simOnCurrentPage ? this.columnStartY(simCol) : this.cur.bodyTop;
|
|
13784
|
+
simBannerUsed = simOnCurrentPage && this.cur.bannerTop !== void 0 ? this.cur.openingColumnReserve ?? 0 : 0;
|
|
13378
13785
|
} else {
|
|
13379
13786
|
simCol = 0;
|
|
13380
13787
|
simOnCurrentPage = false;
|
|
13381
13788
|
simY = this.cur.bodyTop;
|
|
13789
|
+
simBannerUsed = 0;
|
|
13382
13790
|
}
|
|
13383
13791
|
updateBottom();
|
|
13384
13792
|
};
|
|
@@ -13397,7 +13805,7 @@ var Engine = class {
|
|
|
13397
13805
|
const noteAdd = lineNoteHeights(lines[li]);
|
|
13398
13806
|
const baseNotes = simOnCurrentPage ? this.cur.footnoteH[simCol] ?? 0 : 0;
|
|
13399
13807
|
const simSep = simNotes + noteAdd > 0 && baseNotes === 0 ? this.noteSeparatorReserve(this.cur) : 0;
|
|
13400
|
-
const overflowsHere = !postTablePageBreak && (simBalancing ? simY > bottom + 0.01 : simY + lines[li].fitHeight + (li === lines.length - 1 ? keepNextTail : 0) > bottom - simNotes - noteAdd - simSep + 0.01);
|
|
13808
|
+
const overflowsHere = !postTablePageBreak && (simBalancing ? simY > bottom + 0.01 : simY + lines[li].fitHeight + (li === lines.length - 1 ? keepNextTail : 0) > bottom - simNotes - noteAdd - simSep + paragraphOverhang + 0.01);
|
|
13401
13809
|
if (overflowsHere && li === segStart && segStart === 0 && onPartialPage && !simBalancing) {
|
|
13402
13810
|
breaks2.add(0);
|
|
13403
13811
|
segStart = 0;
|
|
@@ -13483,7 +13891,7 @@ var Engine = class {
|
|
|
13483
13891
|
const pendingNotes = this.pendingNoteHeight(line2);
|
|
13484
13892
|
const balancing = this.balanceBottom !== void 0 && this.col + 1 < this.cur.colXs.length;
|
|
13485
13893
|
const balBottomBased = balancing && this.colWidth < 40;
|
|
13486
|
-
const overflow = !postTablePageBreak && (balancing ? (balBottomBased ? this.y + line2.fitHeight : this.y) > this.bodyBottom + 0.01 : this.y + line2.fitHeight > this.bodyBottom - pendingNotes + 0.01) && !this.pageIsEmptyAtCursor();
|
|
13894
|
+
const overflow = !postTablePageBreak && (balancing ? (balBottomBased ? this.y + line2.fitHeight : this.y) > this.bodyBottom + 0.01 : this.y + line2.fitHeight > this.bodyBottom - pendingNotes + (this.customNoteBannerFit ? CUSTOM_NOTE_BANNER_OVERHANG : 0) + 0.01) && !this.pageIsEmptyAtCursor();
|
|
13487
13895
|
if ((planned || overflow) && li > fragStartLine) {
|
|
13488
13896
|
closeFragment(li, false);
|
|
13489
13897
|
this.nextColumn();
|
|
@@ -13523,6 +13931,7 @@ var Engine = class {
|
|
|
13523
13931
|
for (const bm of para.bookmarks) {
|
|
13524
13932
|
if (!this.bookmarkPages.has(bm)) {
|
|
13525
13933
|
this.bookmarkPages.set(bm, formatNumber(pg.displayNumber, PAGE_FMT[pg.sp.pageNumberFormat ?? "decimal"] ?? "decimal"));
|
|
13934
|
+
this.bookmarkPageIndices.set(bm, pg.physIndex - 1);
|
|
13526
13935
|
}
|
|
13527
13936
|
}
|
|
13528
13937
|
}
|
|
@@ -14150,13 +14559,35 @@ var Engine = class {
|
|
|
14150
14559
|
y = Math.max(y, pendingPageFrame.bottom);
|
|
14151
14560
|
pendingPageFrame = null;
|
|
14152
14561
|
}
|
|
14153
|
-
y = this.layoutTableInFrame(block, fake, 0, y, width, fields);
|
|
14562
|
+
y = this.layoutTableInFrame(block, fake, 0, y, width, fields, inCell === true);
|
|
14154
14563
|
framePrevAfter = 0;
|
|
14155
14564
|
}
|
|
14156
14565
|
}
|
|
14157
14566
|
if (pendingPageFrame) y = Math.max(y, pendingPageFrame.bottom);
|
|
14567
|
+
const itemBottom = (item) => {
|
|
14568
|
+
if (item.kind === "text") return (item.glyphTop ?? item.lineTop) + item.lineHeight;
|
|
14569
|
+
if (item.kind === "rect" || item.kind === "image" || item.kind === "path" || item.kind === "drawingHit") {
|
|
14570
|
+
return item.y + item.height;
|
|
14571
|
+
}
|
|
14572
|
+
if (item.kind === "edge") return Math.max(item.y1, item.y2);
|
|
14573
|
+
if (item.kind === "wordart" || item.kind === "warptext") return item.y + item.height;
|
|
14574
|
+
return 0;
|
|
14575
|
+
};
|
|
14576
|
+
const headerBandBottom = this.sp.marginTop - (origin?.y ?? 0);
|
|
14577
|
+
const paintedHeaderBottom = items.reduce((bottom, item) => {
|
|
14578
|
+
const itemEnd = itemBottom(item);
|
|
14579
|
+
return "behind" in item && item.behind && itemEnd <= headerBandBottom + 0.01 ? Math.max(bottom, itemEnd) : bottom;
|
|
14580
|
+
}, 0);
|
|
14581
|
+
const wrappedBottom = (this.floats.get(fake) ?? []).reduce(
|
|
14582
|
+
(bottom, float) => Math.max(bottom, float.y1 - (origin?.y ?? 0)),
|
|
14583
|
+
0
|
|
14584
|
+
);
|
|
14158
14585
|
this.floats.delete(fake);
|
|
14159
|
-
return {
|
|
14586
|
+
return {
|
|
14587
|
+
items,
|
|
14588
|
+
height: y + pageFramePhantomH,
|
|
14589
|
+
contentBottom: Math.max(y + pageFramePhantomH, paintedHeaderBottom, wrappedBottom)
|
|
14590
|
+
};
|
|
14160
14591
|
}
|
|
14161
14592
|
/**
|
|
14162
14593
|
* Emit floating shapes anchored at (textX, textY). Coordinates in the shape
|
|
@@ -14562,7 +14993,7 @@ var Engine = class {
|
|
|
14562
14993
|
page.items.push(it);
|
|
14563
14994
|
}
|
|
14564
14995
|
}
|
|
14565
|
-
measureHeaderFooter(hf, page, contentWidth, overlayPageFrame = false) {
|
|
14996
|
+
measureHeaderFooter(hf, page, contentWidth, overlayPageFrame = false, reserveBodyClearance = false) {
|
|
14566
14997
|
if (!hf || hf.blocks.length === 0) return 0;
|
|
14567
14998
|
const fields = {
|
|
14568
14999
|
pageNumber: () => page.displayNumber,
|
|
@@ -14571,10 +15002,25 @@ var Engine = class {
|
|
|
14571
15002
|
};
|
|
14572
15003
|
const snapshot = new Map(Array.from(this.counters, ([k, v]) => [k, [...v]]));
|
|
14573
15004
|
const seenSnapshot = new Set(this.seenNumIds);
|
|
14574
|
-
const {
|
|
15005
|
+
const origin = reserveBodyClearance ? { x: page.sp.marginLeft + page.sp.gutter, y: page.sp.headerDistance } : void 0;
|
|
15006
|
+
const { height, contentBottom } = this.layoutFrame(
|
|
15007
|
+
hf.blocks,
|
|
15008
|
+
contentWidth,
|
|
15009
|
+
fields,
|
|
15010
|
+
origin,
|
|
15011
|
+
false,
|
|
15012
|
+
overlayPageFrame
|
|
15013
|
+
);
|
|
14575
15014
|
this.counters = snapshot;
|
|
14576
15015
|
this.seenNumIds = seenSnapshot;
|
|
14577
|
-
|
|
15016
|
+
const anchors = hf.blocks.flatMap(
|
|
15017
|
+
(block) => block.type === "paragraph" ? this.collectAnchors(block) : []
|
|
15018
|
+
);
|
|
15019
|
+
const hasOnlyUnwrappedAnchors = anchors.length > 0 && anchors.every(
|
|
15020
|
+
(shape) => !("wrap" in shape) || shape.wrap === void 0 || shape.wrap === "none"
|
|
15021
|
+
);
|
|
15022
|
+
const complexHeader = anchors.length > 0 || hf.blocks.some((block) => block.type === "table");
|
|
15023
|
+
return reserveBodyClearance ? Math.max(height, contentBottom) + (!hasOnlyUnwrappedAnchors && complexHeader ? ptToPx(22.5) : 0) : height;
|
|
14578
15024
|
}
|
|
14579
15025
|
pageFieldFrameOverlay(hf) {
|
|
14580
15026
|
if (!hf) return false;
|
|
@@ -14636,7 +15082,10 @@ var Engine = class {
|
|
|
14636
15082
|
const measured = this.layoutFrame(footer.blocks, contentWidth, fields, void 0, false, overlayPageFrame);
|
|
14637
15083
|
this.counters = snapshot;
|
|
14638
15084
|
this.seenNumIds = seenSnapshot;
|
|
14639
|
-
const
|
|
15085
|
+
const legacyPageFrame = this.doc.compatibilityMode < 15 && footer.blocks.some(
|
|
15086
|
+
(block) => block.type === "paragraph" && this.doc.effectiveParaProps(block).frame?.vAnchor === "page"
|
|
15087
|
+
);
|
|
15088
|
+
const top = sp.pageHeight - sp.footerDistance - (legacyPageFrame ? 0 : measured.height);
|
|
14640
15089
|
snapshot = new Map(Array.from(this.counters, ([k, v]) => [k, [...v]]));
|
|
14641
15090
|
seenSnapshot = new Set(this.seenNumIds);
|
|
14642
15091
|
this.hfMarginVTop = page.bodyTop;
|
|
@@ -15015,7 +15464,14 @@ var Engine = class {
|
|
|
15015
15464
|
if (cell.props.margins?.top !== void 0) topPad = Math.max(topPad, cell.props.margins.top);
|
|
15016
15465
|
if (cell.props.margins?.bottom !== void 0) bottomPad = Math.max(bottomPad, cell.props.margins.bottom);
|
|
15017
15466
|
}
|
|
15018
|
-
if (row.props.heightRule === "exact")
|
|
15467
|
+
if (row.props.heightRule === "exact") {
|
|
15468
|
+
return this.doc.compatibilityMode < 15 ? trHeight : trHeight + topPad;
|
|
15469
|
+
}
|
|
15470
|
+
if (this.doc.compatibilityMode < 15) {
|
|
15471
|
+
const legacyBottomPad = bottomPad >= ptToPx(1) ? bottomPad : 0;
|
|
15472
|
+
const legacyTopPad = row.props.heightRule === "atLeast" && (row.props.height ?? 0) >= ptToPx(30) ? Math.max(topPad - ptToPx(0.25), 0) : topPad;
|
|
15473
|
+
return Math.max(contentHeight, trHeight + legacyTopPad + legacyBottomPad);
|
|
15474
|
+
}
|
|
15019
15475
|
const borderPad = this.rowBorderShare(tbl, ri);
|
|
15020
15476
|
return Math.max(contentHeight, trHeight + topPad + bottomPad + borderPad);
|
|
15021
15477
|
}
|
|
@@ -15235,7 +15691,7 @@ var Engine = class {
|
|
|
15235
15691
|
};
|
|
15236
15692
|
let guard = 0;
|
|
15237
15693
|
const noteReserve = this.rowNoteHeight(laid) + this.footnoteReserve(this.cur, this.col);
|
|
15238
|
-
const overhang = noteReserve > 0 || row.props.cantSplit
|
|
15694
|
+
const overhang = noteReserve > 0 || row.props.heightRule === "exact" ? 0 : row.props.cantSplit ? this.doc.compatibilityMode < 15 && (row.props.heightRule !== "atLeast" || (row.props.height ?? 0) >= ptToPx(2)) ? this.cur.footerHeight : 0 : ROW_OVERHANG_TOL;
|
|
15239
15695
|
while (this.y + rowHeight > this.bodyBottom - this.rowNoteHeight(laid) + overhang + 0.01 && guard++ < 50) {
|
|
15240
15696
|
const atColumnTop = this.pageIsEmptyAtCursor() || this.y <= this.cur.bodyTop + this.rowBorderWidths(tbl, ri).top / 2 + 0.01;
|
|
15241
15697
|
const cantSplitHolds = row.props.cantSplit === true && (rowHeight <= this.cur.bodyBottom - this.cur.bodyTop + 0.01 || !atColumnTop);
|
|
@@ -15454,9 +15910,9 @@ var Engine = class {
|
|
|
15454
15910
|
});
|
|
15455
15911
|
}
|
|
15456
15912
|
}
|
|
15457
|
-
layoutTableInFrame(tbl, fake, x0, y, width, fields) {
|
|
15913
|
+
layoutTableInFrame(tbl, fake, x0, y, width, fields, nested) {
|
|
15458
15914
|
this.ensureTableBorders(tbl);
|
|
15459
|
-
const widths = this.resolveGridWidths(tbl, width,
|
|
15915
|
+
const widths = this.resolveGridWidths(tbl, width, nested);
|
|
15460
15916
|
const saveY = this.y;
|
|
15461
15917
|
const saveCur = this.cur;
|
|
15462
15918
|
const saveCol = this.col;
|
|
@@ -15722,6 +16178,7 @@ var Engine = class {
|
|
|
15722
16178
|
}
|
|
15723
16179
|
let maxH = 0;
|
|
15724
16180
|
let measuredContentH = 0;
|
|
16181
|
+
const effectiveBottomPad = (bottom) => this.doc.compatibilityMode < 15 && row.props.heightRule === "atLeast" && (row.props.height ?? 0) < ptToPx(2) && (bottom ?? 0) >= ptToPx(2) ? (bottom ?? 0) / 2 : bottom ?? 0;
|
|
15725
16182
|
for (let ci = 0; ci < row.cells.length; ci++) {
|
|
15726
16183
|
const cell = row.cells[ci];
|
|
15727
16184
|
const { x, width: w, margins: m } = geometry[ci];
|
|
@@ -15741,7 +16198,7 @@ var Engine = class {
|
|
|
15741
16198
|
true
|
|
15742
16199
|
);
|
|
15743
16200
|
for (const it of items) offsetItem(it, m.left ?? 0, m.top ?? 0);
|
|
15744
|
-
const cellHeight = height + (m.top ?? 0) + (m.bottom
|
|
16201
|
+
const cellHeight = height + (m.top ?? 0) + effectiveBottomPad(m.bottom);
|
|
15745
16202
|
cells[ci] = { items, height: cellHeight, x, width: w, cellIdx: ci };
|
|
15746
16203
|
measuredContentH = Math.max(measuredContentH, height);
|
|
15747
16204
|
maxH = Math.max(maxH, cellHeight);
|
|
@@ -15785,7 +16242,7 @@ var Engine = class {
|
|
|
15785
16242
|
it.rotate = { deg, ox: centerX - it.x, oy: centerY - top };
|
|
15786
16243
|
}
|
|
15787
16244
|
}
|
|
15788
|
-
const cellHeight = frameWidth + (m.top ?? 0) + (m.bottom
|
|
16245
|
+
const cellHeight = frameWidth + (m.top ?? 0) + effectiveBottomPad(m.bottom);
|
|
15789
16246
|
cells[ci] = { items, height: cellHeight, x, width: w, cellIdx: ci, rotated: true };
|
|
15790
16247
|
maxH = Math.max(maxH, cellHeight);
|
|
15791
16248
|
}
|
|
@@ -15934,6 +16391,24 @@ var Engine = class {
|
|
|
15934
16391
|
}
|
|
15935
16392
|
}
|
|
15936
16393
|
};
|
|
16394
|
+
function customFootnoteAnchorIds(p) {
|
|
16395
|
+
const ids = [];
|
|
16396
|
+
for (const child4 of p.children) {
|
|
16397
|
+
const runs = child4.type === "run" ? [child4] : child4.runs;
|
|
16398
|
+
for (const run of runs) {
|
|
16399
|
+
for (const content of run.content) {
|
|
16400
|
+
if (content.kind === "text") {
|
|
16401
|
+
if (content.text.trim().length > 0) return void 0;
|
|
16402
|
+
} else if (content.kind === "noteRef" && content.noteType === "footnote" && !content.self && content.customMarkFollows) {
|
|
16403
|
+
ids.push(content.id);
|
|
16404
|
+
} else {
|
|
16405
|
+
return void 0;
|
|
16406
|
+
}
|
|
16407
|
+
}
|
|
16408
|
+
}
|
|
16409
|
+
}
|
|
16410
|
+
return ids.length > 0 ? ids : void 0;
|
|
16411
|
+
}
|
|
15937
16412
|
function isEmptyParagraph(p) {
|
|
15938
16413
|
for (const child4 of p.children) {
|
|
15939
16414
|
const runs = child4.type === "run" ? [child4] : child4.runs;
|
|
@@ -16905,7 +17380,7 @@ function renderToDom(doc, layout, container, options = {}, prev) {
|
|
|
16905
17380
|
renderComments(doc, root, handle.bindings, zoom, options.onDeleteComment, options.onReplyComment);
|
|
16906
17381
|
}
|
|
16907
17382
|
};
|
|
16908
|
-
const wantedPages = () => {
|
|
17383
|
+
const wantedPages = (overscan = 2) => {
|
|
16909
17384
|
const wanted = /* @__PURE__ */ new Set();
|
|
16910
17385
|
const top = container.scrollTop;
|
|
16911
17386
|
const bottom = top + Math.max(container.clientHeight, 1);
|
|
@@ -16921,15 +17396,15 @@ function renderToDom(doc, layout, container, options = {}, prev) {
|
|
|
16921
17396
|
y = pageBottom + gap;
|
|
16922
17397
|
}
|
|
16923
17398
|
if (first < 0) first = last = Math.max(0, pages.length - 1);
|
|
16924
|
-
for (let i = Math.max(0, first -
|
|
17399
|
+
for (let i = Math.max(0, first - overscan); i <= Math.min(pages.length - 1, last + overscan); i++) wanted.add(i);
|
|
16925
17400
|
for (let i = 0; i < pages.length; i++) {
|
|
16926
17401
|
if (pages[i].mounted && pages[i].el.querySelector("[data-dxw-caret], .dxw-sel")) wanted.add(i);
|
|
16927
17402
|
}
|
|
16928
17403
|
return wanted;
|
|
16929
17404
|
};
|
|
16930
|
-
const syncViewport = (notify, force = false) => {
|
|
17405
|
+
const syncViewport = (notify, force = false, overscan = 2) => {
|
|
16931
17406
|
if (!virtualized) return;
|
|
16932
|
-
const wanted = wantedPages();
|
|
17407
|
+
const wanted = wantedPages(overscan);
|
|
16933
17408
|
let changed = false;
|
|
16934
17409
|
for (const i of wanted) {
|
|
16935
17410
|
if (pages[i].mounted) continue;
|
|
@@ -16944,14 +17419,30 @@ function renderToDom(doc, layout, container, options = {}, prev) {
|
|
|
16944
17419
|
}
|
|
16945
17420
|
if (!changed && !force) return;
|
|
16946
17421
|
refreshBindings();
|
|
16947
|
-
redrawComments();
|
|
17422
|
+
if (drawComments || force) redrawComments();
|
|
16948
17423
|
if (notify) options.onViewportChange?.();
|
|
16949
17424
|
};
|
|
17425
|
+
let settleTimer;
|
|
17426
|
+
let syncedScrollTop = container.scrollTop;
|
|
17427
|
+
let pendingOverscan = 2;
|
|
16950
17428
|
const scheduleViewport = () => {
|
|
17429
|
+
const fast = Math.abs(container.scrollTop - syncedScrollTop) > Math.max(container.clientHeight, 1) * 2;
|
|
17430
|
+
if (fast) {
|
|
17431
|
+
pendingOverscan = 0;
|
|
17432
|
+
if (settleTimer !== void 0) clearTimeout(settleTimer);
|
|
17433
|
+
settleTimer = setTimeout(() => {
|
|
17434
|
+
settleTimer = void 0;
|
|
17435
|
+
syncedScrollTop = container.scrollTop;
|
|
17436
|
+
syncViewport(true);
|
|
17437
|
+
}, 80);
|
|
17438
|
+
}
|
|
16951
17439
|
if (frame) return;
|
|
16952
17440
|
frame = requestAnimationFrame(() => {
|
|
16953
17441
|
frame = 0;
|
|
16954
|
-
|
|
17442
|
+
const overscan = pendingOverscan;
|
|
17443
|
+
pendingOverscan = 2;
|
|
17444
|
+
syncedScrollTop = container.scrollTop;
|
|
17445
|
+
syncViewport(true, false, overscan);
|
|
16955
17446
|
});
|
|
16956
17447
|
};
|
|
16957
17448
|
const stopVirtualizer = () => {
|
|
@@ -16960,6 +17451,8 @@ function renderToDom(doc, layout, container, options = {}, prev) {
|
|
|
16960
17451
|
window.removeEventListener("resize", scheduleViewport);
|
|
16961
17452
|
if (frame) cancelAnimationFrame(frame);
|
|
16962
17453
|
frame = 0;
|
|
17454
|
+
if (settleTimer !== void 0) clearTimeout(settleTimer);
|
|
17455
|
+
settleTimer = void 0;
|
|
16963
17456
|
};
|
|
16964
17457
|
handle = {
|
|
16965
17458
|
root,
|
|
@@ -17683,6 +18176,11 @@ function renderItem(doc, item, urls) {
|
|
|
17683
18176
|
hit.dataset.dxwDrawing = "1";
|
|
17684
18177
|
if (item.ink) hit.dataset.dxwInk = "1";
|
|
17685
18178
|
if (item.smartArt) hit.dataset.dxwSmartArt = "1";
|
|
18179
|
+
if (item.height < 12) {
|
|
18180
|
+
const target = document.createElement("div");
|
|
18181
|
+
target.style.cssText = `position:absolute;left:0;top:${-(12 - item.height) / 2}px;width:100%;height:12px;cursor:move;`;
|
|
18182
|
+
hit.appendChild(target);
|
|
18183
|
+
}
|
|
17686
18184
|
return hit;
|
|
17687
18185
|
}
|
|
17688
18186
|
case "edge": {
|
|
@@ -18142,6 +18640,10 @@ function renderText(item) {
|
|
|
18142
18640
|
el16.style.alignItems = "flex-end";
|
|
18143
18641
|
el16.style.whiteSpace = "pre";
|
|
18144
18642
|
el16.style.font = cssFont(item.font);
|
|
18643
|
+
if (item.font.paintDY) {
|
|
18644
|
+
const transform = el16.style.transform;
|
|
18645
|
+
el16.style.transform = `${transform ? `${transform} ` : ""}translateY(${item.font.paintDY}px)`;
|
|
18646
|
+
}
|
|
18145
18647
|
}
|
|
18146
18648
|
if (item.rtl) {
|
|
18147
18649
|
el16.style.direction = "rtl";
|
|
@@ -18205,7 +18707,8 @@ function renderEdge(x1, y1, x2, y2, border, rotate) {
|
|
|
18205
18707
|
}
|
|
18206
18708
|
const horizontal = Math.abs(y2 - y1) < 0.01;
|
|
18207
18709
|
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
18208
|
-
const
|
|
18710
|
+
const declaredWidth = border.rawWidth !== void 0 && border.rawWidth < 0.25 ? border.rawWidth : border.width;
|
|
18711
|
+
const w = Math.max(1 / dpr, Math.round(declaredWidth * dpr) / dpr);
|
|
18209
18712
|
const snap = (v) => Math.round(v * dpr) / dpr;
|
|
18210
18713
|
const place = border.space === 0 ? snap : (v) => v;
|
|
18211
18714
|
const dashPattern = border.style === "dashed" || border.style === "dotDash" || border.style === "dotDotDash" ? [3, 1] : border.style === "dotted" ? [1, 1] : null;
|
|
@@ -18475,6 +18978,10 @@ function mergeParagraphBackward(doc, pEl) {
|
|
|
18475
18978
|
if (idx <= 0) return false;
|
|
18476
18979
|
const prev = parent.children[idx - 1];
|
|
18477
18980
|
if (localName(prev.name) !== "p") return false;
|
|
18981
|
+
const finishMerge = (survivor) => {
|
|
18982
|
+
if (!doc.reparseDirectBodyParagraphMerge(prev, pEl, survivor)) doc.refresh();
|
|
18983
|
+
return true;
|
|
18984
|
+
};
|
|
18478
18985
|
const visible = [];
|
|
18479
18986
|
const collect = (el16) => {
|
|
18480
18987
|
for (const c of el16.children) {
|
|
@@ -18492,6 +18999,7 @@ function mergeParagraphBackward(doc, pEl) {
|
|
|
18492
18999
|
if (type === "page" || type === "column") {
|
|
18493
19000
|
if (visible.length === 1) {
|
|
18494
19001
|
parent.children.splice(idx - 1, 1);
|
|
19002
|
+
return finishMerge(pEl);
|
|
18495
19003
|
} else {
|
|
18496
19004
|
last.parent.children.splice(last.parent.children.indexOf(last.el), 1);
|
|
18497
19005
|
}
|
|
@@ -18501,14 +19009,12 @@ function mergeParagraphBackward(doc, pEl) {
|
|
|
18501
19009
|
}
|
|
18502
19010
|
if (visible.length === 0) {
|
|
18503
19011
|
parent.children.splice(idx - 1, 1);
|
|
18504
|
-
|
|
18505
|
-
return true;
|
|
19012
|
+
return finishMerge(pEl);
|
|
18506
19013
|
}
|
|
18507
19014
|
const moved = pEl.children.filter((c) => localName(c.name) !== "pPr");
|
|
18508
19015
|
prev.children.push(...moved);
|
|
18509
19016
|
parent.children.splice(idx, 1);
|
|
18510
|
-
|
|
18511
|
-
return true;
|
|
19017
|
+
return finishMerge(prev);
|
|
18512
19018
|
}
|
|
18513
19019
|
function firstTextOf(pEl) {
|
|
18514
19020
|
const walk2 = (el16) => {
|
|
@@ -20423,23 +20929,44 @@ function insertShapeAt(doc, caretT, preset, text = "") {
|
|
|
20423
20929
|
if (!caretRun || !parent || localName(caretRun.name) !== "r") return null;
|
|
20424
20930
|
const w = prefixOf8(caretRun);
|
|
20425
20931
|
const id = String(doc.nextDrawingId());
|
|
20426
|
-
const
|
|
20427
|
-
const
|
|
20932
|
+
const isLine = preset === "line";
|
|
20933
|
+
const width = isLine ? 240 : preset === "textBox" ? 240 : 192;
|
|
20934
|
+
const height = isLine ? 2 : preset === "textBox" ? 72 : 96;
|
|
20428
20935
|
const cx = String(Math.round(width * EMU_PER_PX4));
|
|
20429
20936
|
const cy = String(Math.round(height * EMU_PER_PX4));
|
|
20430
20937
|
const geometry = preset === "roundedRectangle" ? "roundRect" : preset === "rectangle" || preset === "textBox" ? "rect" : preset;
|
|
20431
20938
|
const isTextBox = preset === "textBox";
|
|
20432
|
-
const shapeName = isTextBox ? `Text Box ${id}` : `Shape ${id}`;
|
|
20939
|
+
const shapeName = isLine ? `Line ${id}` : isTextBox ? `Text Box ${id}` : `Shape ${id}`;
|
|
20433
20940
|
const spPr = [
|
|
20434
|
-
el6("a:xfrm", {}, [
|
|
20941
|
+
el6("a:xfrm", {}, [
|
|
20942
|
+
el6("a:off", { x: "0", y: "0" }),
|
|
20943
|
+
el6("a:ext", { cx, cy })
|
|
20944
|
+
]),
|
|
20435
20945
|
el6("a:prstGeom", { prst: geometry }, [el6("a:avLst")]),
|
|
20436
|
-
isTextBox ? el6("a:noFill") : el6("a:solidFill", {}, [el6("a:srgbClr", { val: "4472C4" })]),
|
|
20437
|
-
el6("a:ln", { w: "12700" }, [el6("a:solidFill", {}, [el6("a:srgbClr", { val: isTextBox ? "404040" : "2F5597" })])])
|
|
20946
|
+
isTextBox || isLine ? el6("a:noFill") : el6("a:solidFill", {}, [el6("a:srgbClr", { val: "4472C4" })]),
|
|
20947
|
+
el6("a:ln", { w: "12700" }, [el6("a:solidFill", {}, [el6("a:srgbClr", { val: isTextBox || isLine ? "404040" : "2F5597" })])])
|
|
20438
20948
|
];
|
|
20439
20949
|
const textRun = el6(`${w}r`, {}, [
|
|
20440
20950
|
el6(`${w}rPr`, {}, [el6(`${w}color`, { [`${w}val`]: isTextBox ? "202124" : "FFFFFF" }), el6(`${w}sz`, { [`${w}val`]: "22" })]),
|
|
20441
20951
|
el6(`${w}t`, { "xml:space": "preserve" }, [], text)
|
|
20442
20952
|
]);
|
|
20953
|
+
const shapeChildren = isLine ? [
|
|
20954
|
+
el6("wps:cNvCnPr", {}, [el6("a:cxnSpLocks", { noChangeShapeType: "1" })]),
|
|
20955
|
+
el6("wps:spPr", { bwMode: "auto" }, spPr),
|
|
20956
|
+
el6("wps:bodyPr")
|
|
20957
|
+
] : [
|
|
20958
|
+
el6("wps:cNvSpPr", isTextBox ? { txBox: "1" } : {}),
|
|
20959
|
+
el6("wps:spPr", {}, spPr),
|
|
20960
|
+
el6("wps:txbx", {}, [
|
|
20961
|
+
el6(`${w}txbxContent`, {}, [
|
|
20962
|
+
el6(`${w}p`, {}, [
|
|
20963
|
+
el6(`${w}pPr`, {}, [el6(`${w}jc`, { [`${w}val`]: isTextBox ? "left" : "center" })]),
|
|
20964
|
+
textRun
|
|
20965
|
+
])
|
|
20966
|
+
])
|
|
20967
|
+
]),
|
|
20968
|
+
el6("wps:bodyPr", { rot: "0", anchor: isTextBox ? "t" : "ctr" }, [el6("a:noAutofit")])
|
|
20969
|
+
];
|
|
20443
20970
|
const drawing = el6(`${w}drawing`, {}, [
|
|
20444
20971
|
el6("wp:anchor", {
|
|
20445
20972
|
"xmlns:wp": NS_WP3,
|
|
@@ -20459,24 +20986,12 @@ function insertShapeAt(doc, caretT, preset, text = "") {
|
|
|
20459
20986
|
el6("wp:positionV", { relativeFrom: "paragraph" }, [el6("wp:posOffset", {}, [], "0")]),
|
|
20460
20987
|
el6("wp:extent", { cx, cy }),
|
|
20461
20988
|
el6("wp:effectExtent", { l: "0", t: "0", r: "0", b: "0" }),
|
|
20462
|
-
el6("wp:wrapSquare", { wrapText: "bothSides" }),
|
|
20989
|
+
isLine ? el6("wp:wrapNone") : el6("wp:wrapSquare", { wrapText: "bothSides" }),
|
|
20463
20990
|
el6("wp:docPr", { id, name: shapeName }),
|
|
20464
20991
|
el6("wp:cNvGraphicFramePr"),
|
|
20465
20992
|
el6("a:graphic", { "xmlns:a": NS_A3 }, [
|
|
20466
20993
|
el6("a:graphicData", { uri: NS_WPS }, [
|
|
20467
|
-
el6("wps:wsp", { "xmlns:wps": NS_WPS },
|
|
20468
|
-
el6("wps:cNvSpPr", { txBox: "1" }),
|
|
20469
|
-
el6("wps:spPr", {}, spPr),
|
|
20470
|
-
el6("wps:txbx", {}, [
|
|
20471
|
-
el6(`${w}txbxContent`, {}, [
|
|
20472
|
-
el6(`${w}p`, {}, [
|
|
20473
|
-
el6(`${w}pPr`, {}, [el6(`${w}jc`, { [`${w}val`]: isTextBox ? "left" : "center" })]),
|
|
20474
|
-
textRun
|
|
20475
|
-
])
|
|
20476
|
-
])
|
|
20477
|
-
]),
|
|
20478
|
-
el6("wps:bodyPr", { rot: "0", anchor: isTextBox ? "t" : "ctr" }, [el6("a:noAutofit")])
|
|
20479
|
-
])
|
|
20994
|
+
el6("wps:wsp", { "xmlns:wps": NS_WPS }, shapeChildren)
|
|
20480
20995
|
])
|
|
20481
20996
|
])
|
|
20482
20997
|
])
|
|
@@ -20538,7 +21053,26 @@ function setDrawingWordArtText(doc, drawing, text) {
|
|
|
20538
21053
|
doc.refresh();
|
|
20539
21054
|
return true;
|
|
20540
21055
|
}
|
|
20541
|
-
function
|
|
21056
|
+
function drawingLineStyle(drawing) {
|
|
21057
|
+
const line2 = descendant3(drawing, "ln");
|
|
21058
|
+
if (!line2) return null;
|
|
21059
|
+
const color = descendant3(line2, "srgbClr")?.attrs.val ?? "000000";
|
|
21060
|
+
const width = Math.max((parseInt(line2.attrs.w ?? "0", 10) || 0) / EMU_PER_PX4, 0.75);
|
|
21061
|
+
return { color: `#${color.toUpperCase()}`, width };
|
|
21062
|
+
}
|
|
21063
|
+
function setDrawingLineStyle(doc, drawing, color, widthPx) {
|
|
21064
|
+
const line2 = descendant3(drawing, "ln");
|
|
21065
|
+
if (!line2) return false;
|
|
21066
|
+
line2.attrs.w = String(Math.max(1, Math.round(widthPx * EMU_PER_PX4)));
|
|
21067
|
+
line2.children = line2.children.filter((child4) => {
|
|
21068
|
+
const name = localName(child4.name);
|
|
21069
|
+
return name !== "solidFill" && name !== "noFill";
|
|
21070
|
+
});
|
|
21071
|
+
line2.children.unshift(el6("a:solidFill", {}, [el6("a:srgbClr", { val: color.replace(/^#/, "").toUpperCase() })]));
|
|
21072
|
+
doc.refresh();
|
|
21073
|
+
return true;
|
|
21074
|
+
}
|
|
21075
|
+
function insertInkAt(doc, caretT, points, color = "#202124", widthPx = 2, opacity = 1, refreshModel = true) {
|
|
20542
21076
|
if (points.length < 2) return null;
|
|
20543
21077
|
const caretRun = doc.findParentOf(caretT);
|
|
20544
21078
|
const parent = caretRun && doc.findParentOf(caretRun);
|
|
@@ -20615,7 +21149,7 @@ function insertInkAt(doc, caretT, points, color = "#202124", widthPx = 2, opacit
|
|
|
20615
21149
|
])
|
|
20616
21150
|
]);
|
|
20617
21151
|
parent.children.splice(parent.children.indexOf(caretRun) + 1, 0, el6(`${w}r`, {}, [drawing]));
|
|
20618
|
-
doc.refresh();
|
|
21152
|
+
if (refreshModel) doc.refresh();
|
|
20619
21153
|
return drawing;
|
|
20620
21154
|
}
|
|
20621
21155
|
|
|
@@ -20946,6 +21480,111 @@ function deleteWatermark(doc, shapeEl) {
|
|
|
20946
21480
|
return true;
|
|
20947
21481
|
}
|
|
20948
21482
|
|
|
21483
|
+
// ../core/src/edit/dialog.ts
|
|
21484
|
+
var dialogSequence = 0;
|
|
21485
|
+
function requestTextInputDialog(anchor, options) {
|
|
21486
|
+
const doc = anchor.ownerDocument;
|
|
21487
|
+
const win = doc.defaultView;
|
|
21488
|
+
return new Promise((resolve) => {
|
|
21489
|
+
const id = `dxw-input-dialog-${++dialogSequence}`;
|
|
21490
|
+
const previousFocus = doc.activeElement instanceof HTMLElement ? doc.activeElement : null;
|
|
21491
|
+
const backdrop = doc.createElement("div");
|
|
21492
|
+
backdrop.className = "dxw-input-dialog-backdrop";
|
|
21493
|
+
backdrop.dataset.dxwInputDialog = "";
|
|
21494
|
+
backdrop.style.cssText = "position:fixed;inset:0;z-index:var(--dxw-dialog-z-index,1000);display:grid;place-items:center;padding:16px;box-sizing:border-box;background:var(--dxw-dialog-backdrop,rgba(32,33,36,.38));";
|
|
21495
|
+
if (win) {
|
|
21496
|
+
const computed = win.getComputedStyle(anchor);
|
|
21497
|
+
for (const property of [
|
|
21498
|
+
"--dxw-toolbar-fg",
|
|
21499
|
+
"--dxw-toolbar-border",
|
|
21500
|
+
"--dxw-toolbar-muted",
|
|
21501
|
+
"--dxw-accent",
|
|
21502
|
+
"--dxw-accent-fg",
|
|
21503
|
+
"--dxw-popover-bg",
|
|
21504
|
+
"--dxw-popover-shadow",
|
|
21505
|
+
"--dxw-dialog-backdrop",
|
|
21506
|
+
"--dxw-dialog-z-index",
|
|
21507
|
+
"--dxw-dialog-width",
|
|
21508
|
+
"--dxw-dialog-radius",
|
|
21509
|
+
"--dxw-dialog-field-bg"
|
|
21510
|
+
]) {
|
|
21511
|
+
const value = computed.getPropertyValue(property);
|
|
21512
|
+
if (value) backdrop.style.setProperty(property, value);
|
|
21513
|
+
}
|
|
21514
|
+
}
|
|
21515
|
+
const form = doc.createElement("form");
|
|
21516
|
+
form.className = "dxw-input-dialog";
|
|
21517
|
+
form.setAttribute("role", "dialog");
|
|
21518
|
+
form.setAttribute("aria-modal", "true");
|
|
21519
|
+
form.setAttribute("aria-labelledby", id);
|
|
21520
|
+
form.style.cssText = "width:min(var(--dxw-dialog-width,420px),calc(100vw - 32px));box-sizing:border-box;display:grid;gap:10px;padding:16px;border:1px solid var(--dxw-toolbar-border,#dadce0);border-radius:var(--dxw-dialog-radius,10px);color:var(--dxw-toolbar-fg,#3c4043);background:var(--dxw-popover-bg,#fff);box-shadow:var(--dxw-popover-shadow,0 8px 28px rgba(0,0,0,.24));font:13px system-ui,sans-serif;";
|
|
21521
|
+
const title = doc.createElement("strong");
|
|
21522
|
+
title.id = id;
|
|
21523
|
+
title.className = "dxw-input-dialog-title";
|
|
21524
|
+
title.textContent = options.title;
|
|
21525
|
+
title.style.cssText = "font-size:15px;line-height:1.35;";
|
|
21526
|
+
form.appendChild(title);
|
|
21527
|
+
const label = doc.createElement("label");
|
|
21528
|
+
label.className = "dxw-input-dialog-label";
|
|
21529
|
+
label.textContent = options.label ?? options.title;
|
|
21530
|
+
label.style.cssText = "display:grid;gap:5px;color:var(--dxw-toolbar-muted,#5f6368);font-size:12px;";
|
|
21531
|
+
const field = options.multiline ? doc.createElement("textarea") : doc.createElement("input");
|
|
21532
|
+
field.className = "dxw-input-dialog-field";
|
|
21533
|
+
field.value = options.value ?? "";
|
|
21534
|
+
field.placeholder = options.placeholder ?? "";
|
|
21535
|
+
field.setAttribute("aria-label", options.label ?? options.title);
|
|
21536
|
+
if (field instanceof HTMLTextAreaElement) field.rows = 4;
|
|
21537
|
+
field.style.cssText = "width:100%;min-height:34px;box-sizing:border-box;padding:7px 9px;border:1px solid var(--dxw-toolbar-border,#dadce0);border-radius:6px;outline:none;color:var(--dxw-toolbar-fg,#3c4043);background:var(--dxw-dialog-field-bg,var(--dxw-popover-bg,#fff));font:13px system-ui,sans-serif;resize:vertical;";
|
|
21538
|
+
label.appendChild(field);
|
|
21539
|
+
form.appendChild(label);
|
|
21540
|
+
const actions = doc.createElement("div");
|
|
21541
|
+
actions.className = "dxw-input-dialog-actions";
|
|
21542
|
+
actions.style.cssText = "display:flex;justify-content:flex-end;gap:7px;";
|
|
21543
|
+
const cancel = doc.createElement("button");
|
|
21544
|
+
cancel.type = "button";
|
|
21545
|
+
cancel.className = "dxw-input-dialog-cancel";
|
|
21546
|
+
cancel.textContent = "Cancel";
|
|
21547
|
+
cancel.style.cssText = "min-height:32px;padding:0 12px;border:1px solid var(--dxw-toolbar-border,#dadce0);border-radius:7px;color:var(--dxw-toolbar-fg,#3c4043);background:var(--dxw-popover-bg,#fff);cursor:pointer;font:600 12px system-ui,sans-serif;";
|
|
21548
|
+
const submit = doc.createElement("button");
|
|
21549
|
+
submit.type = "submit";
|
|
21550
|
+
submit.className = "dxw-input-dialog-submit";
|
|
21551
|
+
submit.textContent = options.submitLabel ?? "Apply";
|
|
21552
|
+
submit.style.cssText = "min-height:32px;padding:0 14px;border:1px solid transparent;border-radius:7px;color:var(--dxw-accent-fg,#fff);background:var(--dxw-accent,#1a73e8);cursor:pointer;font:600 12px system-ui,sans-serif;";
|
|
21553
|
+
actions.append(cancel, submit);
|
|
21554
|
+
form.appendChild(actions);
|
|
21555
|
+
backdrop.appendChild(form);
|
|
21556
|
+
doc.body.appendChild(backdrop);
|
|
21557
|
+
let finished = false;
|
|
21558
|
+
const finish = (value) => {
|
|
21559
|
+
if (finished) return;
|
|
21560
|
+
finished = true;
|
|
21561
|
+
doc.removeEventListener("keydown", onKeyDown, true);
|
|
21562
|
+
backdrop.remove();
|
|
21563
|
+
previousFocus?.focus({ preventScroll: true });
|
|
21564
|
+
resolve(value);
|
|
21565
|
+
};
|
|
21566
|
+
const onKeyDown = (event) => {
|
|
21567
|
+
if (event.key === "Escape") {
|
|
21568
|
+
event.preventDefault();
|
|
21569
|
+
finish(null);
|
|
21570
|
+
}
|
|
21571
|
+
};
|
|
21572
|
+
doc.addEventListener("keydown", onKeyDown, true);
|
|
21573
|
+
backdrop.addEventListener("mousedown", (event) => {
|
|
21574
|
+
if (event.target === backdrop) finish(null);
|
|
21575
|
+
});
|
|
21576
|
+
cancel.addEventListener("click", () => finish(null));
|
|
21577
|
+
form.addEventListener("submit", (event) => {
|
|
21578
|
+
event.preventDefault();
|
|
21579
|
+
finish(field.value);
|
|
21580
|
+
});
|
|
21581
|
+
requestAnimationFrame(() => {
|
|
21582
|
+
field.focus({ preventScroll: true });
|
|
21583
|
+
field.select();
|
|
21584
|
+
});
|
|
21585
|
+
});
|
|
21586
|
+
}
|
|
21587
|
+
|
|
20949
21588
|
// ../core/src/edit/grapheme.ts
|
|
20950
21589
|
var segmenter = null;
|
|
20951
21590
|
var segmenterTried = false;
|
|
@@ -21651,10 +22290,15 @@ var _DocxEditor = class _DocxEditor {
|
|
|
21651
22290
|
this.selection = null;
|
|
21652
22291
|
this.selectionRects = [];
|
|
21653
22292
|
this.selectedAll = false;
|
|
21654
|
-
/**
|
|
22293
|
+
/** Header/footer membership for hit-testing and caret movement. Rebuilt only
|
|
22294
|
+
* when refresh() replaces the parsed model; header/footer trees are tiny. */
|
|
22295
|
+
this.regionModelVersion = -1;
|
|
22296
|
+
this.headerFooterElements = /* @__PURE__ */ new WeakSet();
|
|
22297
|
+
/** A click-and-type placement in body whitespace has already recorded the undo
|
|
21655
22298
|
* snapshot that the following text insertion belongs to. */
|
|
21656
22299
|
this.pendingClickTypeCheckpoint = false;
|
|
21657
22300
|
this.clickTypeCheckpointUntil = 0;
|
|
22301
|
+
this.textContextMenu = null;
|
|
21658
22302
|
/** True while a drag-selection is in progress (checked by onMouseUp, which
|
|
21659
22303
|
* bubbles from the container BEFORE the document-level drag-end listener). */
|
|
21660
22304
|
this.dragSelecting = false;
|
|
@@ -22009,7 +22653,7 @@ var _DocxEditor = class _DocxEditor {
|
|
|
22009
22653
|
this.hfPage = null;
|
|
22010
22654
|
}
|
|
22011
22655
|
if (caret && region === "body" && !onGlyph && e.detail === 1 && !e.shiftKey) {
|
|
22012
|
-
caret = this.extendCaretBelowFloatingTable(caret, e.clientX, e.clientY) ?? caret;
|
|
22656
|
+
caret = this.extendCaretBelowFloatingTable(caret, e.clientX, e.clientY) ?? this.extendCaretIntoBodyWhitespace(caret, e.clientX, e.clientY) ?? caret;
|
|
22013
22657
|
}
|
|
22014
22658
|
if (caret && e.shiftKey) {
|
|
22015
22659
|
const anchor = this.anchorPoint();
|
|
@@ -22044,6 +22688,102 @@ var _DocxEditor = class _DocxEditor {
|
|
|
22044
22688
|
};
|
|
22045
22689
|
/** Which part tree the element lives in: document body or header/footer. */
|
|
22046
22690
|
this.mathEditorEl = null;
|
|
22691
|
+
this.dismissTextContextMenu = () => {
|
|
22692
|
+
this.textContextMenu?.remove();
|
|
22693
|
+
this.textContextMenu = null;
|
|
22694
|
+
document.removeEventListener("mousedown", this.onContextMenuDocumentMouseDown);
|
|
22695
|
+
};
|
|
22696
|
+
this.onContextMenuDocumentMouseDown = (event) => {
|
|
22697
|
+
if (!this.textContextMenu?.contains(event.target)) this.dismissTextContextMenu();
|
|
22698
|
+
};
|
|
22699
|
+
this.onContextMenu = (event) => {
|
|
22700
|
+
const target = event.target;
|
|
22701
|
+
if (!target?.closest('[data-dxw-item-kind="text"]')) return;
|
|
22702
|
+
const caret = this.caretFromPoint(event.clientX, event.clientY);
|
|
22703
|
+
if (!caret || this.regionOf(caret.t) === "hf" !== this.inHeaderFooter) return;
|
|
22704
|
+
event.preventDefault();
|
|
22705
|
+
event.stopPropagation();
|
|
22706
|
+
this.dismissTextContextMenu();
|
|
22707
|
+
if (!this.hasSelection()) {
|
|
22708
|
+
this.caret = caret;
|
|
22709
|
+
this.selectWordAt(caret);
|
|
22710
|
+
}
|
|
22711
|
+
const menu = document.createElement("div");
|
|
22712
|
+
menu.dataset.dxwTextContextMenu = "1";
|
|
22713
|
+
menu.setAttribute("role", "menu");
|
|
22714
|
+
menu.style.cssText = `position:fixed;left:${event.clientX}px;top:${event.clientY}px;z-index:2147483647;min-width:210px;padding:5px;background:#fff;border:1px solid #dadce0;border-radius:8px;box-shadow:0 4px 18px rgba(0,0,0,.2);font:13px system-ui,sans-serif;color:#202124;`;
|
|
22715
|
+
const isApplePlatform = /Mac|iPhone|iPad/.test(navigator.platform);
|
|
22716
|
+
const mod = isApplePlatform ? "\u2318" : "Ctrl+";
|
|
22717
|
+
const item = (label, shortcut, disabled, action) => {
|
|
22718
|
+
const button = document.createElement("button");
|
|
22719
|
+
button.type = "button";
|
|
22720
|
+
button.disabled = disabled;
|
|
22721
|
+
button.setAttribute("role", "menuitem");
|
|
22722
|
+
button.style.cssText = `display:flex;width:100%;align-items:center;justify-content:space-between;gap:24px;border:0;border-radius:5px;padding:7px 9px;background:transparent;color:${disabled ? "#9aa0a6" : "#202124"};cursor:${disabled ? "default" : "pointer"};`;
|
|
22723
|
+
const name = document.createElement("span");
|
|
22724
|
+
name.textContent = label;
|
|
22725
|
+
const keys = document.createElement("span");
|
|
22726
|
+
keys.textContent = shortcut;
|
|
22727
|
+
keys.style.color = "#5f6368";
|
|
22728
|
+
keys.style.fontSize = "11px";
|
|
22729
|
+
button.append(name, keys);
|
|
22730
|
+
button.addEventListener("mouseenter", () => {
|
|
22731
|
+
if (!button.disabled) button.style.background = "#f1f3f4";
|
|
22732
|
+
});
|
|
22733
|
+
button.addEventListener("mouseleave", () => {
|
|
22734
|
+
button.style.background = "transparent";
|
|
22735
|
+
});
|
|
22736
|
+
button.addEventListener("click", () => {
|
|
22737
|
+
if (button.disabled) return;
|
|
22738
|
+
this.dismissTextContextMenu();
|
|
22739
|
+
action();
|
|
22740
|
+
});
|
|
22741
|
+
menu.appendChild(button);
|
|
22742
|
+
};
|
|
22743
|
+
const separator = () => {
|
|
22744
|
+
const line2 = document.createElement("div");
|
|
22745
|
+
line2.style.cssText = "height:1px;background:#e8eaed;margin:4px 2px;";
|
|
22746
|
+
menu.appendChild(line2);
|
|
22747
|
+
};
|
|
22748
|
+
const selectedText = selectionTextLogical(this.host.doc, this.getSelectionSegments());
|
|
22749
|
+
const clipboard = navigator.clipboard;
|
|
22750
|
+
const copy = () => clipboard.writeText(selectedText);
|
|
22751
|
+
item("Copy", `${mod}C`, !selectedText || !clipboard?.writeText, () => void copy());
|
|
22752
|
+
item("Cut", `${mod}X`, !selectedText || !clipboard?.writeText, () => {
|
|
22753
|
+
void copy().then(() => {
|
|
22754
|
+
this.host.history?.checkpoint();
|
|
22755
|
+
this.removeSelectedText();
|
|
22756
|
+
this.commit();
|
|
22757
|
+
});
|
|
22758
|
+
});
|
|
22759
|
+
item("Paste", `${mod}V`, !clipboard?.readText, () => {
|
|
22760
|
+
void clipboard.readText().then((text) => {
|
|
22761
|
+
if (text) this.insertText(text);
|
|
22762
|
+
});
|
|
22763
|
+
});
|
|
22764
|
+
separator();
|
|
22765
|
+
item("Bold", `${mod}B`, !selectedText, () => this.host.onFormatShortcut?.("bold"));
|
|
22766
|
+
item("Italic", `${mod}I`, !selectedText, () => this.host.onFormatShortcut?.("italic"));
|
|
22767
|
+
item("Underline", `${mod}U`, !selectedText, () => this.host.onFormatShortcut?.("underline"));
|
|
22768
|
+
separator();
|
|
22769
|
+
item("Link\u2026", `${mod}K`, !selectedText, () => this.host.onTextCommand?.("link"));
|
|
22770
|
+
item("New comment\u2026", isApplePlatform ? "\u2318\u2325A" : "Ctrl+Alt+M", !selectedText, () => this.host.onTextCommand?.("comment"));
|
|
22771
|
+
item("Bulleted list", `${mod}Shift+L`, false, () => this.host.onTextCommand?.("bullet"));
|
|
22772
|
+
item("Numbered list", `${mod}Shift+7`, false, () => this.host.onTextCommand?.("number"));
|
|
22773
|
+
separator();
|
|
22774
|
+
item("Align left", `${mod}L`, false, () => this.host.onTextCommand?.("alignLeft"));
|
|
22775
|
+
item("Center", `${mod}E`, false, () => this.host.onTextCommand?.("alignCenter"));
|
|
22776
|
+
item("Align right", `${mod}R`, false, () => this.host.onTextCommand?.("alignRight"));
|
|
22777
|
+
item("Justify", `${mod}J`, false, () => this.host.onTextCommand?.("justify"));
|
|
22778
|
+
separator();
|
|
22779
|
+
item("Select all", `${mod}A`, false, () => this.selectAll());
|
|
22780
|
+
document.body.appendChild(menu);
|
|
22781
|
+
const rect = menu.getBoundingClientRect();
|
|
22782
|
+
menu.style.left = `${Math.max(6, Math.min(event.clientX, window.innerWidth - rect.width - 6))}px`;
|
|
22783
|
+
menu.style.top = `${Math.max(6, Math.min(event.clientY, window.innerHeight - rect.height - 6))}px`;
|
|
22784
|
+
this.textContextMenu = menu;
|
|
22785
|
+
setTimeout(() => document.addEventListener("mousedown", this.onContextMenuDocumentMouseDown), 0);
|
|
22786
|
+
};
|
|
22047
22787
|
// ---------- keyboard ----------
|
|
22048
22788
|
this.onKeyDown = (e) => {
|
|
22049
22789
|
if (this.composing || e.isComposing || e.keyCode === 229) return;
|
|
@@ -22051,6 +22791,11 @@ var _DocxEditor = class _DocxEditor {
|
|
|
22051
22791
|
this.pendingClickTypeCheckpoint = false;
|
|
22052
22792
|
this.clickTypeCheckpointUntil = 0;
|
|
22053
22793
|
}
|
|
22794
|
+
if (this.textContextMenu) {
|
|
22795
|
+
if (e.key === "Escape") e.preventDefault();
|
|
22796
|
+
this.dismissTextContextMenu();
|
|
22797
|
+
if (e.key === "Escape") return;
|
|
22798
|
+
}
|
|
22054
22799
|
if (e.key === "Escape" && this.drawingTool) {
|
|
22055
22800
|
e.preventDefault();
|
|
22056
22801
|
this.setDrawingTool(null);
|
|
@@ -22165,6 +22910,12 @@ var _DocxEditor = class _DocxEditor {
|
|
|
22165
22910
|
}
|
|
22166
22911
|
}
|
|
22167
22912
|
const meta = e.metaKey || e.ctrlKey;
|
|
22913
|
+
const isApplePlatform = /Mac|iPhone|iPad/.test(navigator.platform);
|
|
22914
|
+
if (isApplePlatform ? e.metaKey && e.altKey && e.key.toLowerCase() === "a" : e.ctrlKey && e.altKey && e.key.toLowerCase() === "m") {
|
|
22915
|
+
e.preventDefault();
|
|
22916
|
+
if (this.hasSelection()) this.host.onTextCommand?.("comment");
|
|
22917
|
+
return;
|
|
22918
|
+
}
|
|
22168
22919
|
if (meta && e.altKey && /^[0-6]$/.test(e.key)) {
|
|
22169
22920
|
e.preventDefault();
|
|
22170
22921
|
this.host.onStyleShortcut?.(e.key === "0" ? null : `Heading${e.key}`);
|
|
@@ -22184,14 +22935,36 @@ var _DocxEditor = class _DocxEditor {
|
|
|
22184
22935
|
}
|
|
22185
22936
|
return;
|
|
22186
22937
|
}
|
|
22187
|
-
if (e.
|
|
22938
|
+
if (!e.shiftKey && k === "k") {
|
|
22188
22939
|
e.preventDefault();
|
|
22189
|
-
|
|
22190
|
-
|
|
22191
|
-
|
|
22192
|
-
|
|
22193
|
-
|
|
22194
|
-
|
|
22940
|
+
if (this.hasSelection()) this.host.onTextCommand?.("link");
|
|
22941
|
+
return;
|
|
22942
|
+
}
|
|
22943
|
+
if (e.shiftKey && (k === "l" || k === "8")) {
|
|
22944
|
+
e.preventDefault();
|
|
22945
|
+
this.host.onTextCommand?.("bullet");
|
|
22946
|
+
return;
|
|
22947
|
+
}
|
|
22948
|
+
if (e.shiftKey && k === "7") {
|
|
22949
|
+
e.preventDefault();
|
|
22950
|
+
this.host.onTextCommand?.("number");
|
|
22951
|
+
return;
|
|
22952
|
+
}
|
|
22953
|
+
if (!e.shiftKey && (k === "l" || k === "e" || k === "r" || k === "j")) {
|
|
22954
|
+
e.preventDefault();
|
|
22955
|
+
this.host.onTextCommand?.(
|
|
22956
|
+
k === "l" ? "alignLeft" : k === "e" ? "alignCenter" : k === "r" ? "alignRight" : "justify"
|
|
22957
|
+
);
|
|
22958
|
+
return;
|
|
22959
|
+
}
|
|
22960
|
+
if (e.key.startsWith("Arrow")) {
|
|
22961
|
+
e.preventDefault();
|
|
22962
|
+
const extend = e.shiftKey;
|
|
22963
|
+
if (e.key === "ArrowLeft" || e.key === "ArrowRight") {
|
|
22964
|
+
this.moveFocus((pt) => this.lineEdgePoint(pt, e.key === "ArrowLeft" ? "start" : "end"), extend);
|
|
22965
|
+
} else {
|
|
22966
|
+
this.moveFocus((pt) => this.paragraphPoint(pt, e.key === "ArrowUp" ? -1 : 1), extend);
|
|
22967
|
+
}
|
|
22195
22968
|
this.revealCaret();
|
|
22196
22969
|
return;
|
|
22197
22970
|
}
|
|
@@ -22270,6 +23043,7 @@ var _DocxEditor = class _DocxEditor {
|
|
|
22270
23043
|
/** Focus the hidden text target (keeps IME working); falls back to the
|
|
22271
23044
|
* container if the textarea is not attached yet. */
|
|
22272
23045
|
focusText() {
|
|
23046
|
+
if (!this.imeEl.isConnected) this.host.container.appendChild(this.imeEl);
|
|
22273
23047
|
if (this.imeEl.isConnected) this.imeEl.focus({ preventScroll: true });
|
|
22274
23048
|
else this.host.container.focus({ preventScroll: true });
|
|
22275
23049
|
}
|
|
@@ -22278,6 +23052,14 @@ var _DocxEditor = class _DocxEditor {
|
|
|
22278
23052
|
this.applyHfChrome();
|
|
22279
23053
|
this.paintSelection();
|
|
22280
23054
|
this.positionCaret();
|
|
23055
|
+
if (this.caret || this.selection) this.focusText();
|
|
23056
|
+
}
|
|
23057
|
+
/** Repaint only state affected by virtualized page mounts. Scrolling keeps
|
|
23058
|
+
* the current focus and skips header/footer mode notifications in body mode. */
|
|
23059
|
+
afterViewportChange() {
|
|
23060
|
+
if (this.inHeaderFooter) this.applyHfChrome();
|
|
23061
|
+
if (this.selection) this.paintSelection();
|
|
23062
|
+
if (this.caret) this.positionCaret();
|
|
22281
23063
|
}
|
|
22282
23064
|
// ---------- owned selection ----------
|
|
22283
23065
|
hasSelection() {
|
|
@@ -22810,6 +23592,7 @@ var _DocxEditor = class _DocxEditor {
|
|
|
22810
23592
|
c.addEventListener("copy", this.onCopy);
|
|
22811
23593
|
c.addEventListener("cut", this.onCut);
|
|
22812
23594
|
c.addEventListener("paste", this.onPaste);
|
|
23595
|
+
c.addEventListener("contextmenu", this.onContextMenu);
|
|
22813
23596
|
c.addEventListener("dragover", this.onDragOver);
|
|
22814
23597
|
c.addEventListener("drop", this.onDrop);
|
|
22815
23598
|
this.applyHfChrome();
|
|
@@ -22829,8 +23612,10 @@ var _DocxEditor = class _DocxEditor {
|
|
|
22829
23612
|
c.removeEventListener("copy", this.onCopy);
|
|
22830
23613
|
c.removeEventListener("cut", this.onCut);
|
|
22831
23614
|
c.removeEventListener("paste", this.onPaste);
|
|
23615
|
+
c.removeEventListener("contextmenu", this.onContextMenu);
|
|
22832
23616
|
c.removeEventListener("dragover", this.onDragOver);
|
|
22833
23617
|
c.removeEventListener("drop", this.onDrop);
|
|
23618
|
+
this.dismissTextContextMenu();
|
|
22834
23619
|
this.dismissSuggestionPopover();
|
|
22835
23620
|
this.setDrawingTool(null);
|
|
22836
23621
|
this.deselectInkGroup();
|
|
@@ -23034,6 +23819,12 @@ var _DocxEditor = class _DocxEditor {
|
|
|
23034
23819
|
const page = target.closest?.(".dxw-page");
|
|
23035
23820
|
const surface = page?.firstElementChild;
|
|
23036
23821
|
if (!page || !surface || !surface.contains(target)) return false;
|
|
23822
|
+
const zoom = this.host.zoom ?? 1;
|
|
23823
|
+
const rect = surface.getBoundingClientRect();
|
|
23824
|
+
const localY = (e.clientY - rect.top) / zoom;
|
|
23825
|
+
const bodyTop = parseFloat(page.dataset.bodyTop ?? "0");
|
|
23826
|
+
const bodyBottom = parseFloat(page.dataset.bodyBottom ?? "0");
|
|
23827
|
+
if (localY < bodyTop || localY > bodyBottom) return false;
|
|
23037
23828
|
this.deselectInkGroup();
|
|
23038
23829
|
if (tool.kind === "eraser") return this.startInkEraser(e, page, tool.size);
|
|
23039
23830
|
if (tool.kind === "lasso") return this.startInkLasso(e, page, surface);
|
|
@@ -23043,8 +23834,6 @@ var _DocxEditor = class _DocxEditor {
|
|
|
23043
23834
|
this.deselectImage();
|
|
23044
23835
|
this.deselectWordArt();
|
|
23045
23836
|
this.hideCaret();
|
|
23046
|
-
const zoom = this.host.zoom ?? 1;
|
|
23047
|
-
const rect = surface.getBoundingClientRect();
|
|
23048
23837
|
const pointAt = (clientX, clientY) => ({
|
|
23049
23838
|
x: Math.max(0, Math.min((clientX - rect.left) / zoom, rect.width / zoom)),
|
|
23050
23839
|
y: Math.max(0, Math.min((clientY - rect.top) / zoom, rect.height / zoom))
|
|
@@ -23081,9 +23870,18 @@ var _DocxEditor = class _DocxEditor {
|
|
|
23081
23870
|
if (points.length < 2) return;
|
|
23082
23871
|
const anchor = this.nearestCaret(e.clientX, e.clientY, "body") ?? this.nearestCaret(up.clientX, up.clientY, "body");
|
|
23083
23872
|
if (!anchor) return;
|
|
23873
|
+
const paragraph = paragraphOf(this.host.doc, anchor.t);
|
|
23874
|
+
const dirtyBlock = topLevelBlockOf(this.host.doc, anchor.t) ?? paragraph ?? void 0;
|
|
23084
23875
|
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.
|
|
23876
|
+
if (insertInkAt(this.host.doc, anchor.t, points, tool.color, tool.width, tool.kind === "highlighter" ? 0.45 : 1, false)) {
|
|
23877
|
+
const reparsed = paragraph ? this.host.doc.reparseBodyParagraph(paragraph) : null;
|
|
23878
|
+
if (reparsed) {
|
|
23879
|
+
invalidateParagraphSignature(paragraph);
|
|
23880
|
+
this.host.rerender(dirtyBlock, "local", anchor.t);
|
|
23881
|
+
} else {
|
|
23882
|
+
this.host.doc.refresh();
|
|
23883
|
+
this.host.rerender(void 0, "global");
|
|
23884
|
+
}
|
|
23087
23885
|
}
|
|
23088
23886
|
};
|
|
23089
23887
|
document.addEventListener("mousemove", onMove);
|
|
@@ -23687,23 +24485,73 @@ var _DocxEditor = class _DocxEditor {
|
|
|
23687
24485
|
};
|
|
23688
24486
|
extra("Alt", "Alternative text", () => {
|
|
23689
24487
|
const cur = imageAltText(src);
|
|
23690
|
-
|
|
23691
|
-
|
|
23692
|
-
|
|
23693
|
-
|
|
23694
|
-
|
|
24488
|
+
void requestTextInputDialog(this.host.container, {
|
|
24489
|
+
title: "Alternative text",
|
|
24490
|
+
label: "Describe this object for screen readers",
|
|
24491
|
+
value: cur
|
|
24492
|
+
}).then((next) => {
|
|
24493
|
+
if (next === null) return;
|
|
24494
|
+
this.host.history?.checkpoint();
|
|
24495
|
+
if (setImageAltText(this.host.doc, src, next)) this.host.rerender();
|
|
24496
|
+
this.deselectImage();
|
|
24497
|
+
});
|
|
23695
24498
|
});
|
|
23696
24499
|
extra("Size", "Exact size (px)", () => {
|
|
23697
24500
|
const curW = parseFloat(el16.style.width) || 0;
|
|
23698
24501
|
const curH = parseFloat(el16.style.height) || 0;
|
|
23699
24502
|
const cur = `${Math.round(curW)}x${Math.round(curH)}`;
|
|
23700
|
-
|
|
23701
|
-
|
|
23702
|
-
|
|
23703
|
-
|
|
23704
|
-
|
|
23705
|
-
|
|
24503
|
+
void requestTextInputDialog(this.host.container, {
|
|
24504
|
+
title: "Exact size",
|
|
24505
|
+
label: "Width \xD7 height in pixels",
|
|
24506
|
+
value: cur,
|
|
24507
|
+
placeholder: "640 \xD7 360"
|
|
24508
|
+
}).then((next) => {
|
|
24509
|
+
const match = next && /^\s*(\d+)\s*[x×]\s*(\d+)\s*$/i.exec(next);
|
|
24510
|
+
if (!match) return;
|
|
24511
|
+
this.host.history?.checkpoint();
|
|
24512
|
+
if (resizeDrawing(this.host.doc, src, parseInt(match[1], 10), parseInt(match[2], 10))) this.host.rerender();
|
|
24513
|
+
this.deselectImage();
|
|
24514
|
+
});
|
|
24515
|
+
});
|
|
24516
|
+
extra("Position", "Exact page position (px)", () => {
|
|
24517
|
+
const curX = parseFloat(el16.style.left) || 0;
|
|
24518
|
+
const curY = parseFloat(el16.style.top) || 0;
|
|
24519
|
+
void requestTextInputDialog(this.host.container, {
|
|
24520
|
+
title: "Page position",
|
|
24521
|
+
label: "X, Y in pixels",
|
|
24522
|
+
value: `${Math.round(curX)}, ${Math.round(curY)}`,
|
|
24523
|
+
placeholder: "120, 80"
|
|
24524
|
+
}).then((next) => {
|
|
24525
|
+
const match = next && /^\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*$/.exec(next);
|
|
24526
|
+
if (!match) return;
|
|
24527
|
+
this.host.history?.checkpoint();
|
|
24528
|
+
if (!isFloatingDrawing(src)) setImageWrap(this.host.doc, src, "square", { x: 0, y: 0 });
|
|
24529
|
+
if (setFloatingPagePosition(this.host.doc, src, parseFloat(match[1]), parseFloat(match[2]))) {
|
|
24530
|
+
this.host.rerender();
|
|
24531
|
+
this.reselectImage(src);
|
|
24532
|
+
}
|
|
24533
|
+
});
|
|
23706
24534
|
});
|
|
24535
|
+
if (kind === "drawing") {
|
|
24536
|
+
extra("Outline", "Outline color and weight", () => {
|
|
24537
|
+
const style = drawingLineStyle(src);
|
|
24538
|
+
if (!style) return;
|
|
24539
|
+
void requestTextInputDialog(this.host.container, {
|
|
24540
|
+
title: "Outline",
|
|
24541
|
+
label: "Color and width in pixels",
|
|
24542
|
+
value: `${style.color}, ${Number(style.width.toFixed(2))}`,
|
|
24543
|
+
placeholder: "#1a73e8, 1.5"
|
|
24544
|
+
}).then((next) => {
|
|
24545
|
+
const match = next && /^\s*#?([0-9a-f]{6})\s*,\s*(\d+(?:\.\d+)?)\s*$/i.exec(next);
|
|
24546
|
+
if (!match) return;
|
|
24547
|
+
this.host.history?.checkpoint();
|
|
24548
|
+
if (setDrawingLineStyle(this.host.doc, src, `#${match[1]}`, parseFloat(match[2]))) {
|
|
24549
|
+
this.host.rerender();
|
|
24550
|
+
this.reselectImage(src);
|
|
24551
|
+
}
|
|
24552
|
+
});
|
|
24553
|
+
});
|
|
24554
|
+
}
|
|
23707
24555
|
if (kind === "drawing" && isDrawingWordArt(src)) {
|
|
23708
24556
|
extra("Edit text", "Edit WordArt text", () => this.editDrawingWordArt(src));
|
|
23709
24557
|
}
|
|
@@ -23857,13 +24705,17 @@ var _DocxEditor = class _DocxEditor {
|
|
|
23857
24705
|
};
|
|
23858
24706
|
button("Edit text", "Edit watermark text", () => {
|
|
23859
24707
|
const cur = wordArtText(src);
|
|
23860
|
-
|
|
23861
|
-
|
|
23862
|
-
|
|
23863
|
-
|
|
23864
|
-
|
|
23865
|
-
this.
|
|
23866
|
-
|
|
24708
|
+
void requestTextInputDialog(this.host.container, {
|
|
24709
|
+
title: "Watermark text",
|
|
24710
|
+
value: cur
|
|
24711
|
+
}).then((next) => {
|
|
24712
|
+
if (next === null || next === cur) return;
|
|
24713
|
+
this.host.history?.checkpoint();
|
|
24714
|
+
if (setWordArtText(this.host.doc, src, next)) {
|
|
24715
|
+
this.host.rerender();
|
|
24716
|
+
this.reselectWordArt(src);
|
|
24717
|
+
}
|
|
24718
|
+
});
|
|
23867
24719
|
});
|
|
23868
24720
|
const sep1 = document.createElement("span");
|
|
23869
24721
|
sep1.style.cssText = "width:1px;background:#dadce0;margin:2px 2px;";
|
|
@@ -23875,15 +24727,20 @@ var _DocxEditor = class _DocxEditor {
|
|
|
23875
24727
|
bar.appendChild(sep2);
|
|
23876
24728
|
button("Rotate", "Set rotation (degrees)", () => {
|
|
23877
24729
|
const cur = wordArtRotation(src);
|
|
23878
|
-
|
|
23879
|
-
|
|
23880
|
-
|
|
23881
|
-
|
|
23882
|
-
|
|
23883
|
-
|
|
23884
|
-
|
|
23885
|
-
|
|
23886
|
-
|
|
24730
|
+
void requestTextInputDialog(this.host.container, {
|
|
24731
|
+
title: "Watermark rotation",
|
|
24732
|
+
label: "Degrees clockwise",
|
|
24733
|
+
value: String(cur)
|
|
24734
|
+
}).then((next) => {
|
|
24735
|
+
if (next === null) return;
|
|
24736
|
+
const degrees = parseFloat(next);
|
|
24737
|
+
if (!Number.isFinite(degrees)) return;
|
|
24738
|
+
this.host.history?.checkpoint();
|
|
24739
|
+
if (setWordArtRotation(this.host.doc, src, degrees)) {
|
|
24740
|
+
this.host.rerender();
|
|
24741
|
+
this.reselectWordArt(src);
|
|
24742
|
+
}
|
|
24743
|
+
});
|
|
23887
24744
|
});
|
|
23888
24745
|
const sep3 = document.createElement("span");
|
|
23889
24746
|
sep3.style.cssText = "width:1px;background:#dadce0;margin:2px 2px;";
|
|
@@ -24518,14 +25375,19 @@ var _DocxEditor = class _DocxEditor {
|
|
|
24518
25375
|
return caretAt(t, 0);
|
|
24519
25376
|
}
|
|
24520
25377
|
regionOf(t) {
|
|
24521
|
-
|
|
24522
|
-
|
|
24523
|
-
|
|
24524
|
-
|
|
24525
|
-
|
|
25378
|
+
if (this.regionModelVersion !== this.host.doc.modelVersion) {
|
|
25379
|
+
this.headerFooterElements = /* @__PURE__ */ new WeakSet();
|
|
25380
|
+
const visit = (element) => {
|
|
25381
|
+
this.headerFooterElements.add(element);
|
|
25382
|
+
for (const child4 of element.children) visit(child4);
|
|
25383
|
+
};
|
|
25384
|
+
for (const root of this.host.doc.revisionRoots()) {
|
|
25385
|
+
const name = localName(root.name);
|
|
25386
|
+
if (name === "hdr" || name === "ftr") visit(root);
|
|
25387
|
+
}
|
|
25388
|
+
this.regionModelVersion = this.host.doc.modelVersion;
|
|
24526
25389
|
}
|
|
24527
|
-
|
|
24528
|
-
return ln === "hdr" || ln === "ftr" ? "hf" : "body";
|
|
25390
|
+
return this.headerFooterElements.has(t) ? "hf" : "body";
|
|
24529
25391
|
}
|
|
24530
25392
|
/**
|
|
24531
25393
|
* Snap to the closest character boundary on the clicked line — makes
|
|
@@ -24689,6 +25551,103 @@ var _DocxEditor = class _DocxEditor {
|
|
|
24689
25551
|
this.host.rerender(void 0, "global");
|
|
24690
25552
|
return caret;
|
|
24691
25553
|
}
|
|
25554
|
+
/** Word-style click-and-type: clicking below the final body line on a page
|
|
25555
|
+
* creates the intervening empty paragraphs so vertical arrows visit every
|
|
25556
|
+
* visible line instead of jumping across synthetic paragraph spacing. */
|
|
25557
|
+
extendCaretIntoBodyWhitespace(caret, x, y) {
|
|
25558
|
+
const handle = this.host.getHandle();
|
|
25559
|
+
const page = document.elementFromPoint(x, y)?.closest(".dxw-page");
|
|
25560
|
+
const surface = page?.firstElementChild;
|
|
25561
|
+
if (!handle || !page || !surface) return null;
|
|
25562
|
+
const rect = surface.getBoundingClientRect();
|
|
25563
|
+
const zoom = this.host.zoom ?? 1;
|
|
25564
|
+
const ly = (y - rect.top) / zoom;
|
|
25565
|
+
const bodyTop = parseFloat(page.dataset.bodyTop ?? "0");
|
|
25566
|
+
const bodyBottom = parseFloat(page.dataset.bodyBottom ?? "0");
|
|
25567
|
+
if (ly < bodyTop || ly > bodyBottom) return null;
|
|
25568
|
+
const paragraph = paragraphOf(this.host.doc, caret.t);
|
|
25569
|
+
const parent = paragraph ? this.host.doc.findParentOf(paragraph) : void 0;
|
|
25570
|
+
if (!paragraph || !parent || localName(parent.name) !== "body") return null;
|
|
25571
|
+
const endText = lastTextOf(paragraph);
|
|
25572
|
+
if (!endText) return null;
|
|
25573
|
+
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];
|
|
25574
|
+
if (!binding) return null;
|
|
25575
|
+
const lineHeight = Math.max(1, binding.item.lineHeight);
|
|
25576
|
+
if (ly <= binding.item.lineTop + lineHeight / 2) return null;
|
|
25577
|
+
const hasLaterLine = handle.bindings.some(
|
|
25578
|
+
(candidate) => candidate.el.parentElement === surface && candidate.item.src?.t && this.regionOf(candidate.item.src.t) === "body" && candidate.item.lineTop > binding.item.lineTop + lineHeight / 2
|
|
25579
|
+
);
|
|
25580
|
+
if (hasLaterLine) return null;
|
|
25581
|
+
const lineCount = Math.max(1, Math.round((ly - binding.item.lineTop) / lineHeight));
|
|
25582
|
+
this.host.history?.checkpoint();
|
|
25583
|
+
this.caret = {
|
|
25584
|
+
t: endText,
|
|
25585
|
+
run: binding.item.src.run,
|
|
25586
|
+
offset: endText.text.length,
|
|
25587
|
+
bias: endText.text.length > 0 ? "end" : void 0
|
|
25588
|
+
};
|
|
25589
|
+
const split = this.splitParagraphCore();
|
|
25590
|
+
if (!split) return null;
|
|
25591
|
+
const hasPageBreak = (element) => localName(element.name) === "br" && attr(element, "type") === "page" || element.children.some(hasPageBreak);
|
|
25592
|
+
const insertBeforeTrailingBreak = hasPageBreak(split.after);
|
|
25593
|
+
const afterSources = insertBeforeTrailingBreak ? [] : [split.after];
|
|
25594
|
+
const w = split.after.name.includes(":") ? split.after.name.slice(0, split.after.name.indexOf(":") + 1) : "";
|
|
25595
|
+
const templatePPr = split.after.children.find((child4) => localName(child4.name) === "pPr");
|
|
25596
|
+
const templateRun = split.after.children.find(
|
|
25597
|
+
(child4) => localName(child4.name) === "r" && child4.children.includes(this.caret.t)
|
|
25598
|
+
);
|
|
25599
|
+
const templateRPr = templateRun?.children.find((child4) => localName(child4.name) === "rPr");
|
|
25600
|
+
let previous = insertBeforeTrailingBreak ? split.before : split.after;
|
|
25601
|
+
let caretSource = split.after;
|
|
25602
|
+
for (let i = 1; i < lineCount; i++) {
|
|
25603
|
+
if (this.suggesting && previous !== split.before) markParagraphGlyph(previous, "ins", this.revMeta());
|
|
25604
|
+
const t = {
|
|
25605
|
+
name: this.caret.t.name,
|
|
25606
|
+
attrs: { ...this.caret.t.attrs, "xml:space": "preserve" },
|
|
25607
|
+
children: [],
|
|
25608
|
+
text: ""
|
|
25609
|
+
};
|
|
25610
|
+
const run = {
|
|
25611
|
+
name: templateRun?.name ?? `${w}r`,
|
|
25612
|
+
attrs: { ...templateRun?.attrs ?? {} },
|
|
25613
|
+
children: [...templateRPr ? [cloneXml(templateRPr)] : [], t],
|
|
25614
|
+
text: ""
|
|
25615
|
+
};
|
|
25616
|
+
const paragraph2 = {
|
|
25617
|
+
name: split.after.name,
|
|
25618
|
+
attrs: {},
|
|
25619
|
+
children: [...templatePPr ? [cloneXml(templatePPr)] : [], run],
|
|
25620
|
+
text: ""
|
|
25621
|
+
};
|
|
25622
|
+
const previousIndex = parent.children.indexOf(previous);
|
|
25623
|
+
parent.children.splice(previousIndex + 1, 0, paragraph2);
|
|
25624
|
+
afterSources.push(paragraph2);
|
|
25625
|
+
previous = paragraph2;
|
|
25626
|
+
caretSource = paragraph2;
|
|
25627
|
+
this.caret = { t, run: caret.run, offset: 0 };
|
|
25628
|
+
}
|
|
25629
|
+
if (insertBeforeTrailingBreak) afterSources.push(split.after);
|
|
25630
|
+
const reparsed = this.host.doc.reparseDirectBodyParagraphSplits(split.before, afterSources);
|
|
25631
|
+
if (reparsed) {
|
|
25632
|
+
const caretParagraph = reparsed[afterSources.indexOf(caretSource) + 1];
|
|
25633
|
+
for (const child4 of caretParagraph.children) {
|
|
25634
|
+
const runs = child4.type === "run" ? [child4] : child4.runs;
|
|
25635
|
+
const run = runs.find(
|
|
25636
|
+
(candidate) => candidate.content.some((content) => content.kind === "text" && content.srcT === this.caret.t)
|
|
25637
|
+
);
|
|
25638
|
+
if (run) {
|
|
25639
|
+
this.caret.run = run;
|
|
25640
|
+
break;
|
|
25641
|
+
}
|
|
25642
|
+
}
|
|
25643
|
+
invalidateParagraphSignature(split.before);
|
|
25644
|
+
for (const source of afterSources) invalidateParagraphSignature(source);
|
|
25645
|
+
}
|
|
25646
|
+
this.pendingClickTypeCheckpoint = true;
|
|
25647
|
+
this.commit(false, "local", !!reparsed);
|
|
25648
|
+
this.focusText();
|
|
25649
|
+
return this.caret;
|
|
25650
|
+
}
|
|
24692
25651
|
caretFromPoint(x, y) {
|
|
24693
25652
|
const doc = document;
|
|
24694
25653
|
let node = null;
|
|
@@ -24991,7 +25950,8 @@ var _DocxEditor = class _DocxEditor {
|
|
|
24991
25950
|
if (mergeParagraphBackward(this.host.doc, pEl)) {
|
|
24992
25951
|
const target = junction && paragraphOf(this.host.doc, junction) ? junction : caret.t;
|
|
24993
25952
|
this.caret = { t: target, run: caret.run, offset: target === junction ? target.text.length : 0 };
|
|
24994
|
-
this.
|
|
25953
|
+
invalidateParagraphSignature(paragraphOf(this.host.doc, target) ?? pEl);
|
|
25954
|
+
this.commit(false, "local", true);
|
|
24995
25955
|
}
|
|
24996
25956
|
return;
|
|
24997
25957
|
}
|
|
@@ -25011,7 +25971,10 @@ var _DocxEditor = class _DocxEditor {
|
|
|
25011
25971
|
const next = siblingParagraph(this.host.doc, pEl, 1);
|
|
25012
25972
|
if (!next) return;
|
|
25013
25973
|
this.host.history?.checkpoint();
|
|
25014
|
-
if (mergeParagraphBackward(this.host.doc, next))
|
|
25974
|
+
if (mergeParagraphBackward(this.host.doc, next)) {
|
|
25975
|
+
invalidateParagraphSignature(pEl);
|
|
25976
|
+
this.commit(false, "local", true);
|
|
25977
|
+
}
|
|
25015
25978
|
return;
|
|
25016
25979
|
}
|
|
25017
25980
|
if (!this.stepToNeighbor(1)) return;
|
|
@@ -25241,6 +26204,7 @@ var _DocxEditor = class _DocxEditor {
|
|
|
25241
26204
|
invalidateParagraphSignature(split.after);
|
|
25242
26205
|
}
|
|
25243
26206
|
this.commit(false, "local", !!reparsed);
|
|
26207
|
+
this.focusText();
|
|
25244
26208
|
}
|
|
25245
26209
|
/** Split the paragraph at the caret without history or commit — shared by
|
|
25246
26210
|
* Enter and multi-line paste. */
|
|
@@ -26983,7 +27947,8 @@ function detectMissingFonts(layout) {
|
|
|
26983
27947
|
for (const page of layout.pages) {
|
|
26984
27948
|
for (const item of page.items) {
|
|
26985
27949
|
if (item.kind !== "text" || !item.text.trim()) continue;
|
|
26986
|
-
const
|
|
27950
|
+
const requested = item.font.family.split(",")[0].trim().replace(/^"|"$/g, "");
|
|
27951
|
+
const primary = normalizeFamily(requested, item.font.bold, item.font.italic).family;
|
|
26987
27952
|
if (!primary || GENERIC.has(primary.toLowerCase())) continue;
|
|
26988
27953
|
const existing = samples.get(primary);
|
|
26989
27954
|
if (!existing || !/[^-ɏ]/.test(existing) && /[^-ɏ]/.test(item.text)) {
|
|
@@ -27115,15 +28080,6 @@ var btnStyle = (active) => ({
|
|
|
27115
28080
|
padding: "0 5px",
|
|
27116
28081
|
color: T.fg
|
|
27117
28082
|
});
|
|
27118
|
-
var selectStyle = {
|
|
27119
|
-
height: 26,
|
|
27120
|
-
border: "1px solid transparent",
|
|
27121
|
-
background: "transparent",
|
|
27122
|
-
borderRadius: 4,
|
|
27123
|
-
fontSize: 13,
|
|
27124
|
-
color: T.fg,
|
|
27125
|
-
cursor: "pointer"
|
|
27126
|
-
};
|
|
27127
28083
|
var PAGE_SIZES = [
|
|
27128
28084
|
{ value: "letter", label: "Letter", description: '8.5" \xD7 11"', width: 8.5, height: 11 },
|
|
27129
28085
|
{ value: "legal", label: "Legal", description: '8.5" \xD7 14"', width: 8.5, height: 14 },
|
|
@@ -27227,6 +28183,264 @@ function HighlightIcon({ color }) {
|
|
|
27227
28183
|
/* @__PURE__ */ jsx("rect", { x: "2", y: "13.5", width: "12", height: "2.5", rx: "0.5", fill: color })
|
|
27228
28184
|
] });
|
|
27229
28185
|
}
|
|
28186
|
+
function ToolbarMenuSelect({
|
|
28187
|
+
value,
|
|
28188
|
+
options,
|
|
28189
|
+
onChange,
|
|
28190
|
+
placeholder = "Choose\u2026",
|
|
28191
|
+
title,
|
|
28192
|
+
ariaLabel,
|
|
28193
|
+
triggerAriaLabel,
|
|
28194
|
+
width,
|
|
28195
|
+
menuWidth,
|
|
28196
|
+
className,
|
|
28197
|
+
style
|
|
28198
|
+
}) {
|
|
28199
|
+
const [open, setOpen] = useState(false);
|
|
28200
|
+
const [position, setPosition] = useState({ left: 8, top: 8, width: menuWidth ?? 180, maxHeight: 320 });
|
|
28201
|
+
const rootRef = useRef(null);
|
|
28202
|
+
const triggerRef = useRef(null);
|
|
28203
|
+
const menuRef = useRef(null);
|
|
28204
|
+
const keyboardOpen = useRef(null);
|
|
28205
|
+
const id = useId();
|
|
28206
|
+
const selected = options.find((option) => option.value === value);
|
|
28207
|
+
useLayoutEffect(() => {
|
|
28208
|
+
if (!open) return;
|
|
28209
|
+
const update = () => {
|
|
28210
|
+
const trigger = triggerRef.current;
|
|
28211
|
+
if (!trigger) return;
|
|
28212
|
+
const rect = trigger.getBoundingClientRect();
|
|
28213
|
+
const nextWidth = Math.min(
|
|
28214
|
+
window.innerWidth - 16,
|
|
28215
|
+
menuWidth ?? Math.max(rect.width, menuRef.current?.scrollWidth ?? 180)
|
|
28216
|
+
);
|
|
28217
|
+
const below = window.innerHeight - rect.bottom - 8;
|
|
28218
|
+
const above = rect.top - 8;
|
|
28219
|
+
const placeAbove = below < 140 && above > below;
|
|
28220
|
+
const maxHeight = Math.max(96, Math.min(320, placeAbove ? above : below));
|
|
28221
|
+
const shownHeight = Math.min(menuRef.current?.scrollHeight ?? maxHeight, maxHeight);
|
|
28222
|
+
setPosition({
|
|
28223
|
+
left: Math.max(8, Math.min(rect.left, window.innerWidth - nextWidth - 8)),
|
|
28224
|
+
top: placeAbove ? Math.max(8, rect.top - shownHeight - 4) : rect.bottom + 4,
|
|
28225
|
+
width: nextWidth,
|
|
28226
|
+
maxHeight
|
|
28227
|
+
});
|
|
28228
|
+
};
|
|
28229
|
+
update();
|
|
28230
|
+
const frame = requestAnimationFrame(() => {
|
|
28231
|
+
update();
|
|
28232
|
+
if (!keyboardOpen.current) return;
|
|
28233
|
+
const items = menuRef.current?.querySelectorAll('[role="option"]');
|
|
28234
|
+
const item = keyboardOpen.current === "last" ? items?.[items.length - 1] : items?.[0];
|
|
28235
|
+
item?.focus({ preventScroll: true });
|
|
28236
|
+
keyboardOpen.current = null;
|
|
28237
|
+
});
|
|
28238
|
+
const close = (event) => {
|
|
28239
|
+
if (!rootRef.current?.contains(event.target)) setOpen(false);
|
|
28240
|
+
};
|
|
28241
|
+
const keydown = (event) => {
|
|
28242
|
+
if (event.key === "Escape") {
|
|
28243
|
+
setOpen(false);
|
|
28244
|
+
requestAnimationFrame(() => triggerRef.current?.focus({ preventScroll: true }));
|
|
28245
|
+
}
|
|
28246
|
+
};
|
|
28247
|
+
document.addEventListener("mousedown", close);
|
|
28248
|
+
document.addEventListener("keydown", keydown);
|
|
28249
|
+
window.addEventListener("resize", update);
|
|
28250
|
+
window.addEventListener("scroll", update, true);
|
|
28251
|
+
return () => {
|
|
28252
|
+
cancelAnimationFrame(frame);
|
|
28253
|
+
document.removeEventListener("mousedown", close);
|
|
28254
|
+
document.removeEventListener("keydown", keydown);
|
|
28255
|
+
window.removeEventListener("resize", update);
|
|
28256
|
+
window.removeEventListener("scroll", update, true);
|
|
28257
|
+
};
|
|
28258
|
+
}, [open, menuWidth]);
|
|
28259
|
+
const pick = (next) => {
|
|
28260
|
+
const option = options.find((item) => item.value === next);
|
|
28261
|
+
if (!option || option.disabled) return;
|
|
28262
|
+
onChange(next);
|
|
28263
|
+
setOpen(false);
|
|
28264
|
+
};
|
|
28265
|
+
const onMenuKeyDown = (event) => {
|
|
28266
|
+
const items = menuRef.current ? Array.from(menuRef.current.querySelectorAll('[role="option"]:not(:disabled)')) : [];
|
|
28267
|
+
const current = items.indexOf(document.activeElement);
|
|
28268
|
+
let next = current;
|
|
28269
|
+
if (event.key === "ArrowDown") next = current < 0 ? 0 : (current + 1) % items.length;
|
|
28270
|
+
else if (event.key === "ArrowUp") next = current < 0 ? items.length - 1 : (current - 1 + items.length) % items.length;
|
|
28271
|
+
else if (event.key === "Home") next = 0;
|
|
28272
|
+
else if (event.key === "End") next = items.length - 1;
|
|
28273
|
+
else if ((event.key === "Enter" || event.key === " ") && current >= 0) {
|
|
28274
|
+
event.preventDefault();
|
|
28275
|
+
items[current].click();
|
|
28276
|
+
return;
|
|
28277
|
+
} else if (event.key === "Escape" || event.key === "Tab") {
|
|
28278
|
+
event.preventDefault();
|
|
28279
|
+
setOpen(false);
|
|
28280
|
+
requestAnimationFrame(() => triggerRef.current?.focus({ preventScroll: true }));
|
|
28281
|
+
return;
|
|
28282
|
+
} else return;
|
|
28283
|
+
event.preventDefault();
|
|
28284
|
+
items[next]?.focus({ preventScroll: true });
|
|
28285
|
+
};
|
|
28286
|
+
let previousGroup;
|
|
28287
|
+
return /* @__PURE__ */ jsxs(
|
|
28288
|
+
"span",
|
|
28289
|
+
{
|
|
28290
|
+
ref: rootRef,
|
|
28291
|
+
className: `dxw-menu-select${className ? ` ${className}` : ""}`,
|
|
28292
|
+
"data-dxw-menu-select": "",
|
|
28293
|
+
style: { position: "relative", display: "inline-flex", width },
|
|
28294
|
+
children: [
|
|
28295
|
+
/* @__PURE__ */ jsxs(
|
|
28296
|
+
"select",
|
|
28297
|
+
{
|
|
28298
|
+
tabIndex: -1,
|
|
28299
|
+
title,
|
|
28300
|
+
"aria-label": ariaLabel,
|
|
28301
|
+
"aria-hidden": "true",
|
|
28302
|
+
value,
|
|
28303
|
+
onChange: (event) => pick(event.target.value),
|
|
28304
|
+
"data-dxw-native-bridge": "",
|
|
28305
|
+
style: {
|
|
28306
|
+
position: "absolute",
|
|
28307
|
+
width: 1,
|
|
28308
|
+
height: 1,
|
|
28309
|
+
inset: 0,
|
|
28310
|
+
opacity: 0,
|
|
28311
|
+
pointerEvents: "none"
|
|
28312
|
+
},
|
|
28313
|
+
children: [
|
|
28314
|
+
!options.some((option) => option.value === value) && /* @__PURE__ */ jsx("option", { value: "", children: String(placeholder) }),
|
|
28315
|
+
options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, disabled: option.disabled, children: String(option.label) }, option.value))
|
|
28316
|
+
]
|
|
28317
|
+
}
|
|
28318
|
+
),
|
|
28319
|
+
/* @__PURE__ */ jsxs(
|
|
28320
|
+
"button",
|
|
28321
|
+
{
|
|
28322
|
+
ref: triggerRef,
|
|
28323
|
+
type: "button",
|
|
28324
|
+
"aria-haspopup": "listbox",
|
|
28325
|
+
"aria-expanded": open,
|
|
28326
|
+
"aria-controls": open ? id : void 0,
|
|
28327
|
+
"aria-label": triggerAriaLabel,
|
|
28328
|
+
"data-tip": title,
|
|
28329
|
+
className: "dxw-menu-select-trigger",
|
|
28330
|
+
"data-dxw-menu-select-trigger": "",
|
|
28331
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
28332
|
+
onClick: () => setOpen(!open),
|
|
28333
|
+
onKeyDown: (event) => {
|
|
28334
|
+
if (!open && (event.key === "Enter" || event.key === " " || event.key === "ArrowDown" || event.key === "ArrowUp")) {
|
|
28335
|
+
event.preventDefault();
|
|
28336
|
+
keyboardOpen.current = event.key === "ArrowUp" ? "last" : "first";
|
|
28337
|
+
setOpen(true);
|
|
28338
|
+
}
|
|
28339
|
+
},
|
|
28340
|
+
style: {
|
|
28341
|
+
width: "100%",
|
|
28342
|
+
minWidth: 0,
|
|
28343
|
+
height: "var(--dxw-select-height, 26px)",
|
|
28344
|
+
border: "1px solid var(--dxw-select-border, transparent)",
|
|
28345
|
+
borderRadius: "var(--dxw-select-radius, 4px)",
|
|
28346
|
+
background: "var(--dxw-select-bg, transparent)",
|
|
28347
|
+
color: "var(--dxw-select-fg, var(--dxw-toolbar-fg, #3c4043))",
|
|
28348
|
+
padding: "var(--dxw-select-padding, 0 6px)",
|
|
28349
|
+
display: "inline-flex",
|
|
28350
|
+
alignItems: "center",
|
|
28351
|
+
justifyContent: "space-between",
|
|
28352
|
+
gap: 6,
|
|
28353
|
+
cursor: "pointer",
|
|
28354
|
+
font: "var(--dxw-select-font, 13px system-ui, sans-serif)",
|
|
28355
|
+
...style
|
|
28356
|
+
},
|
|
28357
|
+
children: [
|
|
28358
|
+
/* @__PURE__ */ jsx("span", { style: { minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", fontFamily: selected?.fontFamily }, children: selected?.label ?? placeholder }),
|
|
28359
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "dxw-menu-select-chevron", style: { flexShrink: 0, fontSize: 10 }, children: "\u2304" })
|
|
28360
|
+
]
|
|
28361
|
+
}
|
|
28362
|
+
),
|
|
28363
|
+
open && /* @__PURE__ */ jsx(
|
|
28364
|
+
"div",
|
|
28365
|
+
{
|
|
28366
|
+
ref: menuRef,
|
|
28367
|
+
id,
|
|
28368
|
+
role: "listbox",
|
|
28369
|
+
"aria-label": ariaLabel ?? title,
|
|
28370
|
+
className: "dxw-menu-select-menu",
|
|
28371
|
+
"data-dxw-menu-select-menu": "",
|
|
28372
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
28373
|
+
onKeyDown: onMenuKeyDown,
|
|
28374
|
+
style: {
|
|
28375
|
+
position: "fixed",
|
|
28376
|
+
left: position.left,
|
|
28377
|
+
top: position.top,
|
|
28378
|
+
zIndex: "var(--dxw-toolbar-z-index, 100)",
|
|
28379
|
+
width: position.width,
|
|
28380
|
+
maxHeight: `min(var(--dxw-select-menu-max-height, 320px), ${position.maxHeight}px)`,
|
|
28381
|
+
overflowY: "auto",
|
|
28382
|
+
overscrollBehavior: "contain",
|
|
28383
|
+
boxSizing: "border-box",
|
|
28384
|
+
padding: "var(--dxw-select-menu-padding, 5px)",
|
|
28385
|
+
border: "1px solid var(--dxw-select-menu-border, var(--dxw-toolbar-border, #dadce0))",
|
|
28386
|
+
borderRadius: "var(--dxw-select-menu-radius, 8px)",
|
|
28387
|
+
background: "var(--dxw-select-menu-bg, var(--dxw-popover-bg, #fff))",
|
|
28388
|
+
boxShadow: "var(--dxw-select-menu-shadow, var(--dxw-popover-shadow, 0 4px 16px rgba(0,0,0,.15)))"
|
|
28389
|
+
},
|
|
28390
|
+
children: options.map((option) => {
|
|
28391
|
+
const groupChanged = option.group !== previousGroup;
|
|
28392
|
+
previousGroup = option.group;
|
|
28393
|
+
const active = option.value === value;
|
|
28394
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
28395
|
+
groupChanged && option.group && /* @__PURE__ */ jsx("div", { className: "dxw-menu-select-group", style: { padding: "6px 8px 3px", color: T.muted, font: "600 10.5px system-ui, sans-serif" }, children: option.group }),
|
|
28396
|
+
/* @__PURE__ */ jsxs(
|
|
28397
|
+
"button",
|
|
28398
|
+
{
|
|
28399
|
+
type: "button",
|
|
28400
|
+
role: "option",
|
|
28401
|
+
"aria-selected": active,
|
|
28402
|
+
disabled: option.disabled,
|
|
28403
|
+
tabIndex: -1,
|
|
28404
|
+
className: "dxw-menu-select-option",
|
|
28405
|
+
"data-dxw-menu-select-option": option.value,
|
|
28406
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
28407
|
+
onClick: () => pick(option.value),
|
|
28408
|
+
style: {
|
|
28409
|
+
width: "100%",
|
|
28410
|
+
minHeight: 30,
|
|
28411
|
+
border: 0,
|
|
28412
|
+
borderRadius: 6,
|
|
28413
|
+
padding: "5px 8px",
|
|
28414
|
+
display: "flex",
|
|
28415
|
+
alignItems: "center",
|
|
28416
|
+
gap: 8,
|
|
28417
|
+
background: active ? T.activeBg : "transparent",
|
|
28418
|
+
color: option.disabled ? T.muted : T.fg,
|
|
28419
|
+
textAlign: "left",
|
|
28420
|
+
cursor: option.disabled ? "default" : "pointer",
|
|
28421
|
+
font: "13px system-ui, sans-serif",
|
|
28422
|
+
fontFamily: option.fontFamily
|
|
28423
|
+
},
|
|
28424
|
+
onMouseEnter: (event) => {
|
|
28425
|
+
if (!active && !option.disabled) event.currentTarget.style.background = T.hoverBg;
|
|
28426
|
+
},
|
|
28427
|
+
onMouseLeave: (event) => {
|
|
28428
|
+
if (!active) event.currentTarget.style.background = "transparent";
|
|
28429
|
+
},
|
|
28430
|
+
children: [
|
|
28431
|
+
/* @__PURE__ */ jsx("span", { style: { flex: 1 }, children: option.label }),
|
|
28432
|
+
active && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { color: T.accent, fontWeight: 700 }, children: "\u2713" })
|
|
28433
|
+
]
|
|
28434
|
+
}
|
|
28435
|
+
)
|
|
28436
|
+
] }, option.value);
|
|
28437
|
+
})
|
|
28438
|
+
}
|
|
28439
|
+
)
|
|
28440
|
+
]
|
|
28441
|
+
}
|
|
28442
|
+
);
|
|
28443
|
+
}
|
|
27230
28444
|
function ActionMenu({
|
|
27231
28445
|
label,
|
|
27232
28446
|
title,
|
|
@@ -27234,22 +28448,21 @@ function ActionMenu({
|
|
|
27234
28448
|
onPick,
|
|
27235
28449
|
width
|
|
27236
28450
|
}) {
|
|
27237
|
-
return /* @__PURE__ */
|
|
27238
|
-
|
|
28451
|
+
return /* @__PURE__ */ jsx(
|
|
28452
|
+
ToolbarMenuSelect,
|
|
27239
28453
|
{
|
|
27240
28454
|
title,
|
|
28455
|
+
triggerAriaLabel: title,
|
|
27241
28456
|
value: "",
|
|
27242
|
-
|
|
27243
|
-
|
|
27244
|
-
|
|
27245
|
-
|
|
27246
|
-
|
|
27247
|
-
|
|
27248
|
-
|
|
27249
|
-
|
|
27250
|
-
|
|
27251
|
-
)
|
|
27252
|
-
]
|
|
28457
|
+
placeholder: label,
|
|
28458
|
+
width,
|
|
28459
|
+
menuWidth: Math.max(width ?? 0, 190),
|
|
28460
|
+
options: groups.flatMap((group) => group.items.map(([value, text]) => ({
|
|
28461
|
+
value,
|
|
28462
|
+
label: text,
|
|
28463
|
+
group: group.label
|
|
28464
|
+
}))),
|
|
28465
|
+
onChange: onPick
|
|
27253
28466
|
}
|
|
27254
28467
|
);
|
|
27255
28468
|
}
|
|
@@ -27329,6 +28542,183 @@ function HighlightMenu({ current, onPick }) {
|
|
|
27329
28542
|
)
|
|
27330
28543
|
] });
|
|
27331
28544
|
}
|
|
28545
|
+
var COLOR_SWATCHES = [
|
|
28546
|
+
"#000000",
|
|
28547
|
+
"#434343",
|
|
28548
|
+
"#666666",
|
|
28549
|
+
"#999999",
|
|
28550
|
+
"#b7b7b7",
|
|
28551
|
+
"#cccccc",
|
|
28552
|
+
"#d9d9d9",
|
|
28553
|
+
"#ffffff",
|
|
28554
|
+
"#980000",
|
|
28555
|
+
"#ff0000",
|
|
28556
|
+
"#ff9900",
|
|
28557
|
+
"#ffff00",
|
|
28558
|
+
"#00ff00",
|
|
28559
|
+
"#00ffff",
|
|
28560
|
+
"#4a86e8",
|
|
28561
|
+
"#0000ff",
|
|
28562
|
+
"#9900ff",
|
|
28563
|
+
"#ff00ff",
|
|
28564
|
+
"#e6b8af",
|
|
28565
|
+
"#f4cccc",
|
|
28566
|
+
"#fce5cd",
|
|
28567
|
+
"#fff2cc",
|
|
28568
|
+
"#d9ead3",
|
|
28569
|
+
"#d0e0e3",
|
|
28570
|
+
"#c9daf8",
|
|
28571
|
+
"#cfe2f3",
|
|
28572
|
+
"#d9d2e9",
|
|
28573
|
+
"#ead1dc",
|
|
28574
|
+
"#a61c00",
|
|
28575
|
+
"#cc0000",
|
|
28576
|
+
"#e69138",
|
|
28577
|
+
"#6aa84f"
|
|
28578
|
+
];
|
|
28579
|
+
function normalizedColor(value) {
|
|
28580
|
+
const match = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(value.trim());
|
|
28581
|
+
if (!match) return null;
|
|
28582
|
+
const digits = match[1].length === 3 ? match[1].split("").map((digit) => digit + digit).join("") : match[1];
|
|
28583
|
+
return `#${digits.toLowerCase()}`;
|
|
28584
|
+
}
|
|
28585
|
+
function ColorMenu({
|
|
28586
|
+
current,
|
|
28587
|
+
title,
|
|
28588
|
+
trigger,
|
|
28589
|
+
onPick
|
|
28590
|
+
}) {
|
|
28591
|
+
const [open, setOpen] = useState(false);
|
|
28592
|
+
const [custom, setCustom] = useState(current);
|
|
28593
|
+
const [position, setPosition] = useState({ left: 8, top: 8 });
|
|
28594
|
+
const rootRef = useRef(null);
|
|
28595
|
+
const triggerRef = useRef(null);
|
|
28596
|
+
const menuRef = useRef(null);
|
|
28597
|
+
const valid = normalizedColor(custom);
|
|
28598
|
+
useLayoutEffect(() => {
|
|
28599
|
+
if (!open) return;
|
|
28600
|
+
setCustom(current);
|
|
28601
|
+
const update = () => {
|
|
28602
|
+
const rect = triggerRef.current?.getBoundingClientRect();
|
|
28603
|
+
if (!rect) return;
|
|
28604
|
+
const width = Math.min(236, window.innerWidth - 16);
|
|
28605
|
+
const menuHeight = menuRef.current?.offsetHeight ?? 188;
|
|
28606
|
+
const top = window.innerHeight - rect.bottom >= menuHeight + 8 ? rect.bottom + 4 : Math.max(8, rect.top - menuHeight - 4);
|
|
28607
|
+
setPosition({ left: Math.max(8, Math.min(rect.left, window.innerWidth - width - 8)), top });
|
|
28608
|
+
};
|
|
28609
|
+
update();
|
|
28610
|
+
const frame = requestAnimationFrame(update);
|
|
28611
|
+
const close = (event) => {
|
|
28612
|
+
if (!rootRef.current?.contains(event.target)) setOpen(false);
|
|
28613
|
+
};
|
|
28614
|
+
const keydown = (event) => {
|
|
28615
|
+
if (event.key === "Escape") {
|
|
28616
|
+
setOpen(false);
|
|
28617
|
+
requestAnimationFrame(() => triggerRef.current?.focus({ preventScroll: true }));
|
|
28618
|
+
}
|
|
28619
|
+
};
|
|
28620
|
+
document.addEventListener("mousedown", close);
|
|
28621
|
+
document.addEventListener("keydown", keydown);
|
|
28622
|
+
window.addEventListener("resize", update);
|
|
28623
|
+
window.addEventListener("scroll", update, true);
|
|
28624
|
+
return () => {
|
|
28625
|
+
cancelAnimationFrame(frame);
|
|
28626
|
+
document.removeEventListener("mousedown", close);
|
|
28627
|
+
document.removeEventListener("keydown", keydown);
|
|
28628
|
+
window.removeEventListener("resize", update);
|
|
28629
|
+
window.removeEventListener("scroll", update, true);
|
|
28630
|
+
};
|
|
28631
|
+
}, [open, current]);
|
|
28632
|
+
const pick = (value) => {
|
|
28633
|
+
onPick(value);
|
|
28634
|
+
setOpen(false);
|
|
28635
|
+
};
|
|
28636
|
+
return /* @__PURE__ */ jsxs("span", { ref: rootRef, className: "dxw-color-control", style: { position: "relative", display: "inline-flex" }, children: [
|
|
28637
|
+
/* @__PURE__ */ jsx(
|
|
28638
|
+
"button",
|
|
28639
|
+
{
|
|
28640
|
+
ref: triggerRef,
|
|
28641
|
+
type: "button",
|
|
28642
|
+
title,
|
|
28643
|
+
"aria-haspopup": "dialog",
|
|
28644
|
+
"aria-expanded": open,
|
|
28645
|
+
className: "dxw-color-trigger",
|
|
28646
|
+
"data-dxw-color-trigger": "",
|
|
28647
|
+
style: { ...btnStyle(open), display: "inline-flex", alignItems: "center", gap: 5 },
|
|
28648
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
28649
|
+
onClick: () => setOpen(!open),
|
|
28650
|
+
children: trigger
|
|
28651
|
+
}
|
|
28652
|
+
),
|
|
28653
|
+
open && /* @__PURE__ */ jsxs(
|
|
28654
|
+
"div",
|
|
28655
|
+
{
|
|
28656
|
+
ref: menuRef,
|
|
28657
|
+
role: "dialog",
|
|
28658
|
+
"aria-label": title,
|
|
28659
|
+
className: "dxw-color-menu",
|
|
28660
|
+
"data-dxw-color-menu": "",
|
|
28661
|
+
onMouseDown: (event) => event.stopPropagation(),
|
|
28662
|
+
style: {
|
|
28663
|
+
position: "fixed",
|
|
28664
|
+
left: position.left,
|
|
28665
|
+
top: position.top,
|
|
28666
|
+
zIndex: "var(--dxw-toolbar-z-index, 100)",
|
|
28667
|
+
width: "min(var(--dxw-color-menu-width, 236px), calc(100vw - 16px))",
|
|
28668
|
+
boxSizing: "border-box",
|
|
28669
|
+
padding: 8,
|
|
28670
|
+
border: `1px solid ${T.border}`,
|
|
28671
|
+
borderRadius: 8,
|
|
28672
|
+
background: T.popoverBg,
|
|
28673
|
+
boxShadow: T.popoverShadow
|
|
28674
|
+
},
|
|
28675
|
+
children: [
|
|
28676
|
+
/* @__PURE__ */ jsx("div", { className: "dxw-color-swatches", style: { display: "grid", gridTemplateColumns: "repeat(8, 1fr)", gap: 4 }, children: COLOR_SWATCHES.map((color) => /* @__PURE__ */ jsx(
|
|
28677
|
+
"button",
|
|
28678
|
+
{
|
|
28679
|
+
type: "button",
|
|
28680
|
+
title: color,
|
|
28681
|
+
"aria-label": `Choose ${color}`,
|
|
28682
|
+
className: "dxw-color-swatch",
|
|
28683
|
+
"data-dxw-color": color,
|
|
28684
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
28685
|
+
onClick: () => pick(color),
|
|
28686
|
+
style: {
|
|
28687
|
+
width: 23,
|
|
28688
|
+
height: 23,
|
|
28689
|
+
padding: 0,
|
|
28690
|
+
borderRadius: 4,
|
|
28691
|
+
cursor: "pointer",
|
|
28692
|
+
border: color.toLowerCase() === current.toLowerCase() ? `2px solid ${T.accent}` : `1px solid ${T.border}`,
|
|
28693
|
+
background: color
|
|
28694
|
+
}
|
|
28695
|
+
},
|
|
28696
|
+
color
|
|
28697
|
+
)) }),
|
|
28698
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6, marginTop: 8 }, children: [
|
|
28699
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { width: 24, height: 24, borderRadius: 4, border: `1px solid ${T.border}`, background: valid ?? current, flexShrink: 0 } }),
|
|
28700
|
+
/* @__PURE__ */ jsx(
|
|
28701
|
+
"input",
|
|
28702
|
+
{
|
|
28703
|
+
"aria-label": "Custom hex color",
|
|
28704
|
+
className: "dxw-color-value",
|
|
28705
|
+
value: custom,
|
|
28706
|
+
onChange: (event) => setCustom(event.target.value),
|
|
28707
|
+
onKeyDown: (event) => {
|
|
28708
|
+
if (event.key === "Enter" && valid) pick(valid);
|
|
28709
|
+
},
|
|
28710
|
+
spellCheck: false,
|
|
28711
|
+
placeholder: "#1a73e8",
|
|
28712
|
+
style: { minWidth: 0, flex: 1, height: 28, boxSizing: "border-box", border: `1px solid ${T.border}`, borderRadius: 5, padding: "3px 6px", color: T.fg, background: T.popoverBg }
|
|
28713
|
+
}
|
|
28714
|
+
),
|
|
28715
|
+
/* @__PURE__ */ jsx("button", { type: "button", disabled: !valid, onClick: () => valid && pick(valid), style: pillBtn, children: "Apply" })
|
|
28716
|
+
] })
|
|
28717
|
+
]
|
|
28718
|
+
}
|
|
28719
|
+
)
|
|
28720
|
+
] });
|
|
28721
|
+
}
|
|
27332
28722
|
function BulletListIcon() {
|
|
27333
28723
|
return /* @__PURE__ */ jsxs("svg", { style: icon, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.4", children: [
|
|
27334
28724
|
/* @__PURE__ */ jsx("circle", { cx: "3", cy: "4", r: "1.1", fill: "currentColor", stroke: "none" }),
|
|
@@ -27691,7 +29081,18 @@ function CrossReferenceMenu({ api }) {
|
|
|
27691
29081
|
return /* @__PURE__ */ jsxs("span", { ref: rootRef, style: { position: "relative", display: "inline-block" }, children: [
|
|
27692
29082
|
/* @__PURE__ */ jsx("button", { title: "Insert cross-reference", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: () => setOpen(!open), children: "Cross-reference" }),
|
|
27693
29083
|
open && /* @__PURE__ */ jsx("div", { style: { position: "absolute", top: 28, left: 0, zIndex: 100, width: 260, padding: 10, background: T.popoverBg, border: `1px solid ${T.border}`, borderRadius: 8, boxShadow: T.popoverShadow }, children: bookmarks.length === 0 ? /* @__PURE__ */ jsx("div", { style: { color: T.muted, fontSize: 12 }, children: "Add a bookmark first, then reference its text or page." }) : /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
27694
|
-
/* @__PURE__ */ jsx(
|
|
29084
|
+
/* @__PURE__ */ jsx(
|
|
29085
|
+
ToolbarMenuSelect,
|
|
29086
|
+
{
|
|
29087
|
+
value: selected,
|
|
29088
|
+
ariaLabel: "Bookmark to reference",
|
|
29089
|
+
width: "100%",
|
|
29090
|
+
menuWidth: 240,
|
|
29091
|
+
options: bookmarks.map((name) => ({ value: name, label: name })),
|
|
29092
|
+
onChange: setBookmark,
|
|
29093
|
+
style: { borderColor: T.border }
|
|
29094
|
+
}
|
|
29095
|
+
),
|
|
27695
29096
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "flex-end", gap: 6, marginTop: 8 }, children: [
|
|
27696
29097
|
/* @__PURE__ */ jsx("button", { style: { ...pillBtn, background: T.popoverBg, color: T.fg }, onClick: () => insert("page"), children: "Page number" }),
|
|
27697
29098
|
/* @__PURE__ */ jsx("button", { style: pillBtn, onClick: () => insert("text"), children: "Bookmark text" })
|
|
@@ -27798,6 +29199,7 @@ function SymbolMenu({ api }) {
|
|
|
27798
29199
|
] });
|
|
27799
29200
|
}
|
|
27800
29201
|
var SHAPES = [
|
|
29202
|
+
["line", "Line", "\u2015"],
|
|
27801
29203
|
["rectangle", "Rectangle", "\u25AD"],
|
|
27802
29204
|
["roundedRectangle", "Rounded rectangle", "\u25A2"],
|
|
27803
29205
|
["ellipse", "Ellipse", "\u25EF"],
|
|
@@ -27969,12 +29371,23 @@ function ChartMenu({ api }) {
|
|
|
27969
29371
|
return /* @__PURE__ */ jsxs("span", { ref: rootRef, style: { position: "relative", display: "inline-block" }, children: [
|
|
27970
29372
|
/* @__PURE__ */ jsx("button", { title: "Insert or edit chart", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: () => setOpen(!open), children: "Chart" }),
|
|
27971
29373
|
open && /* @__PURE__ */ jsxs("div", { style: { position: "absolute", top: 28, right: 0, zIndex: 100, width: 320, padding: 10, display: "grid", gap: 7, background: T.popoverBg, border: `1px solid ${T.border}`, borderRadius: 8, boxShadow: T.popoverShadow }, children: [
|
|
27972
|
-
/* @__PURE__ */
|
|
27973
|
-
|
|
27974
|
-
|
|
27975
|
-
|
|
27976
|
-
|
|
27977
|
-
|
|
29374
|
+
/* @__PURE__ */ jsx(
|
|
29375
|
+
ToolbarMenuSelect,
|
|
29376
|
+
{
|
|
29377
|
+
value: type,
|
|
29378
|
+
ariaLabel: "Chart type",
|
|
29379
|
+
width: "100%",
|
|
29380
|
+
menuWidth: 300,
|
|
29381
|
+
options: [
|
|
29382
|
+
{ value: "column", label: "Column" },
|
|
29383
|
+
{ value: "bar", label: "Bar" },
|
|
29384
|
+
{ value: "line", label: "Line" },
|
|
29385
|
+
{ value: "pie", label: "Pie" }
|
|
29386
|
+
],
|
|
29387
|
+
onChange: (value) => setType(value),
|
|
29388
|
+
style: fieldStyle
|
|
29389
|
+
}
|
|
29390
|
+
),
|
|
27978
29391
|
/* @__PURE__ */ jsx("input", { "aria-label": "Chart title", value: title, onChange: (event) => setTitle(event.target.value), placeholder: "Chart title", style: fieldStyle }),
|
|
27979
29392
|
/* @__PURE__ */ jsx("input", { "aria-label": "Chart categories", value: categories, onChange: (event) => setCategories(event.target.value), placeholder: "Q1, Q2, Q3, Q4", style: fieldStyle }),
|
|
27980
29393
|
/* @__PURE__ */ jsx("textarea", { "aria-label": "Chart series", rows: 3, value: series, onChange: (event) => setSeries(event.target.value), style: { ...fieldStyle, resize: "vertical" } }),
|
|
@@ -28007,12 +29420,23 @@ function SmartArtMenu({ api }) {
|
|
|
28007
29420
|
return /* @__PURE__ */ jsxs("span", { ref: rootRef, style: { position: "relative", display: "inline-block" }, children: [
|
|
28008
29421
|
/* @__PURE__ */ jsx("button", { title: "Insert or edit SmartArt", style: btnStyle(open), onMouseDown: (event) => event.preventDefault(), onClick: () => setOpen(!open), children: "SmartArt" }),
|
|
28009
29422
|
open && /* @__PURE__ */ jsxs("div", { style: { position: "absolute", top: 28, right: 0, zIndex: 100, width: 280, padding: 10, display: "grid", gap: 7, background: T.popoverBg, border: `1px solid ${T.border}`, borderRadius: 8, boxShadow: T.popoverShadow }, children: [
|
|
28010
|
-
/* @__PURE__ */
|
|
28011
|
-
|
|
28012
|
-
|
|
28013
|
-
|
|
28014
|
-
|
|
28015
|
-
|
|
29423
|
+
/* @__PURE__ */ jsx(
|
|
29424
|
+
ToolbarMenuSelect,
|
|
29425
|
+
{
|
|
29426
|
+
value: layout,
|
|
29427
|
+
ariaLabel: "SmartArt layout",
|
|
29428
|
+
width: "100%",
|
|
29429
|
+
menuWidth: 260,
|
|
29430
|
+
options: [
|
|
29431
|
+
{ value: "process", label: "Process" },
|
|
29432
|
+
{ value: "cycle", label: "Cycle" },
|
|
29433
|
+
{ value: "hierarchy", label: "Hierarchy" },
|
|
29434
|
+
{ value: "list", label: "List" }
|
|
29435
|
+
],
|
|
29436
|
+
onChange: (value) => setLayout(value),
|
|
29437
|
+
style: fieldStyle
|
|
29438
|
+
}
|
|
29439
|
+
),
|
|
28016
29440
|
/* @__PURE__ */ jsx("textarea", { "aria-label": "SmartArt items", rows: 5, value: items, onChange: (event) => setItems(event.target.value), style: { ...fieldStyle, resize: "vertical" } }),
|
|
28017
29441
|
/* @__PURE__ */ jsx("div", { style: { color: T.muted, font: "11.5px system-ui, sans-serif" }, children: "One diagram item per line." }),
|
|
28018
29442
|
/* @__PURE__ */ jsx("button", { disabled: !items.trim(), onClick: submit, style: { border: 0, borderRadius: 6, padding: "7px 10px", background: items.trim() ? T.accent : T.border, color: T.accentFg, cursor: items.trim() ? "pointer" : "default", font: "600 12px system-ui, sans-serif" }, children: "Insert or update SmartArt" })
|
|
@@ -28070,19 +29494,18 @@ function DrawTab({ api }) {
|
|
|
28070
29494
|
/* @__PURE__ */ jsx(Btn, { label: "Eraser", title: "Stroke eraser", active: active === "eraser", onClick: () => api?.setDrawingTool({ kind: "eraser", size: 14 }) }),
|
|
28071
29495
|
/* @__PURE__ */ jsx(Btn, { label: "Lasso", title: "Lasso ink", active: active === "lasso", onClick: () => api?.setDrawingTool({ kind: "lasso" }) }),
|
|
28072
29496
|
/* @__PURE__ */ jsx(Sep, {}),
|
|
28073
|
-
/* @__PURE__ */
|
|
28074
|
-
|
|
28075
|
-
|
|
28076
|
-
|
|
28077
|
-
|
|
28078
|
-
|
|
28079
|
-
|
|
28080
|
-
|
|
28081
|
-
|
|
28082
|
-
|
|
28083
|
-
|
|
28084
|
-
|
|
28085
|
-
] }),
|
|
29497
|
+
/* @__PURE__ */ jsx(
|
|
29498
|
+
ColorMenu,
|
|
29499
|
+
{
|
|
29500
|
+
current: color,
|
|
29501
|
+
title: "Pen color",
|
|
29502
|
+
trigger: /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
29503
|
+
/* @__PURE__ */ jsx("span", { style: { font: "12px system-ui, sans-serif" }, children: "Color" }),
|
|
29504
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { width: 18, height: 18, borderRadius: 4, border: `1px solid ${T.border}`, background: color } })
|
|
29505
|
+
] }),
|
|
29506
|
+
onPick: (value) => activate(active === "highlighter" ? "highlighter" : "pen", value, width)
|
|
29507
|
+
}
|
|
29508
|
+
),
|
|
28086
29509
|
/* @__PURE__ */ jsx(
|
|
28087
29510
|
ActionMenu,
|
|
28088
29511
|
{
|
|
@@ -28660,9 +30083,8 @@ function MarginMenu({
|
|
|
28660
30083
|
"input",
|
|
28661
30084
|
{
|
|
28662
30085
|
"aria-label": `${label} margin (inches)`,
|
|
28663
|
-
type: "
|
|
28664
|
-
|
|
28665
|
-
step: "0.01",
|
|
30086
|
+
type: "text",
|
|
30087
|
+
inputMode: "decimal",
|
|
28666
30088
|
required: true,
|
|
28667
30089
|
autoFocus: side === "top",
|
|
28668
30090
|
value: values[side],
|
|
@@ -28787,9 +30209,8 @@ function PageSizeMenu({
|
|
|
28787
30209
|
"input",
|
|
28788
30210
|
{
|
|
28789
30211
|
"aria-label": `Page ${side} (inches)`,
|
|
28790
|
-
type: "
|
|
28791
|
-
|
|
28792
|
-
step: "0.01",
|
|
30212
|
+
type: "text",
|
|
30213
|
+
inputMode: "decimal",
|
|
28793
30214
|
required: true,
|
|
28794
30215
|
autoFocus: side === "width",
|
|
28795
30216
|
value: values[side],
|
|
@@ -28887,19 +30308,20 @@ function LayoutTab({ api, showArrange }) {
|
|
|
28887
30308
|
"data-dxw-layout-ribbon": "",
|
|
28888
30309
|
style: { display: "flex", flex: "1 1 640px", minWidth: 0, alignItems: "center", flexWrap: "wrap", gap: 2 },
|
|
28889
30310
|
children: [
|
|
28890
|
-
/* @__PURE__ */
|
|
28891
|
-
|
|
30311
|
+
/* @__PURE__ */ jsx(
|
|
30312
|
+
ToolbarMenuSelect,
|
|
28892
30313
|
{
|
|
28893
30314
|
title: "Apply layout changes to",
|
|
28894
|
-
|
|
30315
|
+
ariaLabel: "Apply layout changes to",
|
|
28895
30316
|
value: scope,
|
|
28896
|
-
|
|
28897
|
-
|
|
28898
|
-
|
|
28899
|
-
|
|
28900
|
-
|
|
28901
|
-
|
|
28902
|
-
|
|
30317
|
+
width: 118,
|
|
30318
|
+
menuWidth: 170,
|
|
30319
|
+
options: [
|
|
30320
|
+
{ value: "document", label: "Whole document" },
|
|
30321
|
+
{ value: "section", label: "This section" }
|
|
30322
|
+
],
|
|
30323
|
+
onChange: (value) => setScope(value),
|
|
30324
|
+
style: { maxWidth: "100%" }
|
|
28903
30325
|
}
|
|
28904
30326
|
),
|
|
28905
30327
|
/* @__PURE__ */ jsx(Sep, {}),
|
|
@@ -29126,42 +30548,44 @@ function DocxToolbar({
|
|
|
29126
30548
|
if (on("styles"))
|
|
29127
30549
|
groups.push({
|
|
29128
30550
|
key: "styles",
|
|
29129
|
-
node: /* @__PURE__ */
|
|
29130
|
-
|
|
30551
|
+
node: /* @__PURE__ */ jsx(
|
|
30552
|
+
ToolbarMenuSelect,
|
|
29131
30553
|
{
|
|
29132
30554
|
title: "Paragraph style",
|
|
29133
30555
|
value: curStyle ?? "__normal",
|
|
29134
|
-
|
|
29135
|
-
|
|
29136
|
-
|
|
29137
|
-
|
|
30556
|
+
width: 92,
|
|
30557
|
+
menuWidth: 190,
|
|
30558
|
+
options: [
|
|
30559
|
+
{ value: "__normal", label: "Normal" },
|
|
30560
|
+
...(api?.listParagraphStyles() ?? []).filter((style2) => !/^normal$/i.test(style2.name)).map((style2) => ({ value: style2.id, label: style2.name })),
|
|
30561
|
+
...curStyle !== null && !(api?.listParagraphStyles() ?? []).some((style2) => style2.id === curStyle) ? [{ value: curStyle, label: api?.document.styles.byId.get(curStyle)?.name ?? curStyle }] : []
|
|
30562
|
+
],
|
|
30563
|
+
onChange: (value) => {
|
|
30564
|
+
if (value) {
|
|
30565
|
+
api?.setParagraphStyle(value === "__normal" ? null : value);
|
|
29138
30566
|
setCurStyle(api?.getParagraphStyleId?.() ?? null);
|
|
29139
30567
|
}
|
|
29140
|
-
}
|
|
29141
|
-
style: { ...selectStyle, width: 92 },
|
|
29142
|
-
children: [
|
|
29143
|
-
/* @__PURE__ */ jsx("option", { value: "__normal", children: "Normal" }),
|
|
29144
|
-
(api?.listParagraphStyles() ?? []).filter((s) => !/^normal$/i.test(s.name)).map((s) => /* @__PURE__ */ jsx("option", { value: s.id, children: s.name }, s.id)),
|
|
29145
|
-
curStyle !== null && !(api?.listParagraphStyles() ?? []).some((s) => s.id === curStyle) && /* @__PURE__ */ jsx("option", { value: curStyle, children: api?.document.styles.byId.get(curStyle)?.name ?? curStyle })
|
|
29146
|
-
]
|
|
30568
|
+
}
|
|
29147
30569
|
}
|
|
29148
30570
|
)
|
|
29149
30571
|
});
|
|
29150
30572
|
if (on("font"))
|
|
29151
30573
|
groups.push({
|
|
29152
30574
|
key: "font",
|
|
29153
|
-
node: /* @__PURE__ */
|
|
29154
|
-
|
|
30575
|
+
node: /* @__PURE__ */ jsx(
|
|
30576
|
+
ToolbarMenuSelect,
|
|
29155
30577
|
{
|
|
29156
30578
|
title: "Font",
|
|
29157
30579
|
value: fmt?.fontFamily ?? "",
|
|
29158
|
-
|
|
29159
|
-
|
|
29160
|
-
|
|
29161
|
-
|
|
29162
|
-
|
|
29163
|
-
|
|
29164
|
-
|
|
30580
|
+
placeholder: "Font",
|
|
30581
|
+
width: 130,
|
|
30582
|
+
menuWidth: 210,
|
|
30583
|
+
options: (fmt?.fontFamily && !detectFonts().includes(fmt.fontFamily) ? [fmt.fontFamily, ...detectFonts()] : detectFonts()).map((font) => ({
|
|
30584
|
+
value: font,
|
|
30585
|
+
label: font,
|
|
30586
|
+
fontFamily: font
|
|
30587
|
+
})),
|
|
30588
|
+
onChange: (value) => value && apply({ fontFamily: value })
|
|
29165
30589
|
}
|
|
29166
30590
|
)
|
|
29167
30591
|
});
|
|
@@ -29169,18 +30593,16 @@ function DocxToolbar({
|
|
|
29169
30593
|
groups.push({
|
|
29170
30594
|
key: "size",
|
|
29171
30595
|
node: /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
29172
|
-
/* @__PURE__ */
|
|
29173
|
-
|
|
30596
|
+
/* @__PURE__ */ jsx(
|
|
30597
|
+
ToolbarMenuSelect,
|
|
29174
30598
|
{
|
|
29175
30599
|
title: "Font size",
|
|
29176
|
-
value: fmt?.fontSizePt
|
|
29177
|
-
|
|
29178
|
-
|
|
29179
|
-
|
|
29180
|
-
|
|
29181
|
-
|
|
29182
|
-
SIZES.map((s) => /* @__PURE__ */ jsx("option", { value: s, children: s }, s))
|
|
29183
|
-
]
|
|
30600
|
+
value: fmt?.fontSizePt === void 0 ? "" : String(fmt.fontSizePt),
|
|
30601
|
+
placeholder: "Size",
|
|
30602
|
+
width: 58,
|
|
30603
|
+
menuWidth: 92,
|
|
30604
|
+
options: SIZES.map((size) => ({ value: String(size), label: String(size) })),
|
|
30605
|
+
onChange: (value) => value && apply({ fontSizePt: parseFloat(value) })
|
|
29184
30606
|
}
|
|
29185
30607
|
),
|
|
29186
30608
|
/* @__PURE__ */ jsx(Sep, {})
|
|
@@ -29237,19 +30659,15 @@ function DocxToolbar({
|
|
|
29237
30659
|
if (on("color"))
|
|
29238
30660
|
groups.push({
|
|
29239
30661
|
key: "color",
|
|
29240
|
-
node: /* @__PURE__ */
|
|
29241
|
-
|
|
29242
|
-
|
|
29243
|
-
"
|
|
29244
|
-
|
|
29245
|
-
|
|
29246
|
-
|
|
29247
|
-
|
|
29248
|
-
|
|
29249
|
-
style: { width: 0, height: 0, opacity: 0, border: "none", padding: 0 }
|
|
29250
|
-
}
|
|
29251
|
-
)
|
|
29252
|
-
] })
|
|
30662
|
+
node: /* @__PURE__ */ jsx(
|
|
30663
|
+
ColorMenu,
|
|
30664
|
+
{
|
|
30665
|
+
current: fmt?.color && fmt.color !== "auto" ? fmt.color : "#000000",
|
|
30666
|
+
title: "Text color",
|
|
30667
|
+
trigger: /* @__PURE__ */ jsx("span", { style: { fontSize: 13, borderBottom: `3px solid ${fmt?.color && fmt.color !== "auto" ? fmt.color : "#000"}`, padding: "0 3px", color: T.fg }, children: "A" }),
|
|
30668
|
+
onPick: (value) => apply({ color: value })
|
|
30669
|
+
}
|
|
30670
|
+
)
|
|
29253
30671
|
});
|
|
29254
30672
|
if (on("highlight"))
|
|
29255
30673
|
groups.push({
|
|
@@ -29822,7 +31240,7 @@ function DocxView({
|
|
|
29822
31240
|
comments: showComments,
|
|
29823
31241
|
onDeleteComment,
|
|
29824
31242
|
onReplyComment,
|
|
29825
|
-
onViewportChange: () => editor?.
|
|
31243
|
+
onViewportChange: () => editor?.afterViewportChange()
|
|
29826
31244
|
}, prev ?? void 0);
|
|
29827
31245
|
container.scrollTop = scrollTop;
|
|
29828
31246
|
container.scrollLeft = scrollLeft;
|
|
@@ -29921,19 +31339,23 @@ function DocxView({
|
|
|
29921
31339
|
"Calibri",
|
|
29922
31340
|
"Calibri Light",
|
|
29923
31341
|
"Tahoma",
|
|
29924
|
-
"Franklin Gothic Medium"
|
|
29925
|
-
// Complex-script faces gate layout too (advances must be real
|
|
29926
|
-
// before line breaking): Mangal (Devanagari), Latha (Tamil),
|
|
29927
|
-
// Noto Sans Lao Looped (Lao — bundled OFL webfont).
|
|
29928
|
-
"Mangal",
|
|
29929
|
-
"Latha",
|
|
29930
|
-
"Noto Sans Lao Looped"
|
|
31342
|
+
"Franklin Gothic Medium"
|
|
29931
31343
|
];
|
|
29932
31344
|
for (const fam of latin) {
|
|
29933
31345
|
for (const variant of ["", "italic ", "bold ", "bold italic "]) {
|
|
29934
31346
|
loads.push(document.fonts.load(`${variant}16px "${fam}"`).catch(() => []));
|
|
29935
31347
|
}
|
|
29936
31348
|
}
|
|
31349
|
+
const complex = [
|
|
31350
|
+
["Mangal", "\u0905"],
|
|
31351
|
+
["Latha", "\u0B85"],
|
|
31352
|
+
["Noto Sans Lao Looped", "\u0E81"]
|
|
31353
|
+
];
|
|
31354
|
+
for (const [fam, sample] of complex) {
|
|
31355
|
+
for (const variant of ["", "bold "]) {
|
|
31356
|
+
loads.push(document.fonts.load(`${variant}16px "${fam}"`, sample).catch(() => []));
|
|
31357
|
+
}
|
|
31358
|
+
}
|
|
29937
31359
|
loads.push(document.fonts.load('16px "Cambria Math"').catch(() => []));
|
|
29938
31360
|
const cjk = [
|
|
29939
31361
|
"MS Mincho",
|
|
@@ -29949,7 +31371,7 @@ function DocxView({
|
|
|
29949
31371
|
];
|
|
29950
31372
|
for (const fam of cjk) {
|
|
29951
31373
|
for (const variant of ["", "bold "]) {
|
|
29952
|
-
loads.push(document.fonts.load(`${variant}16px "${fam}"
|
|
31374
|
+
loads.push(document.fonts.load(`${variant}16px "${fam}"`, "A\u6F22").catch(() => []));
|
|
29953
31375
|
}
|
|
29954
31376
|
}
|
|
29955
31377
|
await Promise.all(loads);
|
|
@@ -29996,7 +31418,39 @@ function DocxView({
|
|
|
29996
31418
|
else if (formatted.length > 0) editor?.selectRanges(formatted);
|
|
29997
31419
|
document.dispatchEvent(new CustomEvent("dxw-selection"));
|
|
29998
31420
|
},
|
|
29999
|
-
onStyleShortcut: (styleId) => applyStyleShortcut?.(styleId)
|
|
31421
|
+
onStyleShortcut: (styleId) => applyStyleShortcut?.(styleId),
|
|
31422
|
+
onTextCommand: (command) => {
|
|
31423
|
+
const current = apiRef.current;
|
|
31424
|
+
if (!current) return;
|
|
31425
|
+
if (command === "link") {
|
|
31426
|
+
const anchor = containerRef.current;
|
|
31427
|
+
if (!anchor) return;
|
|
31428
|
+
void requestTextInputDialog(anchor, {
|
|
31429
|
+
title: "Link address",
|
|
31430
|
+
label: "URL",
|
|
31431
|
+
value: current.getLinkAt() ?? "https://"
|
|
31432
|
+
}).then((next) => {
|
|
31433
|
+
if (next !== null) current.setLink(next.trim() || null);
|
|
31434
|
+
});
|
|
31435
|
+
} else if (command === "comment") {
|
|
31436
|
+
const anchor = containerRef.current;
|
|
31437
|
+
if (!anchor) return;
|
|
31438
|
+
void requestTextInputDialog(anchor, {
|
|
31439
|
+
title: "New comment",
|
|
31440
|
+
label: "Comment",
|
|
31441
|
+
submitLabel: "Comment",
|
|
31442
|
+
multiline: true
|
|
31443
|
+
}).then((text) => {
|
|
31444
|
+
if (text?.trim()) current.addComment(text.trim());
|
|
31445
|
+
});
|
|
31446
|
+
} else if (command === "bullet" || command === "number") {
|
|
31447
|
+
current.toggleList(command);
|
|
31448
|
+
} else {
|
|
31449
|
+
current.setAlignment(
|
|
31450
|
+
command === "alignLeft" ? "left" : command === "alignCenter" ? "center" : command === "alignRight" ? "right" : "justify"
|
|
31451
|
+
);
|
|
31452
|
+
}
|
|
31453
|
+
}
|
|
30000
31454
|
};
|
|
30001
31455
|
editor = new DocxEditor(editorConfig);
|
|
30002
31456
|
editor.attach();
|
|
@@ -30615,7 +32069,8 @@ function DocxView({
|
|
|
30615
32069
|
alignItems: "center"
|
|
30616
32070
|
},
|
|
30617
32071
|
children: [
|
|
30618
|
-
/* @__PURE__ */ jsx2("span", { style: { font: "600 11.5px system-ui, sans-serif", color: "#5f6368", padding: "0 4px" }, children: "Header & footer" }),
|
|
32072
|
+
/* @__PURE__ */ jsx2("span", { style: { font: "600 11.5px system-ui, sans-serif", color: "#5f6368", padding: "0 4px" }, children: "Header & footer \xB7 repeats on pages" }),
|
|
32073
|
+
hotBtn("Line", "Insert a reusable line in the repeating page layer", () => apiRef.current?.insertShape("line")),
|
|
30619
32074
|
hotBtn("Page number", "Insert a dynamic page number at the caret", () => apiRef.current?.insertPageNumber("page")),
|
|
30620
32075
|
hotBtn("Page X of Y", "Insert 'Page X of Y' at the caret", () => apiRef.current?.insertPageNumber("pageOfTotal")),
|
|
30621
32076
|
hotBtn("Close", "Return to the document body", () => {
|
|
@@ -30631,6 +32086,7 @@ export {
|
|
|
30631
32086
|
DocxDocument,
|
|
30632
32087
|
DocxToolbar,
|
|
30633
32088
|
DocxView,
|
|
32089
|
+
ToolbarMenuSelect,
|
|
30634
32090
|
layoutDocument,
|
|
30635
32091
|
printPages,
|
|
30636
32092
|
renderToDom
|