@extend-ai/react-docx 0.7.0-alpha.6 → 0.7.0-alpha.8
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 +11 -8
- package/dist/index.cjs +1330 -123
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -1
- package/dist/index.d.ts +27 -1
- package/dist/index.js +1330 -123
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3160,6 +3160,14 @@ var THUMBNAIL_EXCLUDED_CLONE_SELECTOR = [
|
|
|
3160
3160
|
var THUMBNAIL_IMAGE_DOWNSCALE_MIN_DATA_URI_LENGTH = 32768;
|
|
3161
3161
|
var THUMBNAIL_IMAGE_DOWNSCALE_MAX_DIMENSION_PX = 512;
|
|
3162
3162
|
var THUMBNAIL_IMAGE_JPEG_QUALITY = 0.78;
|
|
3163
|
+
var THUMBNAIL_DIRECT_DEFAULT_FONT_FAMILY = "Calibri, Arial, sans-serif";
|
|
3164
|
+
var THUMBNAIL_DIRECT_DEFAULT_TEXT_COLOR = "#111827";
|
|
3165
|
+
var THUMBNAIL_DIRECT_TABLE_BORDER_COLOR = "#d1d5db";
|
|
3166
|
+
var THUMBNAIL_DIRECT_IMAGE_BACKGROUND = "#f3f4f6";
|
|
3167
|
+
var THUMBNAIL_DIRECT_MAX_ELEMENTS = 320;
|
|
3168
|
+
var THUMBNAIL_DIRECT_MAX_TEXT_CHARS = 640;
|
|
3169
|
+
var THUMBNAIL_DIRECT_MAX_LINES = 14;
|
|
3170
|
+
var THUMBNAIL_DIRECT_MAX_LAYOUT_LINES = 80;
|
|
3163
3171
|
function thumbnailSvgDataUri(svg) {
|
|
3164
3172
|
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
|
3165
3173
|
}
|
|
@@ -3223,6 +3231,346 @@ function getDownscaledThumbnailImageDataUri(src) {
|
|
|
3223
3231
|
downscaledThumbnailImageCache.set(src, pending);
|
|
3224
3232
|
return pending;
|
|
3225
3233
|
}
|
|
3234
|
+
function directThumbnailPositivePx(value, fallback = 1) {
|
|
3235
|
+
return Number.isFinite(value) && value > 0 ? Math.max(1, Number(value)) : fallback;
|
|
3236
|
+
}
|
|
3237
|
+
function setCanvasFillStyle(context, color, fallback) {
|
|
3238
|
+
try {
|
|
3239
|
+
context.fillStyle = color || fallback;
|
|
3240
|
+
} catch {
|
|
3241
|
+
context.fillStyle = fallback;
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
function setCanvasStrokeStyle(context, color, fallback) {
|
|
3245
|
+
try {
|
|
3246
|
+
context.strokeStyle = color || fallback;
|
|
3247
|
+
} catch {
|
|
3248
|
+
context.strokeStyle = fallback;
|
|
3249
|
+
}
|
|
3250
|
+
}
|
|
3251
|
+
function directThumbnailFont(run, fallbackFontSizePx) {
|
|
3252
|
+
const fontSizePx = Math.max(
|
|
3253
|
+
6,
|
|
3254
|
+
Math.min(
|
|
3255
|
+
36,
|
|
3256
|
+
Math.round(
|
|
3257
|
+
directThumbnailPositivePx(run?.fontSizePx, fallbackFontSizePx)
|
|
3258
|
+
)
|
|
3259
|
+
)
|
|
3260
|
+
);
|
|
3261
|
+
const fontStyle = run?.italic ? "italic " : "";
|
|
3262
|
+
const fontWeight = run?.bold ? "700 " : "";
|
|
3263
|
+
return `${fontStyle}${fontWeight}${fontSizePx}px ${run?.fontFamily || THUMBNAIL_DIRECT_DEFAULT_FONT_FAMILY}`;
|
|
3264
|
+
}
|
|
3265
|
+
var THUMBNAIL_DIRECT_TOKEN_REGEX = /(\r\n|\n|\t|[^\S\r\n\t]+|[^\s\r\n\t]+)/g;
|
|
3266
|
+
var THUMBNAIL_DIRECT_LEADING_WHITESPACE_REGEX = /^\s/;
|
|
3267
|
+
var THUMBNAIL_DIRECT_TEXT_MEASURE_CACHE_MAX_ENTRIES = 4096;
|
|
3268
|
+
var directThumbnailTextMeasureCache = /* @__PURE__ */ new Map();
|
|
3269
|
+
function measureDirectThumbnailToken(context, font, text) {
|
|
3270
|
+
if (!text) {
|
|
3271
|
+
return 0;
|
|
3272
|
+
}
|
|
3273
|
+
const cacheKey = `${font}\0${text}`;
|
|
3274
|
+
const cached = directThumbnailTextMeasureCache.get(cacheKey);
|
|
3275
|
+
if (cached !== void 0) {
|
|
3276
|
+
return cached;
|
|
3277
|
+
}
|
|
3278
|
+
const width = context.measureText(text).width;
|
|
3279
|
+
if (directThumbnailTextMeasureCache.size >= THUMBNAIL_DIRECT_TEXT_MEASURE_CACHE_MAX_ENTRIES) {
|
|
3280
|
+
const oldestKey = directThumbnailTextMeasureCache.keys().next().value;
|
|
3281
|
+
if (oldestKey !== void 0) {
|
|
3282
|
+
directThumbnailTextMeasureCache.delete(oldestKey);
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
3285
|
+
directThumbnailTextMeasureCache.set(cacheKey, width);
|
|
3286
|
+
return width;
|
|
3287
|
+
}
|
|
3288
|
+
function appendDirectThumbnailTextLine(lines, currentSegments, currentWidthPx) {
|
|
3289
|
+
const line = {
|
|
3290
|
+
segments: currentSegments,
|
|
3291
|
+
widthPx: currentWidthPx
|
|
3292
|
+
};
|
|
3293
|
+
lines.push(line);
|
|
3294
|
+
return line;
|
|
3295
|
+
}
|
|
3296
|
+
function layoutDirectThumbnailTextRuns(params) {
|
|
3297
|
+
const { context, runs, fallbackFontSizePx } = params;
|
|
3298
|
+
const widthPx = Math.max(1, params.widthPx);
|
|
3299
|
+
const maxLineCount = Math.max(
|
|
3300
|
+
1,
|
|
3301
|
+
Math.min(THUMBNAIL_DIRECT_MAX_LAYOUT_LINES, params.maxLineCount)
|
|
3302
|
+
);
|
|
3303
|
+
const lines = [];
|
|
3304
|
+
let currentSegments = [];
|
|
3305
|
+
let currentWidthPx = 0;
|
|
3306
|
+
let remainingChars = THUMBNAIL_DIRECT_MAX_TEXT_CHARS;
|
|
3307
|
+
const flushLine = () => {
|
|
3308
|
+
appendDirectThumbnailTextLine(lines, currentSegments, currentWidthPx);
|
|
3309
|
+
currentSegments = [];
|
|
3310
|
+
currentWidthPx = 0;
|
|
3311
|
+
};
|
|
3312
|
+
for (const run of runs) {
|
|
3313
|
+
if (lines.length >= maxLineCount || remainingChars <= 0) {
|
|
3314
|
+
break;
|
|
3315
|
+
}
|
|
3316
|
+
const text = run.text.slice(0, remainingChars);
|
|
3317
|
+
remainingChars -= text.length;
|
|
3318
|
+
const runFont = directThumbnailFont(run, fallbackFontSizePx);
|
|
3319
|
+
context.font = runFont;
|
|
3320
|
+
const tokens = text.match(THUMBNAIL_DIRECT_TOKEN_REGEX) ?? [];
|
|
3321
|
+
for (const token of tokens) {
|
|
3322
|
+
if (lines.length >= maxLineCount) {
|
|
3323
|
+
break;
|
|
3324
|
+
}
|
|
3325
|
+
if (token === "\n" || token === "\r\n") {
|
|
3326
|
+
flushLine();
|
|
3327
|
+
continue;
|
|
3328
|
+
}
|
|
3329
|
+
const drawableToken = token === " " ? " " : token;
|
|
3330
|
+
const tokenWidthPx = measureDirectThumbnailToken(
|
|
3331
|
+
context,
|
|
3332
|
+
runFont,
|
|
3333
|
+
drawableToken
|
|
3334
|
+
);
|
|
3335
|
+
const tokenIsWhitespace = THUMBNAIL_DIRECT_LEADING_WHITESPACE_REGEX.test(drawableToken);
|
|
3336
|
+
if (currentSegments.length > 0 && currentWidthPx + tokenWidthPx > widthPx && !tokenIsWhitespace) {
|
|
3337
|
+
flushLine();
|
|
3338
|
+
}
|
|
3339
|
+
if (currentSegments.length === 0 && tokenIsWhitespace) {
|
|
3340
|
+
continue;
|
|
3341
|
+
}
|
|
3342
|
+
currentSegments.push({
|
|
3343
|
+
run,
|
|
3344
|
+
text: drawableToken,
|
|
3345
|
+
widthPx: tokenWidthPx,
|
|
3346
|
+
font: runFont
|
|
3347
|
+
});
|
|
3348
|
+
currentWidthPx += tokenWidthPx;
|
|
3349
|
+
}
|
|
3350
|
+
}
|
|
3351
|
+
if (currentSegments.length > 0 || lines.length === 0) {
|
|
3352
|
+
flushLine();
|
|
3353
|
+
}
|
|
3354
|
+
return lines;
|
|
3355
|
+
}
|
|
3356
|
+
function directThumbnailAlignedX(params) {
|
|
3357
|
+
const { xPx, widthPx, lineWidthPx, align } = params;
|
|
3358
|
+
if (align === "center") {
|
|
3359
|
+
return xPx + Math.max(0, (widthPx - lineWidthPx) / 2);
|
|
3360
|
+
}
|
|
3361
|
+
if (align === "right") {
|
|
3362
|
+
return xPx + Math.max(0, widthPx - lineWidthPx);
|
|
3363
|
+
}
|
|
3364
|
+
return xPx;
|
|
3365
|
+
}
|
|
3366
|
+
function drawDirectThumbnailTextRuns(params) {
|
|
3367
|
+
const {
|
|
3368
|
+
context,
|
|
3369
|
+
runs,
|
|
3370
|
+
xPx,
|
|
3371
|
+
yPx,
|
|
3372
|
+
widthPx,
|
|
3373
|
+
heightPx,
|
|
3374
|
+
align,
|
|
3375
|
+
startLineIndex
|
|
3376
|
+
} = params;
|
|
3377
|
+
const safeWidthPx = Math.max(1, widthPx);
|
|
3378
|
+
const safeHeightPx = Math.max(1, heightPx);
|
|
3379
|
+
const fallbackFontSizePx = Math.max(
|
|
3380
|
+
7,
|
|
3381
|
+
Math.min(
|
|
3382
|
+
20,
|
|
3383
|
+
Math.round(
|
|
3384
|
+
runs.find((run) => Number.isFinite(run.fontSizePx))?.fontSizePx ?? 12
|
|
3385
|
+
)
|
|
3386
|
+
)
|
|
3387
|
+
);
|
|
3388
|
+
const lineHeightPx = Math.max(
|
|
3389
|
+
fallbackFontSizePx + 1,
|
|
3390
|
+
Math.round(params.lineHeightPx ?? fallbackFontSizePx * 1.25)
|
|
3391
|
+
);
|
|
3392
|
+
const skippedLineCount = Math.max(
|
|
3393
|
+
0,
|
|
3394
|
+
Math.min(THUMBNAIL_DIRECT_MAX_LAYOUT_LINES - 1, Math.trunc(startLineIndex ?? 0))
|
|
3395
|
+
);
|
|
3396
|
+
const visibleLineCount = Math.max(
|
|
3397
|
+
1,
|
|
3398
|
+
Math.min(
|
|
3399
|
+
THUMBNAIL_DIRECT_MAX_LINES,
|
|
3400
|
+
Math.ceil(safeHeightPx / Math.max(1, lineHeightPx)) + 1
|
|
3401
|
+
)
|
|
3402
|
+
);
|
|
3403
|
+
const lines = layoutDirectThumbnailTextRuns({
|
|
3404
|
+
context,
|
|
3405
|
+
runs,
|
|
3406
|
+
widthPx: safeWidthPx,
|
|
3407
|
+
fallbackFontSizePx,
|
|
3408
|
+
maxLineCount: skippedLineCount + visibleLineCount
|
|
3409
|
+
}).slice(skippedLineCount, skippedLineCount + visibleLineCount);
|
|
3410
|
+
context.save();
|
|
3411
|
+
context.beginPath();
|
|
3412
|
+
context.rect(xPx, yPx, safeWidthPx, safeHeightPx);
|
|
3413
|
+
context.clip();
|
|
3414
|
+
context.textBaseline = "alphabetic";
|
|
3415
|
+
let lastAppliedFont;
|
|
3416
|
+
lines.forEach((line, lineIndex) => {
|
|
3417
|
+
const lineTopPx = yPx + lineIndex * lineHeightPx;
|
|
3418
|
+
if (lineTopPx > yPx + safeHeightPx) {
|
|
3419
|
+
return;
|
|
3420
|
+
}
|
|
3421
|
+
let cursorXPx = directThumbnailAlignedX({
|
|
3422
|
+
xPx,
|
|
3423
|
+
widthPx: safeWidthPx,
|
|
3424
|
+
lineWidthPx: line.widthPx,
|
|
3425
|
+
align
|
|
3426
|
+
});
|
|
3427
|
+
const baselineYPx = lineTopPx + Math.max(1, Math.round(lineHeightPx * 0.78));
|
|
3428
|
+
line.segments.forEach((segment) => {
|
|
3429
|
+
const segmentWidthPx = segment.widthPx;
|
|
3430
|
+
if (segment.run.backgroundColor) {
|
|
3431
|
+
setCanvasFillStyle(context, segment.run.backgroundColor, "transparent");
|
|
3432
|
+
context.fillRect(cursorXPx, lineTopPx + 1, segmentWidthPx, lineHeightPx);
|
|
3433
|
+
}
|
|
3434
|
+
if (segment.font !== lastAppliedFont) {
|
|
3435
|
+
context.font = segment.font;
|
|
3436
|
+
lastAppliedFont = segment.font;
|
|
3437
|
+
}
|
|
3438
|
+
setCanvasFillStyle(
|
|
3439
|
+
context,
|
|
3440
|
+
segment.run.color,
|
|
3441
|
+
THUMBNAIL_DIRECT_DEFAULT_TEXT_COLOR
|
|
3442
|
+
);
|
|
3443
|
+
context.fillText(segment.text, cursorXPx, baselineYPx);
|
|
3444
|
+
cursorXPx += segmentWidthPx;
|
|
3445
|
+
});
|
|
3446
|
+
});
|
|
3447
|
+
context.restore();
|
|
3448
|
+
}
|
|
3449
|
+
function drawDirectThumbnailParagraph(context, paragraph) {
|
|
3450
|
+
const xPx = Math.round(paragraph.xPx);
|
|
3451
|
+
const yPx = Math.round(paragraph.yPx);
|
|
3452
|
+
const widthPx = Math.max(1, Math.round(paragraph.widthPx));
|
|
3453
|
+
const heightPx = Math.max(1, Math.round(paragraph.heightPx));
|
|
3454
|
+
if (paragraph.backgroundColor) {
|
|
3455
|
+
setCanvasFillStyle(context, paragraph.backgroundColor, "transparent");
|
|
3456
|
+
context.fillRect(xPx, yPx, widthPx, heightPx);
|
|
3457
|
+
}
|
|
3458
|
+
drawDirectThumbnailTextRuns({
|
|
3459
|
+
context,
|
|
3460
|
+
runs: paragraph.runs,
|
|
3461
|
+
xPx: xPx + 1,
|
|
3462
|
+
yPx,
|
|
3463
|
+
widthPx: Math.max(1, widthPx - 2),
|
|
3464
|
+
heightPx,
|
|
3465
|
+
align: paragraph.align,
|
|
3466
|
+
lineHeightPx: paragraph.lineHeightPx,
|
|
3467
|
+
startLineIndex: paragraph.startLineIndex
|
|
3468
|
+
});
|
|
3469
|
+
}
|
|
3470
|
+
function drawDirectThumbnailImagePlaceholder(context, image, hairlineSourcePx) {
|
|
3471
|
+
const xPx = Math.round(image.xPx);
|
|
3472
|
+
const yPx = Math.round(image.yPx);
|
|
3473
|
+
const widthPx = Math.max(1, Math.round(image.widthPx));
|
|
3474
|
+
const heightPx = Math.max(1, Math.round(image.heightPx));
|
|
3475
|
+
setCanvasFillStyle(
|
|
3476
|
+
context,
|
|
3477
|
+
image.backgroundColor,
|
|
3478
|
+
THUMBNAIL_DIRECT_IMAGE_BACKGROUND
|
|
3479
|
+
);
|
|
3480
|
+
context.fillRect(xPx, yPx, widthPx, heightPx);
|
|
3481
|
+
setCanvasStrokeStyle(
|
|
3482
|
+
context,
|
|
3483
|
+
image.borderColor,
|
|
3484
|
+
THUMBNAIL_DIRECT_TABLE_BORDER_COLOR
|
|
3485
|
+
);
|
|
3486
|
+
context.lineWidth = hairlineSourcePx;
|
|
3487
|
+
context.strokeRect(xPx, yPx, widthPx, heightPx);
|
|
3488
|
+
}
|
|
3489
|
+
function drawDirectThumbnailTable(context, table, hairlineSourcePx) {
|
|
3490
|
+
const tableXPx = Math.round(table.xPx);
|
|
3491
|
+
const tableYPx = Math.round(table.yPx);
|
|
3492
|
+
const tableWidthPx = Math.max(1, Math.round(table.widthPx));
|
|
3493
|
+
const tableHeightPx = Math.max(1, Math.round(table.heightPx));
|
|
3494
|
+
context.save();
|
|
3495
|
+
context.beginPath();
|
|
3496
|
+
context.rect(tableXPx, tableYPx, tableWidthPx, tableHeightPx);
|
|
3497
|
+
context.clip();
|
|
3498
|
+
setCanvasStrokeStyle(
|
|
3499
|
+
context,
|
|
3500
|
+
table.borderColor,
|
|
3501
|
+
THUMBNAIL_DIRECT_TABLE_BORDER_COLOR
|
|
3502
|
+
);
|
|
3503
|
+
context.lineWidth = hairlineSourcePx;
|
|
3504
|
+
table.cells.forEach((cell) => {
|
|
3505
|
+
const xPx = tableXPx + Math.round(cell.xPx);
|
|
3506
|
+
const yPx = tableYPx + Math.round(cell.yPx);
|
|
3507
|
+
const widthPx = Math.max(1, Math.round(cell.widthPx));
|
|
3508
|
+
const heightPx = Math.max(1, Math.round(cell.heightPx));
|
|
3509
|
+
if (cell.backgroundColor) {
|
|
3510
|
+
setCanvasFillStyle(context, cell.backgroundColor, "transparent");
|
|
3511
|
+
context.fillRect(xPx, yPx, widthPx, heightPx);
|
|
3512
|
+
}
|
|
3513
|
+
context.strokeRect(xPx, yPx, widthPx, heightPx);
|
|
3514
|
+
if (cell.runs?.length) {
|
|
3515
|
+
drawDirectThumbnailTextRuns({
|
|
3516
|
+
context,
|
|
3517
|
+
runs: cell.runs,
|
|
3518
|
+
xPx: xPx + 3,
|
|
3519
|
+
yPx: yPx + 2,
|
|
3520
|
+
widthPx: Math.max(1, widthPx - 6),
|
|
3521
|
+
heightPx: Math.max(1, heightPx - 4),
|
|
3522
|
+
lineHeightPx: 13
|
|
3523
|
+
});
|
|
3524
|
+
}
|
|
3525
|
+
});
|
|
3526
|
+
context.restore();
|
|
3527
|
+
}
|
|
3528
|
+
function renderDocxThumbnailSnapshotSurface(params) {
|
|
3529
|
+
if (typeof document === "undefined") {
|
|
3530
|
+
throw new Error("DOCX thumbnails require a browser environment.");
|
|
3531
|
+
}
|
|
3532
|
+
const sourceWidthPx = directThumbnailPositivePx(params.snapshot.sourceWidthPx);
|
|
3533
|
+
const sourceHeightPx = directThumbnailPositivePx(params.snapshot.sourceHeightPx);
|
|
3534
|
+
const pixelWidthPx = Math.max(1, Math.round(params.pixelWidthPx));
|
|
3535
|
+
const pixelHeightPx = Math.max(1, Math.round(params.pixelHeightPx));
|
|
3536
|
+
const surface = document.createElement("canvas");
|
|
3537
|
+
surface.width = pixelWidthPx;
|
|
3538
|
+
surface.height = pixelHeightPx;
|
|
3539
|
+
const context = surface.getContext("2d");
|
|
3540
|
+
if (!context) {
|
|
3541
|
+
throw new Error("2D canvas context is unavailable for DOCX thumbnails.");
|
|
3542
|
+
}
|
|
3543
|
+
const scaleX = pixelWidthPx / sourceWidthPx;
|
|
3544
|
+
const scaleY = pixelHeightPx / sourceHeightPx;
|
|
3545
|
+
const hairlineSourcePx = Math.max(0.75, 1 / Math.max(scaleX, scaleY));
|
|
3546
|
+
context.setTransform(scaleX, 0, 0, scaleY, 0, 0);
|
|
3547
|
+
context.imageSmoothingEnabled = true;
|
|
3548
|
+
context.imageSmoothingQuality = "high";
|
|
3549
|
+
setCanvasFillStyle(
|
|
3550
|
+
context,
|
|
3551
|
+
params.snapshot.pageBackgroundColor,
|
|
3552
|
+
"#ffffff"
|
|
3553
|
+
);
|
|
3554
|
+
context.fillRect(0, 0, sourceWidthPx, sourceHeightPx);
|
|
3555
|
+
params.snapshot.elements.slice(0, THUMBNAIL_DIRECT_MAX_ELEMENTS).forEach((element) => {
|
|
3556
|
+
switch (element.kind) {
|
|
3557
|
+
case "paragraph":
|
|
3558
|
+
drawDirectThumbnailParagraph(context, element);
|
|
3559
|
+
break;
|
|
3560
|
+
case "image-placeholder":
|
|
3561
|
+
drawDirectThumbnailImagePlaceholder(
|
|
3562
|
+
context,
|
|
3563
|
+
element,
|
|
3564
|
+
hairlineSourcePx
|
|
3565
|
+
);
|
|
3566
|
+
break;
|
|
3567
|
+
case "table":
|
|
3568
|
+
drawDirectThumbnailTable(context, element, hairlineSourcePx);
|
|
3569
|
+
break;
|
|
3570
|
+
}
|
|
3571
|
+
});
|
|
3572
|
+
return surface;
|
|
3573
|
+
}
|
|
3226
3574
|
async function buildDocxThumbnailSvgMarkup(params) {
|
|
3227
3575
|
const { pageElement, sourceWidthPx, sourceHeightPx, widthPx, heightPx } = params;
|
|
3228
3576
|
const clone = pageElement.cloneNode(true);
|
|
@@ -3284,16 +3632,33 @@ async function rasterizeDocxThumbnailSurface(params) {
|
|
|
3284
3632
|
return surface;
|
|
3285
3633
|
}
|
|
3286
3634
|
function blitDocxThumbnailSurface(surface, canvas, resolution) {
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3635
|
+
const pixelWidth = Math.max(1, Math.round(resolution.pixelWidthPx));
|
|
3636
|
+
const pixelHeight = Math.max(1, Math.round(resolution.pixelHeightPx));
|
|
3637
|
+
const cssWidth = `${Math.max(1, Math.round(resolution.widthPx))}px`;
|
|
3638
|
+
const cssHeight = `${Math.max(1, Math.round(resolution.heightPx))}px`;
|
|
3639
|
+
let bufferResized = false;
|
|
3640
|
+
if (canvas.width !== pixelWidth) {
|
|
3641
|
+
canvas.width = pixelWidth;
|
|
3642
|
+
bufferResized = true;
|
|
3643
|
+
}
|
|
3644
|
+
if (canvas.height !== pixelHeight) {
|
|
3645
|
+
canvas.height = pixelHeight;
|
|
3646
|
+
bufferResized = true;
|
|
3647
|
+
}
|
|
3648
|
+
if (canvas.style.width !== cssWidth) {
|
|
3649
|
+
canvas.style.width = cssWidth;
|
|
3650
|
+
}
|
|
3651
|
+
if (canvas.style.height !== cssHeight) {
|
|
3652
|
+
canvas.style.height = cssHeight;
|
|
3653
|
+
}
|
|
3291
3654
|
const context = canvas.getContext("2d");
|
|
3292
3655
|
if (!context) {
|
|
3293
3656
|
throw new Error("2D canvas context is unavailable for DOCX thumbnails.");
|
|
3294
3657
|
}
|
|
3295
3658
|
context.setTransform(1, 0, 0, 1, 0, 0);
|
|
3296
|
-
|
|
3659
|
+
if (!bufferResized) {
|
|
3660
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
3661
|
+
}
|
|
3297
3662
|
context.drawImage(surface, 0, 0, canvas.width, canvas.height);
|
|
3298
3663
|
}
|
|
3299
3664
|
var DocxThumbnailSurfaceCache = class {
|
|
@@ -3368,6 +3733,7 @@ var SerialIdleTaskQueue = class {
|
|
|
3368
3733
|
now;
|
|
3369
3734
|
pumpScheduled = false;
|
|
3370
3735
|
running = false;
|
|
3736
|
+
nextSequence = 0;
|
|
3371
3737
|
constructor(options) {
|
|
3372
3738
|
this.scheduleTask = options?.scheduleTask ?? defaultScheduleTask;
|
|
3373
3739
|
this.scheduleDelayed = options?.scheduleDelayed ?? defaultScheduleDelayed;
|
|
@@ -3377,14 +3743,23 @@ var SerialIdleTaskQueue = class {
|
|
|
3377
3743
|
get pendingCount() {
|
|
3378
3744
|
return this.pending.length;
|
|
3379
3745
|
}
|
|
3380
|
-
enqueue(key, run) {
|
|
3746
|
+
enqueue(key, run, options) {
|
|
3747
|
+
const priority = Number.isFinite(options?.priority) ? Number(options?.priority) : 0;
|
|
3381
3748
|
return new Promise((resolve) => {
|
|
3382
3749
|
const existing = this.pending.find((entry) => entry.key === key);
|
|
3383
3750
|
if (existing) {
|
|
3384
3751
|
existing.run = run;
|
|
3385
3752
|
existing.resolvers.push(resolve);
|
|
3753
|
+
existing.priority = Math.min(existing.priority, priority);
|
|
3386
3754
|
} else {
|
|
3387
|
-
this.pending.push({
|
|
3755
|
+
this.pending.push({
|
|
3756
|
+
key,
|
|
3757
|
+
run,
|
|
3758
|
+
resolvers: [resolve],
|
|
3759
|
+
priority,
|
|
3760
|
+
sequence: this.nextSequence
|
|
3761
|
+
});
|
|
3762
|
+
this.nextSequence += 1;
|
|
3388
3763
|
}
|
|
3389
3764
|
this.schedulePump();
|
|
3390
3765
|
});
|
|
@@ -3429,6 +3804,8 @@ var SerialIdleTaskQueue = class {
|
|
|
3429
3804
|
}
|
|
3430
3805
|
const now = this.now();
|
|
3431
3806
|
let earliestWaitMs;
|
|
3807
|
+
let bestIndex = -1;
|
|
3808
|
+
let bestEntry;
|
|
3432
3809
|
for (let index = 0; index < this.pending.length; index += 1) {
|
|
3433
3810
|
const candidate = this.pending[index];
|
|
3434
3811
|
if (!candidate) {
|
|
@@ -3437,11 +3814,18 @@ var SerialIdleTaskQueue = class {
|
|
|
3437
3814
|
const lastRunAt = this.lastRunAtByKey.get(candidate.key);
|
|
3438
3815
|
const waitMs = lastRunAt === void 0 ? 0 : lastRunAt + this.minTaskIntervalMs - now;
|
|
3439
3816
|
if (waitMs <= 0) {
|
|
3440
|
-
|
|
3441
|
-
|
|
3817
|
+
if (!bestEntry || candidate.priority < bestEntry.priority || candidate.priority === bestEntry.priority && candidate.sequence < bestEntry.sequence) {
|
|
3818
|
+
bestEntry = candidate;
|
|
3819
|
+
bestIndex = index;
|
|
3820
|
+
}
|
|
3821
|
+
continue;
|
|
3442
3822
|
}
|
|
3443
3823
|
earliestWaitMs = earliestWaitMs === void 0 ? waitMs : Math.min(earliestWaitMs, waitMs);
|
|
3444
3824
|
}
|
|
3825
|
+
if (bestEntry && bestIndex >= 0) {
|
|
3826
|
+
this.pending.splice(bestIndex, 1);
|
|
3827
|
+
return { entry: bestEntry };
|
|
3828
|
+
}
|
|
3445
3829
|
return earliestWaitMs === void 0 ? void 0 : { retryDelayMs: earliestWaitMs };
|
|
3446
3830
|
}
|
|
3447
3831
|
async runNext() {
|
|
@@ -22439,13 +22823,15 @@ function ensureDocxViewerPageSurfaceRegistry(editor) {
|
|
|
22439
22823
|
registry = {
|
|
22440
22824
|
pageElements: /* @__PURE__ */ new Map(),
|
|
22441
22825
|
pageContentKeys: /* @__PURE__ */ new Map(),
|
|
22826
|
+
pageSizes: /* @__PURE__ */ new Map(),
|
|
22827
|
+
pageThumbnailSnapshots: /* @__PURE__ */ new Map(),
|
|
22442
22828
|
listeners: /* @__PURE__ */ new Set()
|
|
22443
22829
|
};
|
|
22444
22830
|
docxViewerPageSurfaceRegistryByEditor.set(owner, registry);
|
|
22445
22831
|
}
|
|
22446
22832
|
return registry;
|
|
22447
22833
|
}
|
|
22448
|
-
function syncDocxViewerPageSurfaceContentKeys(editor, contentKeysByPage) {
|
|
22834
|
+
function syncDocxViewerPageSurfaceContentKeys(editor, contentKeysByPage, pageSizesByPage = [], thumbnailSnapshotsByPage = []) {
|
|
22449
22835
|
const registry = ensureDocxViewerPageSurfaceRegistry(editor);
|
|
22450
22836
|
let changed = false;
|
|
22451
22837
|
contentKeysByPage.forEach((contentKey, pageIndex) => {
|
|
@@ -22454,12 +22840,47 @@ function syncDocxViewerPageSurfaceContentKeys(editor, contentKeysByPage) {
|
|
|
22454
22840
|
changed = true;
|
|
22455
22841
|
}
|
|
22456
22842
|
});
|
|
22843
|
+
pageSizesByPage.forEach((pageSize, pageIndex) => {
|
|
22844
|
+
const widthPx = Math.max(1, Math.round(pageSize.widthPx));
|
|
22845
|
+
const heightPx = Math.max(1, Math.round(pageSize.heightPx));
|
|
22846
|
+
const previous = registry.pageSizes.get(pageIndex);
|
|
22847
|
+
if (previous?.widthPx !== widthPx || previous?.heightPx !== heightPx) {
|
|
22848
|
+
registry.pageSizes.set(pageIndex, { widthPx, heightPx });
|
|
22849
|
+
changed = true;
|
|
22850
|
+
}
|
|
22851
|
+
});
|
|
22852
|
+
thumbnailSnapshotsByPage.forEach((snapshot, pageIndex) => {
|
|
22853
|
+
const previous = registry.pageThumbnailSnapshots.get(pageIndex);
|
|
22854
|
+
if (!snapshot) {
|
|
22855
|
+
if (previous) {
|
|
22856
|
+
registry.pageThumbnailSnapshots.delete(pageIndex);
|
|
22857
|
+
changed = true;
|
|
22858
|
+
}
|
|
22859
|
+
return;
|
|
22860
|
+
}
|
|
22861
|
+
if (previous?.key !== snapshot.key) {
|
|
22862
|
+
registry.pageThumbnailSnapshots.set(pageIndex, snapshot);
|
|
22863
|
+
changed = true;
|
|
22864
|
+
}
|
|
22865
|
+
});
|
|
22457
22866
|
registry.pageContentKeys.forEach((_, pageIndex) => {
|
|
22458
22867
|
if (pageIndex >= contentKeysByPage.length) {
|
|
22459
22868
|
registry.pageContentKeys.delete(pageIndex);
|
|
22460
22869
|
changed = true;
|
|
22461
22870
|
}
|
|
22462
22871
|
});
|
|
22872
|
+
registry.pageSizes.forEach((_, pageIndex) => {
|
|
22873
|
+
if (pageIndex >= pageSizesByPage.length) {
|
|
22874
|
+
registry.pageSizes.delete(pageIndex);
|
|
22875
|
+
changed = true;
|
|
22876
|
+
}
|
|
22877
|
+
});
|
|
22878
|
+
registry.pageThumbnailSnapshots.forEach((_, pageIndex) => {
|
|
22879
|
+
if (pageIndex >= thumbnailSnapshotsByPage.length) {
|
|
22880
|
+
registry.pageThumbnailSnapshots.delete(pageIndex);
|
|
22881
|
+
changed = true;
|
|
22882
|
+
}
|
|
22883
|
+
});
|
|
22463
22884
|
if (changed) {
|
|
22464
22885
|
notifyDocxViewerPageSurfaceSubscribers(registry);
|
|
22465
22886
|
}
|
|
@@ -22476,7 +22897,7 @@ function notifyDocxViewerPageSurfaceSubscribers(registry) {
|
|
|
22476
22897
|
listener();
|
|
22477
22898
|
});
|
|
22478
22899
|
}
|
|
22479
|
-
function registerDocxViewerPageSurface(editor, pageIndex, element) {
|
|
22900
|
+
function registerDocxViewerPageSurface(editor, pageIndex, element, previousElement) {
|
|
22480
22901
|
const registry = ensureDocxViewerPageSurfaceRegistry(editor);
|
|
22481
22902
|
const normalizedPageIndex = Math.max(0, Math.round(pageIndex));
|
|
22482
22903
|
const currentElement = registry.pageElements.get(normalizedPageIndex);
|
|
@@ -22491,9 +22912,22 @@ function registerDocxViewerPageSurface(editor, pageIndex, element) {
|
|
|
22491
22912
|
if (!currentElement) {
|
|
22492
22913
|
return;
|
|
22493
22914
|
}
|
|
22915
|
+
if (previousElement && currentElement !== previousElement) {
|
|
22916
|
+
return;
|
|
22917
|
+
}
|
|
22494
22918
|
registry.pageElements.delete(normalizedPageIndex);
|
|
22495
22919
|
notifyDocxViewerPageSurfaceSubscribers(registry);
|
|
22496
22920
|
}
|
|
22921
|
+
function resolveDocxViewerRegisteredPageSurfaceSize(registry, pageIndex, fallbackWidthPx, fallbackHeightPx) {
|
|
22922
|
+
const registeredSize = registry.pageSizes.get(pageIndex);
|
|
22923
|
+
if (registeredSize) {
|
|
22924
|
+
return registeredSize;
|
|
22925
|
+
}
|
|
22926
|
+
return {
|
|
22927
|
+
widthPx: Math.max(1, Math.round(fallbackWidthPx)),
|
|
22928
|
+
heightPx: Math.max(1, Math.round(fallbackHeightPx))
|
|
22929
|
+
};
|
|
22930
|
+
}
|
|
22497
22931
|
function resolveDocxViewerPageSurfaceSize(element, fallbackWidthPx, fallbackHeightPx) {
|
|
22498
22932
|
if (element) {
|
|
22499
22933
|
const rect = element.getBoundingClientRect();
|
|
@@ -22527,58 +22961,546 @@ function resolveDocxViewerPageSurfaceSize(element, fallbackWidthPx, fallbackHeig
|
|
|
22527
22961
|
heightPx: Math.max(1, Math.round(fallbackHeightPx))
|
|
22528
22962
|
};
|
|
22529
22963
|
}
|
|
22530
|
-
var
|
|
22531
|
-
var
|
|
22532
|
-
|
|
22533
|
-
|
|
22534
|
-
|
|
22535
|
-
|
|
22536
|
-
|
|
22537
|
-
|
|
22538
|
-
}
|
|
22539
|
-
|
|
22540
|
-
|
|
22541
|
-
|
|
22542
|
-
|
|
22543
|
-
|
|
22544
|
-
const scale = Math.min(
|
|
22545
|
-
1,
|
|
22546
|
-
widthBoundPx / safeSourceWidthPx,
|
|
22547
|
-
heightBoundPx / safeSourceHeightPx
|
|
22548
|
-
);
|
|
22549
|
-
const pixelRatio = Number.isFinite(options.pixelRatio) ? Math.max(1, Number(options.pixelRatio)) : 1;
|
|
22550
|
-
const widthPx = Math.max(1, Math.round(safeSourceWidthPx * scale));
|
|
22551
|
-
const heightPx = Math.max(1, Math.round(safeSourceHeightPx * scale));
|
|
22552
|
-
return {
|
|
22553
|
-
widthPx,
|
|
22554
|
-
heightPx,
|
|
22555
|
-
pixelWidthPx: Math.max(1, Math.round(widthPx * pixelRatio)),
|
|
22556
|
-
pixelHeightPx: Math.max(1, Math.round(heightPx * pixelRatio)),
|
|
22557
|
-
scale
|
|
22558
|
-
};
|
|
22964
|
+
var DOCX_DIRECT_THUMBNAIL_MAX_ELEMENTS_PER_PAGE = 260;
|
|
22965
|
+
var DOCX_DIRECT_THUMBNAIL_MAX_TEXT_RUNS = 28;
|
|
22966
|
+
var DOCX_DIRECT_THUMBNAIL_MAX_TEXT_CHARS = 900;
|
|
22967
|
+
var DOCX_DIRECT_THUMBNAIL_MAX_TABLE_CELLS = 220;
|
|
22968
|
+
var DOCX_DIRECT_THUMBNAIL_MAX_CELL_TEXT_CHARS = 120;
|
|
22969
|
+
function docxThumbnailCssNumber(value) {
|
|
22970
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
22971
|
+
return value;
|
|
22972
|
+
}
|
|
22973
|
+
if (typeof value === "string") {
|
|
22974
|
+
const parsed = Number.parseFloat(value);
|
|
22975
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
22976
|
+
}
|
|
22977
|
+
return 0;
|
|
22559
22978
|
}
|
|
22560
|
-
function
|
|
22561
|
-
const
|
|
22562
|
-
|
|
22563
|
-
|
|
22564
|
-
|
|
22979
|
+
function normalizeDocxThumbnailColor(value) {
|
|
22980
|
+
const normalized = value?.trim();
|
|
22981
|
+
if (!normalized || normalized.toLowerCase() === "auto") {
|
|
22982
|
+
return void 0;
|
|
22983
|
+
}
|
|
22984
|
+
if (/^[0-9a-fA-F]{6}$/.test(normalized)) {
|
|
22985
|
+
return `#${normalized}`;
|
|
22986
|
+
}
|
|
22987
|
+
return normalized;
|
|
22988
|
+
}
|
|
22989
|
+
function docxThumbnailTextRunStylesMatch(left, right) {
|
|
22990
|
+
return left.bold === right.bold && left.italic === right.italic && left.color === right.color && left.backgroundColor === right.backgroundColor && left.fontSizePx === right.fontSizePx && left.fontFamily === right.fontFamily;
|
|
22991
|
+
}
|
|
22992
|
+
function appendDocxThumbnailTextRun(runs, run, remaining) {
|
|
22993
|
+
if (remaining.chars <= 0 || runs.length >= DOCX_DIRECT_THUMBNAIL_MAX_TEXT_RUNS) {
|
|
22994
|
+
return;
|
|
22995
|
+
}
|
|
22996
|
+
const text = run.text.slice(0, remaining.chars);
|
|
22997
|
+
if (!text) {
|
|
22998
|
+
return;
|
|
22999
|
+
}
|
|
23000
|
+
remaining.chars -= text.length;
|
|
23001
|
+
const nextRun = { ...run, text };
|
|
23002
|
+
const previous = runs[runs.length - 1];
|
|
23003
|
+
if (previous && docxThumbnailTextRunStylesMatch(previous, nextRun)) {
|
|
23004
|
+
previous.text += nextRun.text;
|
|
23005
|
+
return;
|
|
23006
|
+
}
|
|
23007
|
+
runs.push(nextRun);
|
|
23008
|
+
}
|
|
23009
|
+
function docxThumbnailFallbackHeadingRunStyle(paragraph) {
|
|
23010
|
+
const headingLevel = paragraph.style?.headingLevel;
|
|
23011
|
+
return headingLevel && headingLevel >= 1 && headingLevel <= 6 ? DEFAULT_WORD_HEADING_RUN_STYLES[headingLevel] : void 0;
|
|
23012
|
+
}
|
|
23013
|
+
function docxThumbnailTextRunsFromParagraph(paragraph, documentTheme, maxChars = DOCX_DIRECT_THUMBNAIL_MAX_TEXT_CHARS) {
|
|
23014
|
+
const runs = [];
|
|
23015
|
+
const remaining = { chars: maxChars };
|
|
23016
|
+
const fallbackHeadingStyle = docxThumbnailFallbackHeadingRunStyle(paragraph);
|
|
23017
|
+
const fallbackFontFamily = cssFontFamily(fallbackHeadingStyle?.fontFamily) ?? cssFontFamily(paragraphDominantFontFamily(paragraph));
|
|
23018
|
+
paragraph.children.forEach((child) => {
|
|
23019
|
+
if (remaining.chars <= 0) {
|
|
23020
|
+
return;
|
|
23021
|
+
}
|
|
23022
|
+
const style = child.type === "text" || child.type === "form-field" ? child.style : void 0;
|
|
23023
|
+
const text = child.type === "text" ? child.text : child.type === "form-field" ? formFieldDisplayValue2(child) : child.type === "image" ? child.alt || "[image]" : "";
|
|
23024
|
+
appendDocxThumbnailTextRun(
|
|
23025
|
+
runs,
|
|
23026
|
+
{
|
|
23027
|
+
text,
|
|
23028
|
+
bold: style?.bold ?? fallbackHeadingStyle?.bold,
|
|
23029
|
+
italic: style?.italic ?? fallbackHeadingStyle?.italic,
|
|
23030
|
+
color: normalizeDocxThumbnailColor(
|
|
23031
|
+
themedRunColor(style?.color ?? fallbackHeadingStyle?.color, documentTheme)
|
|
23032
|
+
),
|
|
23033
|
+
backgroundColor: normalizeDocxThumbnailColor(
|
|
23034
|
+
style?.backgroundColor ?? resolveHighlightColor(style?.highlight)
|
|
23035
|
+
),
|
|
23036
|
+
fontSizePx: style?.fontSizePt && style.fontSizePt > 0 ? Math.max(6, style.fontSizePt * 96 / 72) : fallbackHeadingStyle?.fontSizePt ? Math.max(6, fallbackHeadingStyle.fontSizePt * 96 / 72) : paragraphBaseFontSizePx(paragraph),
|
|
23037
|
+
fontFamily: cssFontFamily(style?.fontFamily) ?? fallbackFontFamily
|
|
23038
|
+
},
|
|
23039
|
+
remaining
|
|
23040
|
+
);
|
|
23041
|
+
});
|
|
23042
|
+
return runs;
|
|
23043
|
+
}
|
|
23044
|
+
function docxThumbnailCellTextRuns(cell, documentTheme) {
|
|
23045
|
+
const paragraph = tableCellParagraphsRecursively(cell.nodes).find(
|
|
23046
|
+
(candidate) => paragraphText(candidate).trim().length > 0
|
|
22565
23047
|
);
|
|
22566
|
-
|
|
22567
|
-
|
|
22568
|
-
|
|
22569
|
-
|
|
23048
|
+
if (!paragraph) {
|
|
23049
|
+
return void 0;
|
|
23050
|
+
}
|
|
23051
|
+
const runs = docxThumbnailTextRunsFromParagraph(
|
|
23052
|
+
paragraph,
|
|
23053
|
+
documentTheme,
|
|
23054
|
+
DOCX_DIRECT_THUMBNAIL_MAX_CELL_TEXT_CHARS
|
|
22570
23055
|
);
|
|
22571
|
-
|
|
22572
|
-
|
|
22573
|
-
|
|
22574
|
-
|
|
22575
|
-
|
|
23056
|
+
return runs.length > 0 ? runs : void 0;
|
|
23057
|
+
}
|
|
23058
|
+
function buildDocxThumbnailParagraphElements(params) {
|
|
23059
|
+
const {
|
|
23060
|
+
paragraph,
|
|
23061
|
+
segment,
|
|
23062
|
+
contentLeftPx,
|
|
23063
|
+
contentWidthPx,
|
|
23064
|
+
yPx,
|
|
23065
|
+
heightPx,
|
|
23066
|
+
numberingDefinitions,
|
|
23067
|
+
docGridLinePitchPx,
|
|
23068
|
+
documentTheme
|
|
23069
|
+
} = params;
|
|
23070
|
+
const blockStyle = paragraphBlockStyle(
|
|
23071
|
+
paragraph,
|
|
23072
|
+
numberingDefinitions,
|
|
23073
|
+
void 0,
|
|
23074
|
+
docGridLinePitchPx
|
|
22576
23075
|
);
|
|
22577
|
-
const
|
|
22578
|
-
|
|
22579
|
-
|
|
23076
|
+
const paragraphLineRange = segment.paragraphLineRange;
|
|
23077
|
+
const marginTopPx = paragraphLineRange && paragraphLineRange.startLineIndex > 0 ? 0 : Math.max(0, docxThumbnailCssNumber(blockStyle.marginTop));
|
|
23078
|
+
const marginBottomPx = paragraphLineRange && paragraphLineRange.endLineIndex < paragraphLineRange.totalLineCount ? 0 : Math.max(0, docxThumbnailCssNumber(blockStyle.marginBottom));
|
|
23079
|
+
const marginLeftPx = docxThumbnailCssNumber(blockStyle.marginLeft);
|
|
23080
|
+
const marginRightPx = Math.max(0, docxThumbnailCssNumber(blockStyle.marginRight));
|
|
23081
|
+
const xPx = contentLeftPx + marginLeftPx;
|
|
23082
|
+
const widthPx = Math.max(8, contentWidthPx - marginLeftPx - marginRightPx);
|
|
23083
|
+
const bodyYPx = yPx + marginTopPx;
|
|
23084
|
+
const bodyHeightPx = Math.max(1, heightPx - marginTopPx - marginBottomPx);
|
|
23085
|
+
const runs = docxThumbnailTextRunsFromParagraph(paragraph, documentTheme);
|
|
23086
|
+
const elements = [];
|
|
23087
|
+
elements.push({
|
|
23088
|
+
kind: "paragraph",
|
|
23089
|
+
xPx,
|
|
23090
|
+
yPx: bodyYPx,
|
|
23091
|
+
widthPx,
|
|
23092
|
+
heightPx: bodyHeightPx,
|
|
23093
|
+
align: paragraph.style?.align,
|
|
23094
|
+
backgroundColor: normalizeDocxThumbnailColor(
|
|
23095
|
+
paragraph.style?.backgroundColor
|
|
23096
|
+
),
|
|
23097
|
+
lineHeightPx: paragraphLineRange?.lineHeightPx ?? estimateParagraphLineHeightPx(paragraph, docGridLinePitchPx),
|
|
23098
|
+
startLineIndex: paragraphLineRange?.startLineIndex,
|
|
23099
|
+
runs
|
|
23100
|
+
});
|
|
23101
|
+
const hasVisibleText = runs.some((run) => run.text.trim().length > 0);
|
|
23102
|
+
if (!hasVisibleText) {
|
|
23103
|
+
const imageRuns = paragraph.children.filter(
|
|
23104
|
+
(child) => child.type === "image"
|
|
23105
|
+
);
|
|
23106
|
+
imageRuns.slice(0, 4).forEach((imageRun) => {
|
|
23107
|
+
const imageWidthPx = Math.max(18, imageRun.widthPx ?? widthPx * 0.5);
|
|
23108
|
+
const imageHeightPx = Math.max(18, imageRun.heightPx ?? bodyHeightPx * 0.5);
|
|
23109
|
+
const scale = Math.min(
|
|
23110
|
+
1,
|
|
23111
|
+
(widthPx - 4) / imageWidthPx,
|
|
23112
|
+
(bodyHeightPx - 4) / imageHeightPx
|
|
23113
|
+
);
|
|
23114
|
+
elements.push({
|
|
23115
|
+
kind: "image-placeholder",
|
|
23116
|
+
xPx: xPx + 2,
|
|
23117
|
+
yPx: bodyYPx + 2,
|
|
23118
|
+
widthPx: Math.max(12, imageWidthPx * scale),
|
|
23119
|
+
heightPx: Math.max(12, imageHeightPx * scale)
|
|
23120
|
+
});
|
|
23121
|
+
});
|
|
23122
|
+
}
|
|
23123
|
+
return elements;
|
|
23124
|
+
}
|
|
23125
|
+
function buildDocxThumbnailTableElement(params) {
|
|
23126
|
+
const {
|
|
23127
|
+
table,
|
|
23128
|
+
segment,
|
|
23129
|
+
contentLeftPx,
|
|
23130
|
+
contentWidthPx,
|
|
23131
|
+
contentHeightPx,
|
|
23132
|
+
yPx,
|
|
23133
|
+
heightPx,
|
|
23134
|
+
numberingDefinitions,
|
|
23135
|
+
docGridLinePitchPx,
|
|
23136
|
+
documentTheme
|
|
23137
|
+
} = params;
|
|
23138
|
+
const columnCount = tableColumnCount(table);
|
|
23139
|
+
const tableIndentPx = twipsToSignedPixels(table.style?.indentTwips) ?? 0;
|
|
23140
|
+
const tableWidthPx = twipsToPixels(table.style?.widthTwips);
|
|
23141
|
+
const definedWidthsTwips = columnWidthsFromTableDefinition(table, columnCount);
|
|
23142
|
+
const rawTableColumnWidthsPx = definedWidthsTwips && definedWidthsTwips.length > 0 ? normalizeColumnWidthsPx(
|
|
23143
|
+
definedWidthsTwips.map((widthTwips) => twipsToPixels(widthTwips) ?? 0),
|
|
23144
|
+
columnCount,
|
|
23145
|
+
tableWidthPx,
|
|
23146
|
+
1
|
|
23147
|
+
) : defaultColumnWidthsPx(columnCount, tableWidthPx);
|
|
23148
|
+
const rawResolvedTableWidthPx = tableWidthPx ?? rawTableColumnWidthsPx.reduce((sum, widthPx) => sum + widthPx, 0);
|
|
23149
|
+
const maxTableWidthPx = Math.max(
|
|
23150
|
+
24,
|
|
23151
|
+
contentWidthPx - tableIndentPx - resolveCollapsedTableHorizontalOuterBleedPx(table, columnCount)
|
|
22580
23152
|
);
|
|
22581
|
-
|
|
23153
|
+
const resolvedTableWidthPx = clampTableWidthPx(
|
|
23154
|
+
rawResolvedTableWidthPx,
|
|
23155
|
+
maxTableWidthPx
|
|
23156
|
+
);
|
|
23157
|
+
const { columnWidthsPx } = resolveFittedTableColumnWidths(
|
|
23158
|
+
table,
|
|
23159
|
+
rawTableColumnWidthsPx,
|
|
23160
|
+
resolvedTableWidthPx
|
|
23161
|
+
);
|
|
23162
|
+
const rowHeightsPx = estimateTableRowHeightsPx(
|
|
23163
|
+
table,
|
|
23164
|
+
contentWidthPx,
|
|
23165
|
+
numberingDefinitions,
|
|
23166
|
+
docGridLinePitchPx,
|
|
23167
|
+
contentHeightPx
|
|
23168
|
+
);
|
|
23169
|
+
const startRowIndex = Math.max(
|
|
23170
|
+
0,
|
|
23171
|
+
segment.tableRowSlice?.rowIndex ?? segment.tableRowRange?.startRowIndex ?? 0
|
|
23172
|
+
);
|
|
23173
|
+
const endRowIndex = Math.min(
|
|
23174
|
+
table.rows.length,
|
|
23175
|
+
segment.tableRowSlice ? startRowIndex + 1 : segment.tableRowRange?.endRowIndex ?? table.rows.length
|
|
23176
|
+
);
|
|
23177
|
+
const cells = [];
|
|
23178
|
+
let rowYPx = segment.tableRowSlice ? -Math.max(0, segment.tableRowSlice.startOffsetPx) : 0;
|
|
23179
|
+
for (let rowIndex = startRowIndex; rowIndex < endRowIndex && cells.length < DOCX_DIRECT_THUMBNAIL_MAX_TABLE_CELLS; rowIndex += 1) {
|
|
23180
|
+
const row = table.rows[rowIndex];
|
|
23181
|
+
if (!row) {
|
|
23182
|
+
continue;
|
|
23183
|
+
}
|
|
23184
|
+
const rowHeightPx = segment.tableRowSlice && rowIndex === segment.tableRowSlice.rowIndex ? Math.max(1, segment.tableRowSlice.totalRowHeightPx) : Math.max(1, rowHeightsPx[rowIndex] ?? MIN_PARAGRAPH_LINE_HEIGHT_PX);
|
|
23185
|
+
let columnCursor = 0;
|
|
23186
|
+
row.cells.forEach((cell) => {
|
|
23187
|
+
if (cells.length >= DOCX_DIRECT_THUMBNAIL_MAX_TABLE_CELLS) {
|
|
23188
|
+
return;
|
|
23189
|
+
}
|
|
23190
|
+
const span = cell.style?.gridSpan && cell.style.gridSpan > 1 ? cell.style.gridSpan : 1;
|
|
23191
|
+
const xPx = columnWidthsPx.slice(0, columnCursor).reduce((sum, widthPx2) => sum + widthPx2, 0);
|
|
23192
|
+
const widthPx = columnWidthsPx.slice(columnCursor, columnCursor + span).reduce((sum, widthPx2) => sum + widthPx2, 0);
|
|
23193
|
+
columnCursor += span;
|
|
23194
|
+
cells.push({
|
|
23195
|
+
xPx,
|
|
23196
|
+
yPx: rowYPx,
|
|
23197
|
+
widthPx: Math.max(1, widthPx),
|
|
23198
|
+
heightPx: rowHeightPx,
|
|
23199
|
+
backgroundColor: normalizeDocxThumbnailColor(
|
|
23200
|
+
cell.style?.backgroundColor ?? row.style?.backgroundColor
|
|
23201
|
+
),
|
|
23202
|
+
runs: docxThumbnailCellTextRuns(cell, documentTheme)
|
|
23203
|
+
});
|
|
23204
|
+
});
|
|
23205
|
+
rowYPx += rowHeightPx;
|
|
23206
|
+
}
|
|
23207
|
+
if (cells.length === 0) {
|
|
23208
|
+
return void 0;
|
|
23209
|
+
}
|
|
23210
|
+
return {
|
|
23211
|
+
kind: "table",
|
|
23212
|
+
xPx: contentLeftPx + tableIndentPx,
|
|
23213
|
+
yPx,
|
|
23214
|
+
widthPx: Math.max(1, resolvedTableWidthPx),
|
|
23215
|
+
heightPx: Math.max(1, heightPx),
|
|
23216
|
+
cells
|
|
23217
|
+
};
|
|
23218
|
+
}
|
|
23219
|
+
function buildDocxPageThumbnailRenderSnapshotEntries(params) {
|
|
23220
|
+
const {
|
|
23221
|
+
model,
|
|
23222
|
+
pageNodeSegmentsByPage,
|
|
23223
|
+
pageSectionInfoByIndex,
|
|
23224
|
+
contentKeysByPage,
|
|
23225
|
+
fallbackLayout,
|
|
23226
|
+
documentTheme,
|
|
23227
|
+
docGridLinePitchPxByNodeIndex,
|
|
23228
|
+
numberingDefinitions
|
|
23229
|
+
} = params;
|
|
23230
|
+
return pageNodeSegmentsByPage.map((pageSegments, pageIndex) => {
|
|
23231
|
+
const key = `${contentKeysByPage[pageIndex] ?? ""}|theme:${documentTheme}`;
|
|
23232
|
+
let cachedSnapshot;
|
|
23233
|
+
return {
|
|
23234
|
+
key,
|
|
23235
|
+
getSnapshot: () => {
|
|
23236
|
+
if (cachedSnapshot) {
|
|
23237
|
+
return cachedSnapshot;
|
|
23238
|
+
}
|
|
23239
|
+
const pageLayout = pageSectionInfoByIndex[pageIndex]?.layout ?? fallbackLayout;
|
|
23240
|
+
const contentLeftPx = pageLayout.marginsPx.left;
|
|
23241
|
+
const contentTopPx = pageLayout.marginsPx.top;
|
|
23242
|
+
const contentWidthPx = Math.max(
|
|
23243
|
+
1,
|
|
23244
|
+
pageLayout.pageWidthPx - pageLayout.marginsPx.left - pageLayout.marginsPx.right
|
|
23245
|
+
);
|
|
23246
|
+
const contentHeightPx = Math.max(
|
|
23247
|
+
1,
|
|
23248
|
+
pageLayout.pageHeightPx - pageLayout.marginsPx.top - pageLayout.marginsPx.bottom
|
|
23249
|
+
);
|
|
23250
|
+
const elements = [];
|
|
23251
|
+
let yPx = contentTopPx;
|
|
23252
|
+
for (const segment of pageSegments) {
|
|
23253
|
+
if (elements.length >= DOCX_DIRECT_THUMBNAIL_MAX_ELEMENTS_PER_PAGE) {
|
|
23254
|
+
break;
|
|
23255
|
+
}
|
|
23256
|
+
const node = model.nodes[segment.nodeIndex];
|
|
23257
|
+
if (!node) {
|
|
23258
|
+
continue;
|
|
23259
|
+
}
|
|
23260
|
+
const docGridLinePitchPx = docGridLinePitchPxByNodeIndex.get(
|
|
23261
|
+
segment.nodeIndex
|
|
23262
|
+
);
|
|
23263
|
+
const segmentHeightPx = estimateRenderedPageSegmentHeightPx(
|
|
23264
|
+
node,
|
|
23265
|
+
segment,
|
|
23266
|
+
model,
|
|
23267
|
+
contentWidthPx,
|
|
23268
|
+
numberingDefinitions,
|
|
23269
|
+
docGridLinePitchPx
|
|
23270
|
+
);
|
|
23271
|
+
if (node.type === "paragraph" && !segment.tableRowRange) {
|
|
23272
|
+
elements.push(
|
|
23273
|
+
...buildDocxThumbnailParagraphElements({
|
|
23274
|
+
paragraph: node,
|
|
23275
|
+
segment,
|
|
23276
|
+
contentLeftPx,
|
|
23277
|
+
contentTopPx,
|
|
23278
|
+
contentWidthPx,
|
|
23279
|
+
yPx,
|
|
23280
|
+
heightPx: segmentHeightPx,
|
|
23281
|
+
numberingDefinitions,
|
|
23282
|
+
docGridLinePitchPx,
|
|
23283
|
+
documentTheme
|
|
23284
|
+
})
|
|
23285
|
+
);
|
|
23286
|
+
} else if (node.type === "table") {
|
|
23287
|
+
const tableElement = buildDocxThumbnailTableElement({
|
|
23288
|
+
table: node,
|
|
23289
|
+
segment,
|
|
23290
|
+
contentLeftPx,
|
|
23291
|
+
contentWidthPx,
|
|
23292
|
+
contentHeightPx,
|
|
23293
|
+
yPx,
|
|
23294
|
+
heightPx: segmentHeightPx,
|
|
23295
|
+
numberingDefinitions,
|
|
23296
|
+
docGridLinePitchPx,
|
|
23297
|
+
documentTheme
|
|
23298
|
+
});
|
|
23299
|
+
if (tableElement) {
|
|
23300
|
+
elements.push(tableElement);
|
|
23301
|
+
}
|
|
23302
|
+
}
|
|
23303
|
+
yPx += Math.max(1, segmentHeightPx);
|
|
23304
|
+
}
|
|
23305
|
+
cachedSnapshot = {
|
|
23306
|
+
key,
|
|
23307
|
+
sourceWidthPx: pageLayout.pageWidthPx,
|
|
23308
|
+
sourceHeightPx: pageLayout.pageHeightPx,
|
|
23309
|
+
pageBackgroundColor: documentTheme === "dark" ? "#111827" : "#ffffff",
|
|
23310
|
+
elements
|
|
23311
|
+
};
|
|
23312
|
+
return cachedSnapshot;
|
|
23313
|
+
}
|
|
23314
|
+
};
|
|
23315
|
+
});
|
|
23316
|
+
}
|
|
23317
|
+
function DocxDetachedThumbnailPageSurface({
|
|
23318
|
+
editor,
|
|
23319
|
+
pageIndex
|
|
23320
|
+
}) {
|
|
23321
|
+
return /* @__PURE__ */ jsx(
|
|
23322
|
+
DocxEditorViewer,
|
|
23323
|
+
{
|
|
23324
|
+
editor,
|
|
23325
|
+
mode: "read-only",
|
|
23326
|
+
visiblePageRange: { startPageIndex: pageIndex, endPageIndex: pageIndex },
|
|
23327
|
+
pageVirtualization: { enabled: false },
|
|
23328
|
+
showTrackedChanges: editor.showTrackedChanges,
|
|
23329
|
+
showComments: editor.showComments,
|
|
23330
|
+
style: {
|
|
23331
|
+
background: "transparent",
|
|
23332
|
+
padding: 0,
|
|
23333
|
+
margin: 0
|
|
23334
|
+
}
|
|
23335
|
+
}
|
|
23336
|
+
);
|
|
23337
|
+
}
|
|
23338
|
+
var DocxDetachedThumbnailSurfaceRenderer = class {
|
|
23339
|
+
host;
|
|
23340
|
+
root;
|
|
23341
|
+
activePageIndex;
|
|
23342
|
+
activeRenderKey;
|
|
23343
|
+
async renderPageSurface(params) {
|
|
23344
|
+
if (typeof document === "undefined" || typeof window === "undefined") {
|
|
23345
|
+
return void 0;
|
|
23346
|
+
}
|
|
23347
|
+
const { editor, registry, pageIndex, renderKey } = params;
|
|
23348
|
+
await this.ensureRoot();
|
|
23349
|
+
if (!this.root) {
|
|
23350
|
+
return void 0;
|
|
23351
|
+
}
|
|
23352
|
+
if (this.activePageIndex !== pageIndex || this.activeRenderKey !== renderKey) {
|
|
23353
|
+
this.activePageIndex = pageIndex;
|
|
23354
|
+
this.activeRenderKey = renderKey;
|
|
23355
|
+
this.root.render(
|
|
23356
|
+
/* @__PURE__ */ jsx(
|
|
23357
|
+
DocxDetachedThumbnailPageSurface,
|
|
23358
|
+
{
|
|
23359
|
+
editor,
|
|
23360
|
+
pageIndex
|
|
23361
|
+
}
|
|
23362
|
+
)
|
|
23363
|
+
);
|
|
23364
|
+
}
|
|
23365
|
+
return this.waitForPageSurface(registry, pageIndex);
|
|
23366
|
+
}
|
|
23367
|
+
clear() {
|
|
23368
|
+
if (this.root) {
|
|
23369
|
+
this.root.unmount();
|
|
23370
|
+
this.root = void 0;
|
|
23371
|
+
}
|
|
23372
|
+
if (this.host?.parentNode) {
|
|
23373
|
+
this.host.parentNode.removeChild(this.host);
|
|
23374
|
+
}
|
|
23375
|
+
this.host = void 0;
|
|
23376
|
+
this.activePageIndex = void 0;
|
|
23377
|
+
this.activeRenderKey = void 0;
|
|
23378
|
+
}
|
|
23379
|
+
async ensureRoot() {
|
|
23380
|
+
if (this.root) {
|
|
23381
|
+
return;
|
|
23382
|
+
}
|
|
23383
|
+
if (typeof document === "undefined") {
|
|
23384
|
+
return;
|
|
23385
|
+
}
|
|
23386
|
+
const host = document.createElement("div");
|
|
23387
|
+
host.setAttribute("data-docx-thumbnail-detached-renderer", "true");
|
|
23388
|
+
Object.assign(host.style, {
|
|
23389
|
+
position: "fixed",
|
|
23390
|
+
left: "-100000px",
|
|
23391
|
+
top: "0",
|
|
23392
|
+
width: "1px",
|
|
23393
|
+
height: "1px",
|
|
23394
|
+
overflow: "visible",
|
|
23395
|
+
opacity: "0",
|
|
23396
|
+
pointerEvents: "none",
|
|
23397
|
+
zIndex: "-1"
|
|
23398
|
+
});
|
|
23399
|
+
document.body.appendChild(host);
|
|
23400
|
+
this.host = host;
|
|
23401
|
+
const { createRoot } = await import("react-dom/client");
|
|
23402
|
+
this.root = createRoot(host);
|
|
23403
|
+
}
|
|
23404
|
+
async waitForPageSurface(registry, pageIndex) {
|
|
23405
|
+
for (let attempt = 0; attempt < 8; attempt += 1) {
|
|
23406
|
+
const pageElement2 = registry.pageElements.get(pageIndex);
|
|
23407
|
+
if (pageElement2?.isConnected) {
|
|
23408
|
+
return pageElement2;
|
|
23409
|
+
}
|
|
23410
|
+
await new Promise((resolve) => {
|
|
23411
|
+
window.requestAnimationFrame(() => resolve());
|
|
23412
|
+
});
|
|
23413
|
+
}
|
|
23414
|
+
const pageElement = registry.pageElements.get(pageIndex);
|
|
23415
|
+
return pageElement?.isConnected ? pageElement : void 0;
|
|
23416
|
+
}
|
|
23417
|
+
};
|
|
23418
|
+
var DOCX_THUMBNAIL_SURFACE_CACHE_MAX_ENTRIES = 64;
|
|
23419
|
+
var DOCX_THUMBNAIL_MIN_RASTER_INTERVAL_MS = 200;
|
|
23420
|
+
var DOCX_THUMBNAIL_RENDER_PRIORITY_VISIBLE = 0;
|
|
23421
|
+
var DOCX_THUMBNAIL_RENDER_PRIORITY_ATTACHED = 1;
|
|
23422
|
+
var DOCX_THUMBNAIL_RENDER_PRIORITY_PREFETCH = 2;
|
|
23423
|
+
function normalizeDocxThumbnailMinRasterIntervalMs(value) {
|
|
23424
|
+
return Number.isFinite(value) && Number(value) >= 0 ? Number(value) : DOCX_THUMBNAIL_MIN_RASTER_INTERVAL_MS;
|
|
23425
|
+
}
|
|
23426
|
+
function normalizeDocxThumbnailPageIndexes(indexes, totalPages) {
|
|
23427
|
+
if (!indexes?.length || totalPages <= 0) {
|
|
23428
|
+
return [];
|
|
23429
|
+
}
|
|
23430
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23431
|
+
const normalized = [];
|
|
23432
|
+
indexes.forEach((pageIndex) => {
|
|
23433
|
+
if (!Number.isFinite(pageIndex)) {
|
|
23434
|
+
return;
|
|
23435
|
+
}
|
|
23436
|
+
const roundedPageIndex = Math.trunc(pageIndex);
|
|
23437
|
+
if (roundedPageIndex < 0 || roundedPageIndex >= totalPages || seen.has(roundedPageIndex)) {
|
|
23438
|
+
return;
|
|
23439
|
+
}
|
|
23440
|
+
seen.add(roundedPageIndex);
|
|
23441
|
+
normalized.push(roundedPageIndex);
|
|
23442
|
+
});
|
|
23443
|
+
return normalized;
|
|
23444
|
+
}
|
|
23445
|
+
function docxThumbnailPageIndexesKey(pageIndexes) {
|
|
23446
|
+
return pageIndexes.join(",");
|
|
23447
|
+
}
|
|
23448
|
+
function docxThumbnailCanvasQueueKey(canvasId) {
|
|
23449
|
+
return `canvas:${canvasId}`;
|
|
23450
|
+
}
|
|
23451
|
+
function docxThumbnailPrefetchQueueKey(pageIndex) {
|
|
23452
|
+
return `prefetch:${pageIndex}`;
|
|
23453
|
+
}
|
|
23454
|
+
function resolveDocxPageThumbnailResolution(options) {
|
|
23455
|
+
const safeSourceWidthPx = Math.max(1, Math.round(options.sourceWidthPx));
|
|
23456
|
+
const safeSourceHeightPx = Math.max(1, Math.round(options.sourceHeightPx));
|
|
23457
|
+
const resolutionBounds = typeof options.resolution === "number" && Number.isFinite(options.resolution) && options.resolution > 0 ? {
|
|
23458
|
+
maxWidthPx: Number(options.resolution),
|
|
23459
|
+
maxHeightPx: Number(options.resolution)
|
|
23460
|
+
} : typeof options.resolution === "object" && options.resolution ? {
|
|
23461
|
+
maxWidthPx: Number.isFinite(options.resolution.maxWidth) && Number(options.resolution.maxWidth) > 0 ? Number(options.resolution.maxWidth) : void 0,
|
|
23462
|
+
maxHeightPx: Number.isFinite(options.resolution.maxHeight) && Number(options.resolution.maxHeight) > 0 ? Number(options.resolution.maxHeight) : void 0
|
|
23463
|
+
} : void 0;
|
|
23464
|
+
const widthBoundPx = Number.isFinite(options.maxWidthPx) ? Math.max(1, Math.round(options.maxWidthPx)) : Number.isFinite(resolutionBounds?.maxWidthPx) ? Math.max(1, Math.round(resolutionBounds?.maxWidthPx)) : 180;
|
|
23465
|
+
const heightBoundPx = Number.isFinite(options.maxHeightPx) ? Math.max(1, Math.round(options.maxHeightPx)) : Number.isFinite(resolutionBounds?.maxHeightPx) ? Math.max(1, Math.round(resolutionBounds?.maxHeightPx)) : Number.POSITIVE_INFINITY;
|
|
23466
|
+
const scale = Math.min(
|
|
23467
|
+
1,
|
|
23468
|
+
widthBoundPx / safeSourceWidthPx,
|
|
23469
|
+
heightBoundPx / safeSourceHeightPx
|
|
23470
|
+
);
|
|
23471
|
+
const pixelRatio = Number.isFinite(options.pixelRatio) ? Math.max(1, Number(options.pixelRatio)) : 1;
|
|
23472
|
+
const widthPx = Math.max(1, Math.round(safeSourceWidthPx * scale));
|
|
23473
|
+
const heightPx = Math.max(1, Math.round(safeSourceHeightPx * scale));
|
|
23474
|
+
return {
|
|
23475
|
+
widthPx,
|
|
23476
|
+
heightPx,
|
|
23477
|
+
pixelWidthPx: Math.max(1, Math.round(widthPx * pixelRatio)),
|
|
23478
|
+
pixelHeightPx: Math.max(1, Math.round(heightPx * pixelRatio)),
|
|
23479
|
+
scale
|
|
23480
|
+
};
|
|
23481
|
+
}
|
|
23482
|
+
function useDocxPageThumbnails(editor, options = {}) {
|
|
23483
|
+
const pageSurfaceRegistryOwner = docxViewerPageSurfaceRegistryOwner(editor);
|
|
23484
|
+
const pageSurfaceRegistryEditor = React.useMemo(
|
|
23485
|
+
() => ({ syncPaginationInfo: editor.syncPaginationInfo }),
|
|
23486
|
+
[pageSurfaceRegistryOwner]
|
|
23487
|
+
);
|
|
23488
|
+
const [pageSurfaceEpoch, setPageSurfaceEpoch] = React.useState(0);
|
|
23489
|
+
const [pageThumbnailStates, setPageThumbnailStates] = React.useState(() => /* @__PURE__ */ new Map());
|
|
23490
|
+
const attachedCanvasByPageRef = React.useRef(
|
|
23491
|
+
/* @__PURE__ */ new Map()
|
|
23492
|
+
);
|
|
23493
|
+
const canvasRefCallbacksRef = React.useRef(/* @__PURE__ */ new Map());
|
|
23494
|
+
const renderToCanvasCallbacksRef = React.useRef(/* @__PURE__ */ new Map());
|
|
23495
|
+
const fallbackLayout = React.useMemo(
|
|
23496
|
+
() => resolveDocumentLayout(editor.model),
|
|
23497
|
+
[editor.model]
|
|
23498
|
+
);
|
|
23499
|
+
const pageSurfaceRegistry = React.useMemo(
|
|
23500
|
+
() => ensureDocxViewerPageSurfaceRegistry(pageSurfaceRegistryEditor),
|
|
23501
|
+
[pageSurfaceRegistryEditor]
|
|
23502
|
+
);
|
|
23503
|
+
React.useEffect(
|
|
22582
23504
|
() => subscribeDocxViewerPageSurfaces(pageSurfaceRegistryEditor, () => {
|
|
22583
23505
|
setPageSurfaceEpoch((current) => current + 1);
|
|
22584
23506
|
}),
|
|
@@ -22604,9 +23526,16 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
22604
23526
|
);
|
|
22605
23527
|
const thumbnailSurfaceCacheRef = React.useRef(void 0);
|
|
22606
23528
|
const thumbnailRasterQueueRef = React.useRef(void 0);
|
|
23529
|
+
const detachedThumbnailSurfaceRendererRef = React.useRef(void 0);
|
|
22607
23530
|
const lastPaintedThumbnailKeyByCanvasRef = React.useRef(
|
|
22608
23531
|
/* @__PURE__ */ new WeakMap()
|
|
22609
23532
|
);
|
|
23533
|
+
const thumbnailQueueKeyByCanvasRef = React.useRef(
|
|
23534
|
+
/* @__PURE__ */ new WeakMap()
|
|
23535
|
+
);
|
|
23536
|
+
const nextThumbnailCanvasQueueIdRef = React.useRef(0);
|
|
23537
|
+
const queuedPrefetchThumbnailKeysRef = React.useRef(/* @__PURE__ */ new Set());
|
|
23538
|
+
const thumbnailMinRasterIntervalMs = normalizeDocxThumbnailMinRasterIntervalMs(options.minRasterIntervalMs);
|
|
22610
23539
|
const ensureThumbnailSurfaceCache = React.useCallback(() => {
|
|
22611
23540
|
if (!thumbnailSurfaceCacheRef.current) {
|
|
22612
23541
|
thumbnailSurfaceCacheRef.current = new DocxThumbnailSurfaceCache(
|
|
@@ -22618,16 +23547,57 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
22618
23547
|
const ensureThumbnailRasterQueue = React.useCallback(() => {
|
|
22619
23548
|
if (!thumbnailRasterQueueRef.current) {
|
|
22620
23549
|
thumbnailRasterQueueRef.current = new SerialIdleTaskQueue({
|
|
22621
|
-
minTaskIntervalMs:
|
|
23550
|
+
minTaskIntervalMs: thumbnailMinRasterIntervalMs
|
|
22622
23551
|
});
|
|
22623
23552
|
}
|
|
22624
23553
|
return thumbnailRasterQueueRef.current;
|
|
22625
|
-
}, []);
|
|
23554
|
+
}, [thumbnailMinRasterIntervalMs]);
|
|
23555
|
+
const thumbnailQueueKeyForCanvas = React.useCallback(
|
|
23556
|
+
(canvas) => {
|
|
23557
|
+
const existing = thumbnailQueueKeyByCanvasRef.current.get(canvas);
|
|
23558
|
+
if (existing) {
|
|
23559
|
+
return existing;
|
|
23560
|
+
}
|
|
23561
|
+
const nextKey = docxThumbnailCanvasQueueKey(
|
|
23562
|
+
nextThumbnailCanvasQueueIdRef.current
|
|
23563
|
+
);
|
|
23564
|
+
nextThumbnailCanvasQueueIdRef.current += 1;
|
|
23565
|
+
thumbnailQueueKeyByCanvasRef.current.set(canvas, nextKey);
|
|
23566
|
+
return nextKey;
|
|
23567
|
+
},
|
|
23568
|
+
[]
|
|
23569
|
+
);
|
|
23570
|
+
React.useEffect(() => {
|
|
23571
|
+
thumbnailRasterQueueRef.current?.clear();
|
|
23572
|
+
thumbnailRasterQueueRef.current = void 0;
|
|
23573
|
+
queuedPrefetchThumbnailKeysRef.current.clear();
|
|
23574
|
+
}, [thumbnailMinRasterIntervalMs]);
|
|
22626
23575
|
React.useEffect(() => {
|
|
22627
23576
|
thumbnailSurfaceCacheRef.current?.clear();
|
|
22628
23577
|
thumbnailRasterQueueRef.current?.clear();
|
|
23578
|
+
detachedThumbnailSurfaceRendererRef.current?.clear();
|
|
23579
|
+
detachedThumbnailSurfaceRendererRef.current = void 0;
|
|
22629
23580
|
lastPaintedThumbnailKeyByCanvasRef.current = /* @__PURE__ */ new WeakMap();
|
|
23581
|
+
thumbnailQueueKeyByCanvasRef.current = /* @__PURE__ */ new WeakMap();
|
|
23582
|
+
nextThumbnailCanvasQueueIdRef.current = 0;
|
|
23583
|
+
queuedPrefetchThumbnailKeysRef.current.clear();
|
|
22630
23584
|
}, [editor.documentLoadNonce, pageSurfaceRegistryOwner]);
|
|
23585
|
+
React.useEffect(() => {
|
|
23586
|
+
detachedThumbnailSurfaceRendererRef.current?.clear();
|
|
23587
|
+
detachedThumbnailSurfaceRendererRef.current = void 0;
|
|
23588
|
+
}, [
|
|
23589
|
+
editor.documentTheme,
|
|
23590
|
+
editor.model,
|
|
23591
|
+
editor.showComments,
|
|
23592
|
+
editor.showTrackedChanges
|
|
23593
|
+
]);
|
|
23594
|
+
React.useEffect(
|
|
23595
|
+
() => () => {
|
|
23596
|
+
detachedThumbnailSurfaceRendererRef.current?.clear();
|
|
23597
|
+
detachedThumbnailSurfaceRendererRef.current = void 0;
|
|
23598
|
+
},
|
|
23599
|
+
[]
|
|
23600
|
+
);
|
|
22631
23601
|
const thumbnailResolutionOptionsKey = React.useMemo(() => {
|
|
22632
23602
|
const bounds = options.resolution;
|
|
22633
23603
|
const boundsKey = typeof bounds === "number" ? `n${bounds}` : bounds ? `b${bounds.maxWidth ?? ""}x${bounds.maxHeight ?? ""}` : "";
|
|
@@ -22645,6 +23615,125 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
22645
23615
|
},
|
|
22646
23616
|
[editor.documentTheme, pageSurfaceRegistry, thumbnailResolutionOptionsKey]
|
|
22647
23617
|
);
|
|
23618
|
+
const totalThumbnailPages = Math.max(1, editor.totalPages);
|
|
23619
|
+
const visibleThumbnailPageIndexes = React.useMemo(
|
|
23620
|
+
() => normalizeDocxThumbnailPageIndexes(
|
|
23621
|
+
options.renderWindow?.visiblePageIndexes,
|
|
23622
|
+
totalThumbnailPages
|
|
23623
|
+
),
|
|
23624
|
+
[options.renderWindow?.visiblePageIndexes, totalThumbnailPages]
|
|
23625
|
+
);
|
|
23626
|
+
const prefetchThumbnailPageIndexes = React.useMemo(
|
|
23627
|
+
() => normalizeDocxThumbnailPageIndexes(
|
|
23628
|
+
options.renderWindow?.prefetchPageIndexes,
|
|
23629
|
+
totalThumbnailPages
|
|
23630
|
+
),
|
|
23631
|
+
[options.renderWindow?.prefetchPageIndexes, totalThumbnailPages]
|
|
23632
|
+
);
|
|
23633
|
+
const visibleThumbnailPageIndexesKey = docxThumbnailPageIndexesKey(
|
|
23634
|
+
visibleThumbnailPageIndexes
|
|
23635
|
+
);
|
|
23636
|
+
const prefetchThumbnailPageIndexesKey = docxThumbnailPageIndexesKey(
|
|
23637
|
+
prefetchThumbnailPageIndexes
|
|
23638
|
+
);
|
|
23639
|
+
const visibleThumbnailPageIndexSet = React.useMemo(
|
|
23640
|
+
() => new Set(visibleThumbnailPageIndexes),
|
|
23641
|
+
[visibleThumbnailPageIndexesKey]
|
|
23642
|
+
);
|
|
23643
|
+
const thumbnailRenderPriorityForPage = React.useCallback(
|
|
23644
|
+
(pageIndex, fallbackPriority = DOCX_THUMBNAIL_RENDER_PRIORITY_ATTACHED) => visibleThumbnailPageIndexSet.has(pageIndex) ? DOCX_THUMBNAIL_RENDER_PRIORITY_VISIBLE : fallbackPriority,
|
|
23645
|
+
[visibleThumbnailPageIndexSet]
|
|
23646
|
+
);
|
|
23647
|
+
const renderPageThumbnailSurface = React.useCallback(
|
|
23648
|
+
async (pageIndex, renderOptions) => {
|
|
23649
|
+
const force = renderOptions?.force === true;
|
|
23650
|
+
const runSkipKey = thumbnailSkipKeyForPage(pageIndex);
|
|
23651
|
+
const detachedRenderKey = [
|
|
23652
|
+
runSkipKey ?? `load:${editor.documentLoadNonce}`,
|
|
23653
|
+
editor.showComments ? "comments:1" : "comments:0",
|
|
23654
|
+
editor.showTrackedChanges ? "tracked:1" : "tracked:0"
|
|
23655
|
+
].join("|");
|
|
23656
|
+
const thumbnailSnapshotEntry = pageSurfaceRegistry.pageThumbnailSnapshots.get(pageIndex);
|
|
23657
|
+
const fallbackSourceSize = resolveDocxViewerRegisteredPageSurfaceSize(
|
|
23658
|
+
pageSurfaceRegistry,
|
|
23659
|
+
pageIndex,
|
|
23660
|
+
fallbackLayout.pageWidthPx,
|
|
23661
|
+
fallbackLayout.pageHeightPx
|
|
23662
|
+
);
|
|
23663
|
+
const resolution = resolveDocxPageThumbnailResolution({
|
|
23664
|
+
sourceWidthPx: fallbackSourceSize.widthPx,
|
|
23665
|
+
sourceHeightPx: fallbackSourceSize.heightPx,
|
|
23666
|
+
resolution: options.resolution,
|
|
23667
|
+
maxWidthPx: options.maxWidthPx,
|
|
23668
|
+
maxHeightPx: options.maxHeightPx,
|
|
23669
|
+
pixelRatio: options.pixelRatio
|
|
23670
|
+
});
|
|
23671
|
+
const surfaceKey = runSkipKey === void 0 ? void 0 : `${runSkipKey}|${fallbackSourceSize.widthPx}x${fallbackSourceSize.heightPx}|${resolution.pixelWidthPx}x${resolution.pixelHeightPx}`;
|
|
23672
|
+
const surfaceCache = ensureThumbnailSurfaceCache();
|
|
23673
|
+
let surface = !force && surfaceKey !== void 0 ? surfaceCache.get(surfaceKey) : void 0;
|
|
23674
|
+
if (!surface) {
|
|
23675
|
+
const thumbnailSnapshot = thumbnailSnapshotEntry?.getSnapshot();
|
|
23676
|
+
if (thumbnailSnapshot) {
|
|
23677
|
+
surface = renderDocxThumbnailSnapshotSurface({
|
|
23678
|
+
snapshot: thumbnailSnapshot,
|
|
23679
|
+
widthPx: resolution.widthPx,
|
|
23680
|
+
heightPx: resolution.heightPx,
|
|
23681
|
+
pixelWidthPx: resolution.pixelWidthPx,
|
|
23682
|
+
pixelHeightPx: resolution.pixelHeightPx
|
|
23683
|
+
});
|
|
23684
|
+
if (surfaceKey !== void 0) {
|
|
23685
|
+
surfaceCache.set(surfaceKey, surface);
|
|
23686
|
+
}
|
|
23687
|
+
return { surface, resolution, runSkipKey };
|
|
23688
|
+
}
|
|
23689
|
+
let livePageElement = pageSurfaceRegistry.pageElements.get(pageIndex);
|
|
23690
|
+
if (!livePageElement || !livePageElement.isConnected) {
|
|
23691
|
+
if (!detachedThumbnailSurfaceRendererRef.current) {
|
|
23692
|
+
detachedThumbnailSurfaceRendererRef.current = new DocxDetachedThumbnailSurfaceRenderer();
|
|
23693
|
+
}
|
|
23694
|
+
livePageElement = await detachedThumbnailSurfaceRendererRef.current.renderPageSurface({
|
|
23695
|
+
editor,
|
|
23696
|
+
registry: pageSurfaceRegistry,
|
|
23697
|
+
pageIndex,
|
|
23698
|
+
renderKey: detachedRenderKey
|
|
23699
|
+
});
|
|
23700
|
+
}
|
|
23701
|
+
if (!livePageElement || !livePageElement.isConnected) {
|
|
23702
|
+
return void 0;
|
|
23703
|
+
}
|
|
23704
|
+
const sourceSize = resolveDocxViewerPageSurfaceSize(
|
|
23705
|
+
livePageElement,
|
|
23706
|
+
fallbackSourceSize.widthPx,
|
|
23707
|
+
fallbackSourceSize.heightPx
|
|
23708
|
+
);
|
|
23709
|
+
surface = await rasterizeDocxThumbnailSurface({
|
|
23710
|
+
pageElement: livePageElement,
|
|
23711
|
+
sourceWidthPx: sourceSize.widthPx,
|
|
23712
|
+
sourceHeightPx: sourceSize.heightPx,
|
|
23713
|
+
widthPx: resolution.widthPx,
|
|
23714
|
+
heightPx: resolution.heightPx,
|
|
23715
|
+
pixelWidthPx: resolution.pixelWidthPx,
|
|
23716
|
+
pixelHeightPx: resolution.pixelHeightPx
|
|
23717
|
+
});
|
|
23718
|
+
if (surfaceKey !== void 0) {
|
|
23719
|
+
surfaceCache.set(surfaceKey, surface);
|
|
23720
|
+
}
|
|
23721
|
+
}
|
|
23722
|
+
return { surface, resolution, runSkipKey };
|
|
23723
|
+
},
|
|
23724
|
+
[
|
|
23725
|
+
ensureThumbnailSurfaceCache,
|
|
23726
|
+
fallbackLayout.pageHeightPx,
|
|
23727
|
+
fallbackLayout.pageWidthPx,
|
|
23728
|
+
options.resolution,
|
|
23729
|
+
options.maxHeightPx,
|
|
23730
|
+
options.maxWidthPx,
|
|
23731
|
+
options.pixelRatio,
|
|
23732
|
+
pageSurfaceRegistry,
|
|
23733
|
+
thumbnailSkipKeyForPage,
|
|
23734
|
+
editor
|
|
23735
|
+
]
|
|
23736
|
+
);
|
|
22648
23737
|
const renderPageThumbnailToCanvas = React.useCallback(
|
|
22649
23738
|
async (pageIndex, canvas, renderOptions) => {
|
|
22650
23739
|
if (options.disabled) {
|
|
@@ -22655,59 +23744,25 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
22655
23744
|
return;
|
|
22656
23745
|
}
|
|
22657
23746
|
const requiresAttachedTarget = canvas === void 0;
|
|
22658
|
-
const pageElement = pageSurfaceRegistry.pageElements.get(pageIndex);
|
|
22659
|
-
if (!pageElement || !pageElement.isConnected) {
|
|
22660
|
-
updatePageThumbnailState(pageIndex, "unavailable");
|
|
22661
|
-
return;
|
|
22662
|
-
}
|
|
22663
23747
|
const force = renderOptions?.force === true;
|
|
22664
23748
|
const lastPaintedKey = lastPaintedThumbnailKeyByCanvasRef.current.get(targetCanvas);
|
|
22665
23749
|
if (!force && lastPaintedKey !== void 0 && lastPaintedKey === thumbnailSkipKeyForPage(pageIndex)) {
|
|
22666
23750
|
updatePageThumbnailState(pageIndex, "ready");
|
|
22667
23751
|
return;
|
|
22668
23752
|
}
|
|
22669
|
-
|
|
22670
|
-
await ensureThumbnailRasterQueue().enqueue(targetCanvas, async () => {
|
|
23753
|
+
const paintIntoTarget = async () => {
|
|
22671
23754
|
if (requiresAttachedTarget && attachedCanvasByPageRef.current.get(pageIndex) !== targetCanvas) {
|
|
22672
23755
|
return;
|
|
22673
23756
|
}
|
|
22674
|
-
const livePageElement = pageSurfaceRegistry.pageElements.get(pageIndex);
|
|
22675
|
-
if (!livePageElement || !livePageElement.isConnected) {
|
|
22676
|
-
updatePageThumbnailState(pageIndex, "unavailable");
|
|
22677
|
-
return;
|
|
22678
|
-
}
|
|
22679
|
-
const runSkipKey = thumbnailSkipKeyForPage(pageIndex);
|
|
22680
|
-
const sourceSize = resolveDocxViewerPageSurfaceSize(
|
|
22681
|
-
livePageElement,
|
|
22682
|
-
fallbackLayout.pageWidthPx,
|
|
22683
|
-
fallbackLayout.pageHeightPx
|
|
22684
|
-
);
|
|
22685
|
-
const resolution = resolveDocxPageThumbnailResolution({
|
|
22686
|
-
sourceWidthPx: sourceSize.widthPx,
|
|
22687
|
-
sourceHeightPx: sourceSize.heightPx,
|
|
22688
|
-
resolution: options.resolution,
|
|
22689
|
-
maxWidthPx: options.maxWidthPx,
|
|
22690
|
-
maxHeightPx: options.maxHeightPx,
|
|
22691
|
-
pixelRatio: options.pixelRatio
|
|
22692
|
-
});
|
|
22693
|
-
const surfaceKey = runSkipKey === void 0 ? void 0 : `${runSkipKey}|${sourceSize.widthPx}x${sourceSize.heightPx}|${resolution.pixelWidthPx}x${resolution.pixelHeightPx}`;
|
|
22694
|
-
const surfaceCache = ensureThumbnailSurfaceCache();
|
|
22695
23757
|
try {
|
|
22696
|
-
|
|
22697
|
-
|
|
22698
|
-
|
|
22699
|
-
|
|
22700
|
-
|
|
22701
|
-
|
|
22702
|
-
widthPx: resolution.widthPx,
|
|
22703
|
-
heightPx: resolution.heightPx,
|
|
22704
|
-
pixelWidthPx: resolution.pixelWidthPx,
|
|
22705
|
-
pixelHeightPx: resolution.pixelHeightPx
|
|
22706
|
-
});
|
|
22707
|
-
if (surfaceKey !== void 0) {
|
|
22708
|
-
surfaceCache.set(surfaceKey, surface);
|
|
22709
|
-
}
|
|
23758
|
+
const rendered = await renderPageThumbnailSurface(pageIndex, {
|
|
23759
|
+
force
|
|
23760
|
+
});
|
|
23761
|
+
if (!rendered) {
|
|
23762
|
+
updatePageThumbnailState(pageIndex, "unavailable");
|
|
23763
|
+
return;
|
|
22710
23764
|
}
|
|
23765
|
+
const { surface, resolution, runSkipKey } = rendered;
|
|
22711
23766
|
blitDocxThumbnailSurface(surface, targetCanvas, resolution);
|
|
22712
23767
|
if (runSkipKey !== void 0) {
|
|
22713
23768
|
lastPaintedThumbnailKeyByCanvasRef.current.set(
|
|
@@ -22723,32 +23778,116 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
22723
23778
|
error instanceof Error ? error : new Error("Failed to render DOCX page thumbnail.")
|
|
22724
23779
|
);
|
|
22725
23780
|
}
|
|
22726
|
-
}
|
|
23781
|
+
};
|
|
23782
|
+
updatePageThumbnailState(pageIndex, "rendering");
|
|
23783
|
+
if (pageSurfaceRegistry.pageThumbnailSnapshots.has(pageIndex)) {
|
|
23784
|
+
await paintIntoTarget();
|
|
23785
|
+
return;
|
|
23786
|
+
}
|
|
23787
|
+
await ensureThumbnailRasterQueue().enqueue(
|
|
23788
|
+
thumbnailQueueKeyForCanvas(targetCanvas),
|
|
23789
|
+
paintIntoTarget,
|
|
23790
|
+
{
|
|
23791
|
+
priority: renderOptions?.priority ?? thumbnailRenderPriorityForPage(
|
|
23792
|
+
pageIndex,
|
|
23793
|
+
DOCX_THUMBNAIL_RENDER_PRIORITY_ATTACHED
|
|
23794
|
+
)
|
|
23795
|
+
}
|
|
23796
|
+
);
|
|
22727
23797
|
},
|
|
22728
23798
|
[
|
|
22729
23799
|
ensureThumbnailRasterQueue,
|
|
22730
|
-
ensureThumbnailSurfaceCache,
|
|
22731
|
-
fallbackLayout.pageHeightPx,
|
|
22732
|
-
fallbackLayout.pageWidthPx,
|
|
22733
23800
|
options.disabled,
|
|
22734
|
-
options.resolution,
|
|
22735
|
-
options.maxHeightPx,
|
|
22736
|
-
options.maxWidthPx,
|
|
22737
|
-
options.pixelRatio,
|
|
22738
23801
|
pageSurfaceRegistry,
|
|
23802
|
+
renderPageThumbnailSurface,
|
|
22739
23803
|
thumbnailSkipKeyForPage,
|
|
23804
|
+
thumbnailQueueKeyForCanvas,
|
|
23805
|
+
thumbnailRenderPriorityForPage,
|
|
22740
23806
|
updatePageThumbnailState
|
|
22741
23807
|
]
|
|
22742
23808
|
);
|
|
23809
|
+
const prefetchPageThumbnailSurface = React.useCallback(
|
|
23810
|
+
async (pageIndex) => {
|
|
23811
|
+
if (options.disabled) {
|
|
23812
|
+
return;
|
|
23813
|
+
}
|
|
23814
|
+
const queueKey = docxThumbnailPrefetchQueueKey(pageIndex);
|
|
23815
|
+
queuedPrefetchThumbnailKeysRef.current.add(queueKey);
|
|
23816
|
+
await ensureThumbnailRasterQueue().enqueue(
|
|
23817
|
+
queueKey,
|
|
23818
|
+
async () => {
|
|
23819
|
+
try {
|
|
23820
|
+
await renderPageThumbnailSurface(pageIndex);
|
|
23821
|
+
} catch {
|
|
23822
|
+
}
|
|
23823
|
+
},
|
|
23824
|
+
{ priority: DOCX_THUMBNAIL_RENDER_PRIORITY_PREFETCH }
|
|
23825
|
+
);
|
|
23826
|
+
queuedPrefetchThumbnailKeysRef.current.delete(queueKey);
|
|
23827
|
+
},
|
|
23828
|
+
[ensureThumbnailRasterQueue, options.disabled, renderPageThumbnailSurface]
|
|
23829
|
+
);
|
|
22743
23830
|
const requestAttachedThumbnailRenders = React.useCallback(
|
|
22744
23831
|
async (renderOptions) => {
|
|
22745
|
-
const
|
|
22746
|
-
(
|
|
23832
|
+
const attachedPageIndexes = [
|
|
23833
|
+
...attachedCanvasByPageRef.current.keys()
|
|
23834
|
+
].sort((leftPageIndex, rightPageIndex) => {
|
|
23835
|
+
const leftPriority = thumbnailRenderPriorityForPage(leftPageIndex);
|
|
23836
|
+
const rightPriority = thumbnailRenderPriorityForPage(rightPageIndex);
|
|
23837
|
+
return leftPriority - rightPriority || leftPageIndex - rightPageIndex;
|
|
23838
|
+
});
|
|
23839
|
+
const tasks = attachedPageIndexes.map(
|
|
23840
|
+
(pageIndex) => renderPageThumbnailToCanvas(pageIndex, void 0, {
|
|
23841
|
+
...renderOptions,
|
|
23842
|
+
priority: thumbnailRenderPriorityForPage(pageIndex)
|
|
23843
|
+
})
|
|
22747
23844
|
);
|
|
22748
23845
|
await Promise.all(tasks);
|
|
22749
23846
|
},
|
|
22750
|
-
[renderPageThumbnailToCanvas]
|
|
23847
|
+
[renderPageThumbnailToCanvas, thumbnailRenderPriorityForPage]
|
|
22751
23848
|
);
|
|
23849
|
+
const requestPrefetchThumbnailRenders = React.useCallback(async () => {
|
|
23850
|
+
if (options.disabled) {
|
|
23851
|
+
queuedPrefetchThumbnailKeysRef.current.forEach((queueKey) => {
|
|
23852
|
+
thumbnailRasterQueueRef.current?.cancel(queueKey);
|
|
23853
|
+
});
|
|
23854
|
+
queuedPrefetchThumbnailKeysRef.current.clear();
|
|
23855
|
+
return;
|
|
23856
|
+
}
|
|
23857
|
+
const requestedPrefetchKeys = new Set(
|
|
23858
|
+
prefetchThumbnailPageIndexes.map(
|
|
23859
|
+
(pageIndex) => docxThumbnailPrefetchQueueKey(pageIndex)
|
|
23860
|
+
)
|
|
23861
|
+
);
|
|
23862
|
+
queuedPrefetchThumbnailKeysRef.current.forEach((queueKey) => {
|
|
23863
|
+
if (!requestedPrefetchKeys.has(queueKey)) {
|
|
23864
|
+
thumbnailRasterQueueRef.current?.cancel(queueKey);
|
|
23865
|
+
queuedPrefetchThumbnailKeysRef.current.delete(queueKey);
|
|
23866
|
+
}
|
|
23867
|
+
});
|
|
23868
|
+
const tasks = prefetchThumbnailPageIndexes.map(
|
|
23869
|
+
(pageIndex) => prefetchPageThumbnailSurface(pageIndex)
|
|
23870
|
+
);
|
|
23871
|
+
await Promise.all(tasks);
|
|
23872
|
+
}, [
|
|
23873
|
+
options.disabled,
|
|
23874
|
+
prefetchPageThumbnailSurface,
|
|
23875
|
+
prefetchThumbnailPageIndexes
|
|
23876
|
+
]);
|
|
23877
|
+
React.useEffect(() => {
|
|
23878
|
+
void requestPrefetchThumbnailRenders();
|
|
23879
|
+
}, [
|
|
23880
|
+
editor.documentLoadNonce,
|
|
23881
|
+
editor.documentTheme,
|
|
23882
|
+
editor.model,
|
|
23883
|
+
mountedPageElements,
|
|
23884
|
+
options.maxHeightPx,
|
|
23885
|
+
options.maxWidthPx,
|
|
23886
|
+
options.pixelRatio,
|
|
23887
|
+
options.resolution,
|
|
23888
|
+
prefetchThumbnailPageIndexesKey,
|
|
23889
|
+
requestPrefetchThumbnailRenders
|
|
23890
|
+
]);
|
|
22752
23891
|
const rerenderAttachedThumbnails = React.useCallback(
|
|
22753
23892
|
async () => requestAttachedThumbnailRenders({ force: true }),
|
|
22754
23893
|
[requestAttachedThumbnailRenders]
|
|
@@ -22777,14 +23916,19 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
22777
23916
|
options.pixelRatio,
|
|
22778
23917
|
requestAttachedThumbnailRenders
|
|
22779
23918
|
]);
|
|
22780
|
-
const
|
|
23919
|
+
const thumbnailGeometryItems = React.useMemo(() => {
|
|
22781
23920
|
const totalPages = Math.max(1, editor.totalPages);
|
|
22782
23921
|
return Array.from({ length: totalPages }, (_, pageIndex) => {
|
|
22783
23922
|
const pageElement = mountedPageElements.get(pageIndex);
|
|
22784
|
-
const sourceSize = resolveDocxViewerPageSurfaceSize(
|
|
23923
|
+
const sourceSize = pageElement && pageElement.isConnected ? resolveDocxViewerPageSurfaceSize(
|
|
22785
23924
|
pageElement,
|
|
22786
23925
|
fallbackLayout.pageWidthPx,
|
|
22787
23926
|
fallbackLayout.pageHeightPx
|
|
23927
|
+
) : resolveDocxViewerRegisteredPageSurfaceSize(
|
|
23928
|
+
pageSurfaceRegistry,
|
|
23929
|
+
pageIndex,
|
|
23930
|
+
fallbackLayout.pageWidthPx,
|
|
23931
|
+
fallbackLayout.pageHeightPx
|
|
22788
23932
|
);
|
|
22789
23933
|
const resolution = resolveDocxPageThumbnailResolution({
|
|
22790
23934
|
sourceWidthPx: sourceSize.widthPx,
|
|
@@ -22794,15 +23938,14 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
22794
23938
|
maxHeightPx: options.maxHeightPx,
|
|
22795
23939
|
pixelRatio: options.pixelRatio
|
|
22796
23940
|
});
|
|
22797
|
-
const state = pageThumbnailStates.get(pageIndex);
|
|
22798
23941
|
return {
|
|
23942
|
+
// Internal: drives the default status below; stripped before exposure.
|
|
23943
|
+
hasElement: Boolean(pageElement),
|
|
22799
23944
|
pageIndex,
|
|
22800
23945
|
pageNumber: pageIndex + 1,
|
|
22801
23946
|
sourceWidthPx: sourceSize.widthPx,
|
|
22802
23947
|
sourceHeightPx: sourceSize.heightPx,
|
|
22803
23948
|
isMounted: Boolean(pageElement && pageElement.isConnected),
|
|
22804
|
-
status: state?.status ?? (pageElement ? "idle" : "unavailable"),
|
|
22805
|
-
error: state?.error,
|
|
22806
23949
|
paint: (canvas) => {
|
|
22807
23950
|
if (!canvas || options.disabled) {
|
|
22808
23951
|
return false;
|
|
@@ -22819,7 +23962,9 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
22819
23962
|
}
|
|
22820
23963
|
const previousCanvas = attachedCanvasByPageRef.current.get(pageIndex);
|
|
22821
23964
|
if (previousCanvas) {
|
|
22822
|
-
thumbnailRasterQueueRef.current?.cancel(
|
|
23965
|
+
thumbnailRasterQueueRef.current?.cancel(
|
|
23966
|
+
thumbnailQueueKeyForCanvas(previousCanvas)
|
|
23967
|
+
);
|
|
22823
23968
|
}
|
|
22824
23969
|
attachedCanvasByPageRef.current.delete(pageIndex);
|
|
22825
23970
|
};
|
|
@@ -22854,8 +23999,21 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
22854
23999
|
options.maxHeightPx,
|
|
22855
24000
|
options.maxWidthPx,
|
|
22856
24001
|
options.pixelRatio,
|
|
22857
|
-
|
|
24002
|
+
pageSurfaceRegistry,
|
|
24003
|
+
thumbnailQueueKeyForCanvas
|
|
22858
24004
|
]);
|
|
24005
|
+
const thumbnails = React.useMemo(
|
|
24006
|
+
() => thumbnailGeometryItems.map((geometryItem) => {
|
|
24007
|
+
const { hasElement, ...item } = geometryItem;
|
|
24008
|
+
const state = pageThumbnailStates.get(item.pageIndex);
|
|
24009
|
+
return {
|
|
24010
|
+
...item,
|
|
24011
|
+
status: state?.status ?? (hasElement ? "idle" : "unavailable"),
|
|
24012
|
+
error: state?.error
|
|
24013
|
+
};
|
|
24014
|
+
}),
|
|
24015
|
+
[thumbnailGeometryItems, pageThumbnailStates]
|
|
24016
|
+
);
|
|
22859
24017
|
const paintThumbnail = React.useCallback(
|
|
22860
24018
|
(pageIndex, canvas) => {
|
|
22861
24019
|
if (!canvas || options.disabled) {
|
|
@@ -24150,13 +25308,23 @@ function DocxEditorViewer({
|
|
|
24150
25308
|
if (cached) {
|
|
24151
25309
|
return cached;
|
|
24152
25310
|
}
|
|
25311
|
+
let registeredElement = null;
|
|
24153
25312
|
const nextRef = (element) => {
|
|
24154
25313
|
if (element) {
|
|
25314
|
+
registeredElement = element;
|
|
24155
25315
|
pageElementsRef.current.set(normalizedPageIndex, element);
|
|
24156
25316
|
} else {
|
|
24157
25317
|
pageElementsRef.current.delete(normalizedPageIndex);
|
|
24158
25318
|
}
|
|
24159
|
-
registerDocxViewerPageSurface(
|
|
25319
|
+
registerDocxViewerPageSurface(
|
|
25320
|
+
editor,
|
|
25321
|
+
normalizedPageIndex,
|
|
25322
|
+
element,
|
|
25323
|
+
registeredElement
|
|
25324
|
+
);
|
|
25325
|
+
if (!element) {
|
|
25326
|
+
registeredElement = null;
|
|
25327
|
+
}
|
|
24160
25328
|
};
|
|
24161
25329
|
pageSurfaceRefCallbacksRef.current.set(normalizedPageIndex, nextRef);
|
|
24162
25330
|
return nextRef;
|
|
@@ -25219,12 +26387,51 @@ function DocxEditorViewer({
|
|
|
25219
26387
|
pageSectionInfoByIndex,
|
|
25220
26388
|
trackedChangesEnabled
|
|
25221
26389
|
]);
|
|
26390
|
+
const pageThumbnailSurfaceSizesByPage = React.useMemo(
|
|
26391
|
+
() => pageNodeSegmentsByPage.map((_, pageIndex) => {
|
|
26392
|
+
const pageLayout = pageSectionInfoByIndex[pageIndex]?.layout ?? documentLayout;
|
|
26393
|
+
return {
|
|
26394
|
+
widthPx: pageLayout.pageWidthPx,
|
|
26395
|
+
heightPx: pageLayout.pageHeightPx
|
|
26396
|
+
};
|
|
26397
|
+
}),
|
|
26398
|
+
[documentLayout, pageNodeSegmentsByPage, pageSectionInfoByIndex]
|
|
26399
|
+
);
|
|
26400
|
+
const pageThumbnailSnapshotEntriesByPage = React.useMemo(
|
|
26401
|
+
() => buildDocxPageThumbnailRenderSnapshotEntries({
|
|
26402
|
+
model: editor.model,
|
|
26403
|
+
pageNodeSegmentsByPage,
|
|
26404
|
+
pageSectionInfoByIndex,
|
|
26405
|
+
contentKeysByPage: pageThumbnailContentKeysByPage,
|
|
26406
|
+
fallbackLayout: documentLayout,
|
|
26407
|
+
documentTheme: editor.documentTheme,
|
|
26408
|
+
docGridLinePitchPxByNodeIndex,
|
|
26409
|
+
numberingDefinitions: editor.model.metadata.numberingDefinitions
|
|
26410
|
+
}),
|
|
26411
|
+
[
|
|
26412
|
+
docGridLinePitchPxByNodeIndex,
|
|
26413
|
+
documentLayout,
|
|
26414
|
+
editor.documentTheme,
|
|
26415
|
+
editor.model,
|
|
26416
|
+
editor.model.metadata.numberingDefinitions,
|
|
26417
|
+
pageNodeSegmentsByPage,
|
|
26418
|
+
pageSectionInfoByIndex,
|
|
26419
|
+
pageThumbnailContentKeysByPage
|
|
26420
|
+
]
|
|
26421
|
+
);
|
|
25222
26422
|
React.useEffect(() => {
|
|
25223
26423
|
syncDocxViewerPageSurfaceContentKeys(
|
|
25224
26424
|
editor,
|
|
25225
|
-
pageThumbnailContentKeysByPage
|
|
26425
|
+
pageThumbnailContentKeysByPage,
|
|
26426
|
+
pageThumbnailSurfaceSizesByPage,
|
|
26427
|
+
pageThumbnailSnapshotEntriesByPage
|
|
25226
26428
|
);
|
|
25227
|
-
}, [
|
|
26429
|
+
}, [
|
|
26430
|
+
pageSurfaceRegistryOwner,
|
|
26431
|
+
pageThumbnailContentKeysByPage,
|
|
26432
|
+
pageThumbnailSnapshotEntriesByPage,
|
|
26433
|
+
pageThumbnailSurfaceSizesByPage
|
|
26434
|
+
]);
|
|
25228
26435
|
const resolveStyleRefFieldValueForPage = React.useMemo(() => {
|
|
25229
26436
|
const valueCache = /* @__PURE__ */ new Map();
|
|
25230
26437
|
const nodes = editor.model.nodes;
|