web-doc 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/office.js +4 -2
- package/dist/adapters/pdf.js +19 -8
- package/dist/edit/docx/engine.d.ts +9 -1
- package/dist/edit/docx/engine.js +22 -0
- package/dist/edit/docx/provider.d.ts +3 -1
- package/dist/edit/docx/provider.js +3 -0
- package/dist/edit/docx/session.d.ts +6 -2
- package/dist/edit/docx/session.js +7 -1
- package/dist/edit/docx/style.d.ts +1 -1
- package/dist/edit/docx/style.js +3 -2
- package/dist/edit/docx/types.d.ts +11 -1
- package/dist/edit/engine.d.ts +2 -1
- package/dist/edit/pdf/engine/document.d.ts +4 -2
- package/dist/edit/pdf/engine/document.js +115 -12
- package/dist/edit/pdf/engine/elements.d.ts +5 -1
- package/dist/edit/pdf/engine/elements.js +88 -6
- package/dist/edit/pdf/engine/existing-text.js +16 -61
- package/dist/edit/pdf/engine/fonts.d.ts +14 -0
- package/dist/edit/pdf/engine/fonts.js +114 -0
- package/dist/edit/pdf/engine/handler.js +2 -0
- package/dist/edit/pdf/engine/layout.js +1 -1
- package/dist/edit/pdf/engine/operations.d.ts +7 -1
- package/dist/edit/pdf/engine/paragraph-edit.d.ts +4 -0
- package/dist/edit/pdf/engine/paragraph-edit.js +331 -0
- package/dist/edit/pdf/engine/paragraph.d.ts +31 -0
- package/dist/edit/pdf/engine/paragraph.js +445 -0
- package/dist/edit/pdf/engine/pdfium.d.ts +3 -0
- package/dist/edit/pdf/engine/text-box.js +16 -3
- package/dist/edit/pdf/engine/text-font.js +2 -19
- package/dist/edit/pdf/engine/transform.js +14 -3
- package/dist/edit/pdf/provider.d.ts +3 -1
- package/dist/edit/pdf/provider.js +3 -0
- package/dist/edit/pdf/range-map.d.ts +2 -1
- package/dist/edit/pdf/range-map.js +38 -8
- package/dist/edit/pdf/schemas.d.ts +2 -0
- package/dist/edit/pdf/schemas.js +37 -0
- package/dist/edit/pdf/session.d.ts +3 -1
- package/dist/edit/pdf/session.js +35 -6
- package/dist/edit/pdf/types.d.ts +38 -8
- package/dist/edit/pptx/elements.d.ts +4 -1
- package/dist/edit/pptx/elements.js +35 -0
- package/dist/edit/pptx/engine.d.ts +5 -1
- package/dist/edit/pptx/engine.js +11 -0
- package/dist/edit/pptx/handler.js +8 -0
- package/dist/edit/pptx/provider.d.ts +3 -1
- package/dist/edit/pptx/provider.js +3 -0
- package/dist/edit/pptx/session.d.ts +6 -2
- package/dist/edit/pptx/session.js +7 -1
- package/dist/edit/pptx/types.d.ts +11 -1
- package/dist/edit/range-style.d.ts +24 -0
- package/dist/edit/range-style.js +46 -0
- package/dist/edit/session.js +5 -0
- package/dist/edit/types.d.ts +13 -0
- package/dist/viewport.js +11 -0
- package/dist/worker-protocol.d.ts +1 -1
- package/dist/workers/ooxml-edit-worker.js +90 -2
- package/dist/workers/pdf-edit-worker.js +2019 -1003
- package/package.json +1 -1
package/dist/edit/types.d.ts
CHANGED
|
@@ -214,6 +214,17 @@ export interface AssetOptions {
|
|
|
214
214
|
readonly mimeType?: string;
|
|
215
215
|
readonly signal?: AbortSignal;
|
|
216
216
|
}
|
|
217
|
+
/** A source text object incorporated into another logical text element. */
|
|
218
|
+
export interface TextAnchorMigration {
|
|
219
|
+
/** Zero-based operation in the applied batch, before its text replacement. */
|
|
220
|
+
readonly operationIndex: number;
|
|
221
|
+
readonly sourceElementId: string;
|
|
222
|
+
readonly targetElementId: string;
|
|
223
|
+
/** UTF-16 length retained from the source, excluding generated trailing whitespace. */
|
|
224
|
+
readonly sourceLength: number;
|
|
225
|
+
/** UTF-16 start of the source text in the target before the operation. */
|
|
226
|
+
readonly targetOffset: number;
|
|
227
|
+
}
|
|
217
228
|
export interface EditReceipt {
|
|
218
229
|
readonly sessionId: string;
|
|
219
230
|
/** `state.revision` after the call; unchanged for a dry run or a no-op. */
|
|
@@ -226,6 +237,8 @@ export interface EditReceipt {
|
|
|
226
237
|
readonly removedIds: readonly string[];
|
|
227
238
|
/** Old id → new id, when a format has to rename an element; absent for formats that never do. */
|
|
228
239
|
readonly remappedIds?: Readonly<Record<string, string>>;
|
|
240
|
+
/** Text anchors migrated by an apply (or preview); absent when none migrated. */
|
|
241
|
+
readonly textAnchorMigrations?: readonly TextAnchorMigration[];
|
|
229
242
|
/** Page indexes in the resulting document whose content may have changed; a superset. */
|
|
230
243
|
readonly changedPages: readonly number[];
|
|
231
244
|
readonly pageCount: number;
|
package/dist/viewport.js
CHANGED
|
@@ -155,6 +155,15 @@ export class ViewerViewport {
|
|
|
155
155
|
this.schedule();
|
|
156
156
|
}
|
|
157
157
|
replaceDocument(info, changedPages, revision) {
|
|
158
|
+
// The viewer retires the old adapter after this synchronous handoff.
|
|
159
|
+
// Unfinished paints still belong to that adapter, even on unchanged pages.
|
|
160
|
+
for (const slot of this.#slots.values()) {
|
|
161
|
+
if (!slot.controller)
|
|
162
|
+
continue;
|
|
163
|
+
slot.controller.abort();
|
|
164
|
+
delete slot.controller;
|
|
165
|
+
delete slot.renderKey;
|
|
166
|
+
}
|
|
158
167
|
const previous = this.#info;
|
|
159
168
|
const painted = this.#painted.get(this.#contentRevision);
|
|
160
169
|
this.#painted.clear();
|
|
@@ -533,6 +542,8 @@ export class ViewerViewport {
|
|
|
533
542
|
await rendering?.catch(() => undefined);
|
|
534
543
|
canvas.width = 0;
|
|
535
544
|
canvas.height = 0;
|
|
545
|
+
if (slot.controller === controller)
|
|
546
|
+
delete slot.controller;
|
|
536
547
|
}
|
|
537
548
|
}
|
|
538
549
|
async #buildTextLayers(textLayer, highlightLayer, pageIndex, runs, zoom, signal) {
|
|
@@ -2,7 +2,7 @@ import type { DocumentFormat, DocumentInfo, ResourceLimits, TextRun, ViewerError
|
|
|
2
2
|
import type { EditableFormat } from "./edit/types.js";
|
|
3
3
|
export type DocumentWorkerOperation = "init" | "open" | "get-info" | "render" | "get-text-map" | "close" | "destroy";
|
|
4
4
|
/** Operations of an edit engine worker; payloads mirror the engine interface. */
|
|
5
|
-
export type EditWorkerOperation = "edit-init" | "edit-open" | "edit-validate" | "edit-apply" | "edit-materialize" | "edit-restore" | "edit-put-asset" | "edit-elements" | "edit-element" | "edit-elements-at" | "edit-find-text" | "edit-text-layout" | "edit-text-font" | "edit-position-at" | "edit-range-rects" | "edit-render-without" | "edit-page-layout" | "edit-pptx-slides" | "edit-pptx-layouts" | "edit-docx-revisions" | "edit-dispose";
|
|
5
|
+
export type EditWorkerOperation = "edit-init" | "edit-open" | "edit-validate" | "edit-apply" | "edit-materialize" | "edit-restore" | "edit-put-asset" | "edit-elements" | "edit-element" | "edit-elements-at" | "edit-find-text" | "edit-text-layout" | "edit-text-paragraph" | "edit-text-font" | "edit-position-at" | "edit-range-rects" | "edit-render-without" | "edit-page-layout" | "edit-pptx-slides" | "edit-pptx-layouts" | "edit-docx-revisions" | "edit-docx-text-style" | "edit-pptx-text-style" | "edit-dispose";
|
|
6
6
|
export type WorkerOperation = DocumentWorkerOperation | EditWorkerOperation;
|
|
7
7
|
export interface WorkerRequest {
|
|
8
8
|
readonly kind: "request";
|
|
@@ -2166,11 +2166,12 @@ var DocxStyles = class _DocxStyles {
|
|
|
2166
2166
|
node.children.find((child) => child.local === "basedOn") ?? node,
|
|
2167
2167
|
"w:val"
|
|
2168
2168
|
);
|
|
2169
|
+
const defaultAttribute = part.attribute(node, "w:default");
|
|
2169
2170
|
const record = {
|
|
2170
2171
|
id,
|
|
2171
2172
|
type: part.attribute(node, "w:type") ?? "paragraph",
|
|
2172
2173
|
...basedOn && basedOn !== id ? { basedOn } : {},
|
|
2173
|
-
isDefault: isOn(
|
|
2174
|
+
isDefault: defaultAttribute !== void 0 && isOn(defaultAttribute),
|
|
2174
2175
|
...pick(node, "rPr", "pPr")
|
|
2175
2176
|
};
|
|
2176
2177
|
styles.set(id, record);
|
|
@@ -5329,6 +5330,31 @@ function issueCollector(operationIndex, issues) {
|
|
|
5329
5330
|
return (path, code, message) => issues.push({ operationIndex, path, code, message });
|
|
5330
5331
|
}
|
|
5331
5332
|
|
|
5333
|
+
// src/edit/range-style.ts
|
|
5334
|
+
function runsCovering(runs, span) {
|
|
5335
|
+
if (span.start < span.end)
|
|
5336
|
+
return runs.filter((run2) => run2.start < span.end && run2.end > span.start);
|
|
5337
|
+
const before = runs.filter((run2) => run2.start < span.start && run2.end >= span.start).at(-1);
|
|
5338
|
+
const at = before ?? runs.find((run2) => run2.start >= span.start);
|
|
5339
|
+
return at ? [at] : [];
|
|
5340
|
+
}
|
|
5341
|
+
function sharedStyle(styles) {
|
|
5342
|
+
const [first, ...rest] = styles;
|
|
5343
|
+
if (!first) return void 0;
|
|
5344
|
+
const shared = {};
|
|
5345
|
+
for (const key of Object.keys(first)) {
|
|
5346
|
+
const value = JSON.stringify(first[key]);
|
|
5347
|
+
if (rest.every(
|
|
5348
|
+
(style) => key in style && JSON.stringify(style[key]) === value
|
|
5349
|
+
))
|
|
5350
|
+
shared[key] = first[key];
|
|
5351
|
+
}
|
|
5352
|
+
return shared;
|
|
5353
|
+
}
|
|
5354
|
+
function spanFits(span, length) {
|
|
5355
|
+
return span.start >= 0 && span.start <= span.end && span.end <= length;
|
|
5356
|
+
}
|
|
5357
|
+
|
|
5332
5358
|
// src/edit/docx/engine.ts
|
|
5333
5359
|
var UNAUTHORED_PART = "/webdoc/unauthored.xml";
|
|
5334
5360
|
var UNAUTHORED_NS = "urn:web-doc:docx-edit";
|
|
@@ -5602,6 +5628,26 @@ var DocxEditEngine = class _DocxEditEngine {
|
|
|
5602
5628
|
if (!record || record.kind !== "paragraph") return [];
|
|
5603
5629
|
return revisionsOf(model.document, record.node);
|
|
5604
5630
|
}
|
|
5631
|
+
/**
|
|
5632
|
+
* The style a span of a paragraph shows: what every run it covers shares;
|
|
5633
|
+
* the paragraph mark's for an empty paragraph. None for another element,
|
|
5634
|
+
* an unknown id or a span past the text.
|
|
5635
|
+
*/
|
|
5636
|
+
async textStyle(id, span, signal) {
|
|
5637
|
+
const model = await this.model(signal);
|
|
5638
|
+
const record = model.byId.get(id);
|
|
5639
|
+
if (!record || record.kind !== "paragraph") return void 0;
|
|
5640
|
+
const { text, items } = record.text;
|
|
5641
|
+
const range = span ?? { start: 0, end: text.length };
|
|
5642
|
+
if (!spanFits(range, text.length)) return void 0;
|
|
5643
|
+
const covered = runsCovering(items, range);
|
|
5644
|
+
const mark = record.pPr?.children.find((child) => child.local === "rPr");
|
|
5645
|
+
return sharedStyle(
|
|
5646
|
+
covered.length > 0 ? covered.map(
|
|
5647
|
+
(item) => resolveTextStyle(model.styles, record.pPr, item.rPr)
|
|
5648
|
+
) : [resolveTextStyle(model.styles, record.pPr, mark)]
|
|
5649
|
+
);
|
|
5650
|
+
}
|
|
5605
5651
|
async materialize(purposeOrSignal = "show", options = {}, signal = new AbortController().signal) {
|
|
5606
5652
|
return (await this.materializeDocument(purposeOrSignal, options, signal)).bytes;
|
|
5607
5653
|
}
|
|
@@ -6469,7 +6515,10 @@ function readRecord(context, node, parents, parent, readOnly, walk) {
|
|
|
6469
6515
|
...spPr ? { spPr } : {},
|
|
6470
6516
|
...text ? { text } : {},
|
|
6471
6517
|
readOnly,
|
|
6472
|
-
...parent ? { parent } : {}
|
|
6518
|
+
...parent ? { parent } : {},
|
|
6519
|
+
...text && txBody ? {
|
|
6520
|
+
styleOf: (span) => rangeStyleOf(context, placeholder, txBody, text, span)
|
|
6521
|
+
} : {}
|
|
6473
6522
|
};
|
|
6474
6523
|
}
|
|
6475
6524
|
function operationsFor(kind, hasText) {
|
|
@@ -6513,6 +6562,29 @@ function listStylesOf(context, txBody, placeholder) {
|
|
|
6513
6562
|
if (defaults) lists.push(defaults);
|
|
6514
6563
|
return lists;
|
|
6515
6564
|
}
|
|
6565
|
+
function rangeStyleOf(context, placeholder, txBody, text, span) {
|
|
6566
|
+
const lists = listStylesOf(context, txBody, placeholder);
|
|
6567
|
+
const styleOf = (paragraph2, rPr) => resolveTextStyle2({
|
|
6568
|
+
...rPr ? { rPr: { part: context.part, node: rPr } } : {},
|
|
6569
|
+
...paragraph2.pPr ? { pPr: { part: context.part, node: paragraph2.pPr } } : {},
|
|
6570
|
+
level: paragraph2.level,
|
|
6571
|
+
lists,
|
|
6572
|
+
fonts: context.fonts
|
|
6573
|
+
});
|
|
6574
|
+
const runs = text.paragraphs.flatMap(
|
|
6575
|
+
(paragraph2) => paragraph2.runs.map((run2) => ({
|
|
6576
|
+
start: run2.start,
|
|
6577
|
+
end: run2.end,
|
|
6578
|
+
style: () => styleOf(paragraph2, run2.rPr)
|
|
6579
|
+
}))
|
|
6580
|
+
);
|
|
6581
|
+
const covered = runsCovering(runs, span);
|
|
6582
|
+
if (covered.length > 0) return sharedStyle(covered.map((run2) => run2.style()));
|
|
6583
|
+
const paragraph = text.paragraphs.find(
|
|
6584
|
+
(candidate) => candidate.start <= span.start && span.start <= candidate.end
|
|
6585
|
+
) ?? text.paragraphs[0];
|
|
6586
|
+
return paragraph ? sharedStyle([styleOf(paragraph, paragraph.endParaRPr)]) : void 0;
|
|
6587
|
+
}
|
|
6516
6588
|
function textStyleOf(context, placeholder, txBody, text) {
|
|
6517
6589
|
const first = firstTextRun(text);
|
|
6518
6590
|
const paragraph = first?.paragraph ?? text.paragraphs[0];
|
|
@@ -8918,6 +8990,14 @@ var PptxEditEngine = class _PptxEditEngine {
|
|
|
8918
8990
|
});
|
|
8919
8991
|
return out;
|
|
8920
8992
|
}
|
|
8993
|
+
/** The style a span of a shape's text shows; none for an element without text or a span past it. */
|
|
8994
|
+
async textStyle(id, span, signal) {
|
|
8995
|
+
const record = await this.#locate(id, signal);
|
|
8996
|
+
if (!record?.styleOf || !record.text) return void 0;
|
|
8997
|
+
const range = span ?? { start: 0, end: record.text.text.length };
|
|
8998
|
+
if (!spanFits(range, record.text.text.length)) return void 0;
|
|
8999
|
+
return record.styleOf(range);
|
|
9000
|
+
}
|
|
8921
9001
|
async layouts(signal) {
|
|
8922
9002
|
const model = await this.model(signal);
|
|
8923
9003
|
return model.layouts.map((layout) => ({
|
|
@@ -9136,6 +9216,14 @@ function createOoxmlEditHandler() {
|
|
|
9136
9216
|
payload.id,
|
|
9137
9217
|
signal
|
|
9138
9218
|
);
|
|
9219
|
+
case "edit-docx-text-style": {
|
|
9220
|
+
const { id, span } = payload;
|
|
9221
|
+
return docx().textStyle(id, span, signal);
|
|
9222
|
+
}
|
|
9223
|
+
case "edit-pptx-text-style": {
|
|
9224
|
+
const { id, span } = payload;
|
|
9225
|
+
return pptx().textStyle(id, span, signal);
|
|
9226
|
+
}
|
|
9139
9227
|
case "edit-dispose":
|
|
9140
9228
|
await state?.dispose();
|
|
9141
9229
|
state = void 0;
|