@files-preview-app/preview-file 1.2.6 → 1.2.7
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/angular.cjs +542 -162
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +541 -161
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +543 -163
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +542 -162
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +542 -162
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +541 -161
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +542 -162
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +541 -161
- package/dist/vue.js.map +1 -1
- package/package.json +179 -169
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import DOMPurify6 from 'dompurify';
|
|
2
2
|
import * as pdfjsLib from 'pdfjs-dist';
|
|
3
3
|
import * as docx from 'docx-preview';
|
|
4
4
|
import { unzipSync, strFromU8, unzip } from 'fflate';
|
|
@@ -356,7 +356,7 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
356
356
|
if (magicMime === "application/zip") {
|
|
357
357
|
const ooxmlMime = detectOoxmlType(buffer);
|
|
358
358
|
if (ooxmlMime && ooxmlMime !== "application/zip") {
|
|
359
|
-
metadata.mimeType = ooxmlMime;
|
|
359
|
+
metadata.mimeType = metadata.mimeType ?? ooxmlMime;
|
|
360
360
|
if (ooxmlMime.includes("wordprocessing")) metadata.extension = metadata.extension ?? ".docx";
|
|
361
361
|
else if (ooxmlMime.includes("spreadsheet")) metadata.extension = metadata.extension ?? ".xlsx";
|
|
362
362
|
else if (ooxmlMime.includes("presentation")) metadata.extension = metadata.extension ?? ".pptx";
|
|
@@ -385,12 +385,12 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
385
385
|
return { buffer, metadata };
|
|
386
386
|
}
|
|
387
387
|
function sanitizeHTML(html) {
|
|
388
|
-
return
|
|
388
|
+
return DOMPurify6.sanitize(html, {
|
|
389
389
|
USE_PROFILES: { html: true }
|
|
390
390
|
});
|
|
391
391
|
}
|
|
392
392
|
function sanitizeSVG(svg) {
|
|
393
|
-
return
|
|
393
|
+
return DOMPurify6.sanitize(svg, {
|
|
394
394
|
USE_PROFILES: { svg: true, svgFilters: true }
|
|
395
395
|
});
|
|
396
396
|
}
|
|
@@ -1491,7 +1491,19 @@ var PdfPlugin = class {
|
|
|
1491
1491
|
}
|
|
1492
1492
|
};
|
|
1493
1493
|
await renderPage(1);
|
|
1494
|
+
let resizeTimer = null;
|
|
1495
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
1496
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1497
|
+
resizeTimer = setTimeout(() => {
|
|
1498
|
+
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1499
|
+
renderPage(currentPage);
|
|
1500
|
+
}
|
|
1501
|
+
}, 150);
|
|
1502
|
+
});
|
|
1503
|
+
resizeObserver.observe(container);
|
|
1494
1504
|
const cleanup = () => {
|
|
1505
|
+
resizeObserver.disconnect();
|
|
1506
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1495
1507
|
if (currentRenderTask) {
|
|
1496
1508
|
try {
|
|
1497
1509
|
currentRenderTask.cancel();
|
|
@@ -2239,90 +2251,149 @@ var DocxPlugin = class {
|
|
|
2239
2251
|
console.warn("[DocxPlugin] Error parsing relationships:", relsErr);
|
|
2240
2252
|
}
|
|
2241
2253
|
}
|
|
2242
|
-
const
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2254
|
+
const sectPrs = Array.from(doc.getElementsByTagNameNS("*", "sectPr"));
|
|
2255
|
+
const lastSectPr = sectPrs[sectPrs.length - 1];
|
|
2256
|
+
let defaultW = 12240;
|
|
2257
|
+
let defaultH = 15840;
|
|
2258
|
+
let margins = { top: 1440, right: 1440, bottom: 1440, left: 1440 };
|
|
2259
|
+
if (lastSectPr) {
|
|
2260
|
+
const pgSz = lastSectPr.getElementsByTagNameNS("*", "pgSz")[0];
|
|
2261
|
+
if (pgSz) {
|
|
2262
|
+
defaultW = parseInt(pgSz.getAttribute("w:w") || pgSz.getAttribute("w") || "12240", 10);
|
|
2263
|
+
defaultH = parseInt(pgSz.getAttribute("w:h") || pgSz.getAttribute("h") || "15840", 10);
|
|
2264
|
+
}
|
|
2265
|
+
const pgMar = lastSectPr.getElementsByTagNameNS("*", "pgMar")[0];
|
|
2266
|
+
if (pgMar) {
|
|
2267
|
+
margins.top = parseInt(pgMar.getAttribute("w:top") || pgMar.getAttribute("top") || "1440", 10);
|
|
2268
|
+
margins.bottom = parseInt(pgMar.getAttribute("w:bottom") || pgMar.getAttribute("bottom") || "1440", 10);
|
|
2269
|
+
margins.left = parseInt(pgMar.getAttribute("w:left") || pgMar.getAttribute("left") || "1440", 10);
|
|
2270
|
+
margins.right = parseInt(pgMar.getAttribute("w:right") || pgMar.getAttribute("right") || "1440", 10);
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
const createPageCard = () => {
|
|
2274
|
+
const card = document.createElement("div");
|
|
2275
|
+
card.className = "fp-docx-page-card";
|
|
2276
|
+
card.style.backgroundColor = "#ffffff";
|
|
2277
|
+
card.style.borderRadius = "4px";
|
|
2278
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
2279
|
+
card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
2280
|
+
card.style.color = "#1e293b";
|
|
2281
|
+
card.style.lineHeight = "1.6";
|
|
2282
|
+
card.style.boxSizing = "border-box";
|
|
2283
|
+
card.style.overflow = "hidden";
|
|
2284
|
+
card.style.position = "relative";
|
|
2285
|
+
card.style.marginBottom = "24px";
|
|
2286
|
+
card.style.width = `${defaultW / 15}px`;
|
|
2287
|
+
card.style.height = `${defaultH / 15}px`;
|
|
2288
|
+
card.style.padding = `${margins.top / 15}px ${margins.right / 15}px ${margins.bottom / 15}px ${margins.left / 15}px`;
|
|
2289
|
+
return card;
|
|
2290
|
+
};
|
|
2291
|
+
let currentCard = createPageCard();
|
|
2292
|
+
let currentHtml = "";
|
|
2293
|
+
const pages = [{ card: currentCard, html: "" }];
|
|
2294
|
+
const flushHtml = () => {
|
|
2295
|
+
pages[pages.length - 1].html += currentHtml;
|
|
2296
|
+
currentHtml = "";
|
|
2297
|
+
};
|
|
2298
|
+
const newPage = () => {
|
|
2299
|
+
flushHtml();
|
|
2300
|
+
currentCard = createPageCard();
|
|
2301
|
+
pages.push({ card: currentCard, html: "" });
|
|
2302
|
+
};
|
|
2251
2303
|
const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
|
|
2252
|
-
let html = "";
|
|
2253
2304
|
for (const child of Array.from(body.children)) {
|
|
2254
2305
|
const tag = child.localName || child.nodeName.split(":").pop();
|
|
2255
2306
|
if (tag === "p") {
|
|
2256
2307
|
const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
|
|
2257
2308
|
const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
|
|
2258
2309
|
const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
|
|
2259
|
-
const
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2310
|
+
const chunks = this.extractParagraphChunks(child, imageMap);
|
|
2311
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
2312
|
+
if (i > 0) {
|
|
2313
|
+
newPage();
|
|
2314
|
+
}
|
|
2315
|
+
const textContent = chunks[i];
|
|
2316
|
+
if (!textContent.trim() && !textContent.includes("<img")) {
|
|
2317
|
+
currentHtml += '<div style="height: 10px;"></div>';
|
|
2318
|
+
continue;
|
|
2319
|
+
}
|
|
2320
|
+
const lowerStyle = styleVal.toLowerCase();
|
|
2321
|
+
if (lowerStyle.includes("title")) {
|
|
2322
|
+
currentHtml += `<h1 style="font-size: 28px; font-weight: 700; color: #1e3a8a; margin: 24px 0 12px; border-bottom: 2px solid #e2e8f0; padding-bottom: 8px;">${textContent}</h1>`;
|
|
2323
|
+
} else if (lowerStyle.includes("heading1") || styleVal === "1") {
|
|
2324
|
+
currentHtml += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
|
|
2325
|
+
} else if (lowerStyle.includes("heading2") || styleVal === "2") {
|
|
2326
|
+
currentHtml += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
|
|
2327
|
+
} else if (lowerStyle.includes("heading3") || styleVal === "3") {
|
|
2328
|
+
currentHtml += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
|
|
2329
|
+
} else if (numPr) {
|
|
2330
|
+
currentHtml += `<div style="display: flex; gap: 8px; margin: 4px 0 4px 20px;"><span style="color: #2563eb; font-weight: bold;">\u2022</span><span>${textContent}</span></div>`;
|
|
2331
|
+
} else {
|
|
2332
|
+
currentHtml += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
|
|
2333
|
+
}
|
|
2277
2334
|
}
|
|
2278
2335
|
} else if (tag === "tbl") {
|
|
2279
|
-
|
|
2336
|
+
currentHtml += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
|
|
2280
2337
|
const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
|
|
2281
2338
|
rows.forEach((tr, rIdx) => {
|
|
2282
|
-
|
|
2339
|
+
currentHtml += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
|
|
2283
2340
|
const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
|
|
2284
2341
|
cells.forEach((tc) => {
|
|
2285
2342
|
const cellText = this.extractParagraphHtml(tc, imageMap);
|
|
2286
|
-
|
|
2343
|
+
currentHtml += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || " "}</td>`;
|
|
2287
2344
|
});
|
|
2288
|
-
|
|
2345
|
+
currentHtml += "</tr>";
|
|
2289
2346
|
});
|
|
2290
|
-
|
|
2347
|
+
currentHtml += "</table>";
|
|
2291
2348
|
}
|
|
2292
2349
|
}
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2350
|
+
flushHtml();
|
|
2351
|
+
for (const page of pages) {
|
|
2352
|
+
page.card.innerHTML = DOMPurify6.sanitize(page.html, {
|
|
2353
|
+
ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
|
|
2354
|
+
ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
|
|
2355
|
+
});
|
|
2356
|
+
wrapper.appendChild(page.card);
|
|
2357
|
+
}
|
|
2298
2358
|
}
|
|
2299
2359
|
extractParagraphHtml(pElement, imageMap = {}) {
|
|
2300
|
-
|
|
2360
|
+
return this.extractParagraphChunks(pElement, imageMap).join("<br/>");
|
|
2361
|
+
}
|
|
2362
|
+
extractParagraphChunks(pElement, imageMap = {}) {
|
|
2363
|
+
const chunks = [""];
|
|
2364
|
+
let currentChunkIndex = 0;
|
|
2301
2365
|
const drawings = Array.from(pElement.getElementsByTagNameNS("*", "drawing"));
|
|
2302
2366
|
for (const drawing of drawings) {
|
|
2303
2367
|
const blip = drawing.getElementsByTagNameNS("*", "blip")[0];
|
|
2304
2368
|
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2305
2369
|
if (rId && imageMap[rId]) {
|
|
2306
|
-
|
|
2370
|
+
chunks[currentChunkIndex] += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
|
|
2307
2371
|
}
|
|
2308
2372
|
}
|
|
2309
2373
|
const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
|
|
2310
|
-
if (runs.length === 0 && !
|
|
2311
|
-
|
|
2374
|
+
if (runs.length === 0 && !chunks[currentChunkIndex]) {
|
|
2375
|
+
chunks[currentChunkIndex] = DOMPurify6.sanitize(pElement.textContent || "");
|
|
2376
|
+
return chunks;
|
|
2312
2377
|
}
|
|
2313
2378
|
for (const r of runs) {
|
|
2314
2379
|
const blip = r.getElementsByTagNameNS("*", "blip")[0] || r.getElementsByTagNameNS("*", "imagedata")[0];
|
|
2315
2380
|
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2316
2381
|
if (rId && imageMap[rId]) {
|
|
2317
|
-
|
|
2382
|
+
chunks[currentChunkIndex] += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
|
|
2318
2383
|
}
|
|
2319
|
-
const brs = r.getElementsByTagNameNS("*", "br");
|
|
2320
|
-
for (
|
|
2321
|
-
|
|
2384
|
+
const brs = Array.from(r.getElementsByTagNameNS("*", "br"));
|
|
2385
|
+
for (const br of brs) {
|
|
2386
|
+
const type = br.getAttribute("w:type") || br.getAttribute("type");
|
|
2387
|
+
if (type === "page") {
|
|
2388
|
+
chunks.push("");
|
|
2389
|
+
currentChunkIndex++;
|
|
2390
|
+
} else {
|
|
2391
|
+
chunks[currentChunkIndex] += "<br/>";
|
|
2392
|
+
}
|
|
2322
2393
|
}
|
|
2323
2394
|
const tabs = r.getElementsByTagNameNS("*", "tab");
|
|
2324
2395
|
if (tabs.length > 0) {
|
|
2325
|
-
|
|
2396
|
+
chunks[currentChunkIndex] += " ";
|
|
2326
2397
|
}
|
|
2327
2398
|
const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
|
|
2328
2399
|
const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
|
|
@@ -2336,7 +2407,7 @@ var DocxPlugin = class {
|
|
|
2336
2407
|
const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
|
|
2337
2408
|
let text = texts.map((t) => t.textContent || "").join("");
|
|
2338
2409
|
if (!text) continue;
|
|
2339
|
-
text =
|
|
2410
|
+
text = DOMPurify6.sanitize(text);
|
|
2340
2411
|
let styles = "";
|
|
2341
2412
|
if (isBold) styles += "font-weight: bold; ";
|
|
2342
2413
|
if (isItalic) styles += "font-style: italic; ";
|
|
@@ -2348,12 +2419,12 @@ var DocxPlugin = class {
|
|
|
2348
2419
|
if (!isNaN(pt) && pt > 0) styles += `font-size: ${pt}pt; `;
|
|
2349
2420
|
}
|
|
2350
2421
|
if (styles) {
|
|
2351
|
-
|
|
2422
|
+
chunks[currentChunkIndex] += `<span style="${styles}">${text}</span>`;
|
|
2352
2423
|
} else {
|
|
2353
|
-
|
|
2424
|
+
chunks[currentChunkIndex] += text;
|
|
2354
2425
|
}
|
|
2355
2426
|
}
|
|
2356
|
-
return
|
|
2427
|
+
return chunks;
|
|
2357
2428
|
}
|
|
2358
2429
|
renderBinaryDocFallback(ctx, wrapper) {
|
|
2359
2430
|
const card = document.createElement("div");
|
|
@@ -2370,14 +2441,14 @@ var DocxPlugin = class {
|
|
|
2370
2441
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
2371
2442
|
if (wordDocStream && wordDocStream.length >= 512) {
|
|
2372
2443
|
const text2 = this.extractReadableStrings(wordDocStream);
|
|
2373
|
-
card.innerHTML = `<div style="white-space: pre-wrap;">${
|
|
2444
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6.sanitize(text2)}</div>`;
|
|
2374
2445
|
wrapper.appendChild(card);
|
|
2375
2446
|
return;
|
|
2376
2447
|
}
|
|
2377
2448
|
} catch {
|
|
2378
2449
|
}
|
|
2379
2450
|
const text = this.extractReadableStrings(new Uint8Array(ctx.buffer));
|
|
2380
|
-
card.innerHTML = `<div style="white-space: pre-wrap;">${
|
|
2451
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify6.sanitize(text)}</div>`;
|
|
2381
2452
|
wrapper.appendChild(card);
|
|
2382
2453
|
}
|
|
2383
2454
|
extractReadableStrings(bytes) {
|
|
@@ -2976,41 +3047,94 @@ var CodePlugin = class {
|
|
|
2976
3047
|
async render(ctx) {
|
|
2977
3048
|
const decoder = new TextDecoder("utf-8");
|
|
2978
3049
|
const fullText = decoder.decode(ctx.buffer);
|
|
2979
|
-
const
|
|
2980
|
-
const
|
|
3050
|
+
const extRaw = ctx.metadata.extension?.toLowerCase();
|
|
3051
|
+
const mimeRaw = ctx.metadata.mimeType?.toLowerCase();
|
|
3052
|
+
const isTxt = extRaw === ".txt" || mimeRaw === "text/plain" && (!extRaw || !this.extensions.filter((e) => e !== ".txt").includes(extRaw));
|
|
3053
|
+
let rawPages = [];
|
|
3054
|
+
if (isTxt) {
|
|
3055
|
+
const explicitPages = fullText.split(/(?:\f|\x0C)/);
|
|
3056
|
+
for (const ep of explicitPages) {
|
|
3057
|
+
const lines = ep.split(/\r?\n/);
|
|
3058
|
+
let currentChunk = [];
|
|
3059
|
+
for (let i = 0; i < lines.length; i++) {
|
|
3060
|
+
currentChunk.push(lines[i]);
|
|
3061
|
+
if (currentChunk.length >= 46) {
|
|
3062
|
+
rawPages.push(currentChunk.join("\n"));
|
|
3063
|
+
currentChunk = [];
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
if (currentChunk.length > 0 || lines.length === 0) {
|
|
3067
|
+
rawPages.push(currentChunk.join("\n"));
|
|
3068
|
+
}
|
|
3069
|
+
}
|
|
3070
|
+
if (rawPages.length === 0) rawPages = [""];
|
|
3071
|
+
} else {
|
|
3072
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
3073
|
+
rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
3074
|
+
}
|
|
2981
3075
|
const totalPages = Math.max(1, rawPages.length);
|
|
2982
3076
|
let currentPage = 1;
|
|
2983
3077
|
const container = document.createElement("div");
|
|
2984
3078
|
container.style.width = "100%";
|
|
2985
3079
|
container.style.height = "100%";
|
|
2986
3080
|
container.style.overflow = "auto";
|
|
2987
|
-
container.style.backgroundColor = "#1e1e1e";
|
|
2988
|
-
container.style.color = "#d4d4d4";
|
|
2989
|
-
container.style.padding = "16px";
|
|
2990
|
-
container.style.boxSizing = "border-box";
|
|
2991
3081
|
let fontSize = 13;
|
|
2992
3082
|
let rotation = 0;
|
|
3083
|
+
let zoomLevel = 1;
|
|
2993
3084
|
const pre = document.createElement("pre");
|
|
2994
|
-
pre.style.margin = "0";
|
|
2995
|
-
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
2996
|
-
pre.style.fontSize = `${fontSize}px`;
|
|
2997
|
-
pre.style.lineHeight = "1.5";
|
|
2998
|
-
pre.style.whiteSpace = "pre-wrap";
|
|
2999
|
-
pre.style.wordBreak = "break-all";
|
|
3000
3085
|
const code = document.createElement("code");
|
|
3086
|
+
if (isTxt) {
|
|
3087
|
+
container.style.backgroundColor = "#f1f5f9";
|
|
3088
|
+
container.style.padding = "32px";
|
|
3089
|
+
container.style.boxSizing = "border-box";
|
|
3090
|
+
container.style.display = "flex";
|
|
3091
|
+
container.style.flexDirection = "column";
|
|
3092
|
+
container.style.alignItems = "center";
|
|
3093
|
+
pre.style.margin = "0";
|
|
3094
|
+
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3095
|
+
pre.style.fontSize = "13px";
|
|
3096
|
+
pre.style.color = "#1e293b";
|
|
3097
|
+
pre.style.lineHeight = "1.5";
|
|
3098
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3099
|
+
pre.style.wordBreak = "break-word";
|
|
3100
|
+
pre.style.backgroundColor = "#ffffff";
|
|
3101
|
+
pre.style.width = "816px";
|
|
3102
|
+
pre.style.minHeight = "1056px";
|
|
3103
|
+
pre.style.padding = "72px 56px";
|
|
3104
|
+
pre.style.boxSizing = "border-box";
|
|
3105
|
+
pre.style.boxShadow = "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)";
|
|
3106
|
+
pre.style.borderRadius = "4px";
|
|
3107
|
+
pre.style.transformOrigin = "top center";
|
|
3108
|
+
} else {
|
|
3109
|
+
container.style.backgroundColor = "#1e1e1e";
|
|
3110
|
+
container.style.color = "#d4d4d4";
|
|
3111
|
+
container.style.padding = "16px";
|
|
3112
|
+
container.style.boxSizing = "border-box";
|
|
3113
|
+
pre.style.margin = "0";
|
|
3114
|
+
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
3115
|
+
pre.style.fontSize = `${fontSize}px`;
|
|
3116
|
+
pre.style.lineHeight = "1.5";
|
|
3117
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3118
|
+
pre.style.wordBreak = "break-all";
|
|
3119
|
+
pre.style.transformOrigin = "top left";
|
|
3120
|
+
}
|
|
3001
3121
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
3002
3122
|
const renderCodePage = (text) => {
|
|
3003
|
-
|
|
3004
|
-
if (ext && hljs.getLanguage(ext)) {
|
|
3005
|
-
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
3006
|
-
} else {
|
|
3007
|
-
code.innerHTML = hljs.highlightAuto(text).value;
|
|
3008
|
-
}
|
|
3009
|
-
} catch {
|
|
3123
|
+
if (isTxt) {
|
|
3010
3124
|
code.textContent = text;
|
|
3125
|
+
} else {
|
|
3126
|
+
try {
|
|
3127
|
+
if (ext && hljs.getLanguage(ext)) {
|
|
3128
|
+
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
3129
|
+
} else {
|
|
3130
|
+
code.innerHTML = hljs.highlightAuto(text).value;
|
|
3131
|
+
}
|
|
3132
|
+
} catch {
|
|
3133
|
+
code.textContent = text;
|
|
3134
|
+
}
|
|
3011
3135
|
}
|
|
3012
3136
|
};
|
|
3013
|
-
renderCodePage(rawPages[0] || fullText);
|
|
3137
|
+
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
3014
3138
|
pre.appendChild(code);
|
|
3015
3139
|
container.appendChild(pre);
|
|
3016
3140
|
let indicator = null;
|
|
@@ -3019,15 +3143,22 @@ var CodePlugin = class {
|
|
|
3019
3143
|
indicator.className = "fp-code-page-indicator";
|
|
3020
3144
|
indicator.style.position = "sticky";
|
|
3021
3145
|
indicator.style.bottom = "16px";
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3146
|
+
if (isTxt) {
|
|
3147
|
+
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3148
|
+
indicator.style.color = "#334155";
|
|
3149
|
+
indicator.style.border = "1px solid #e2e8f0";
|
|
3150
|
+
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3151
|
+
} else {
|
|
3152
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3153
|
+
indicator.style.color = "#f8fafc";
|
|
3154
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3155
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3156
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3157
|
+
}
|
|
3025
3158
|
indicator.style.fontSize = "12px";
|
|
3026
3159
|
indicator.style.fontWeight = "600";
|
|
3027
3160
|
indicator.style.padding = "5px 14px";
|
|
3028
3161
|
indicator.style.borderRadius = "20px";
|
|
3029
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3030
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3031
3162
|
indicator.style.zIndex = "10";
|
|
3032
3163
|
indicator.style.userSelect = "none";
|
|
3033
3164
|
indicator.style.pointerEvents = "none";
|
|
@@ -3038,7 +3169,7 @@ var CodePlugin = class {
|
|
|
3038
3169
|
}
|
|
3039
3170
|
const showPage = (pageNum) => {
|
|
3040
3171
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3041
|
-
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
3172
|
+
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
3042
3173
|
if (indicator) {
|
|
3043
3174
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3044
3175
|
}
|
|
@@ -3054,39 +3185,57 @@ var CodePlugin = class {
|
|
|
3054
3185
|
ctx.container.innerHTML = "";
|
|
3055
3186
|
};
|
|
3056
3187
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3188
|
+
const updateTransform = () => {
|
|
3189
|
+
if (isTxt) {
|
|
3190
|
+
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
3191
|
+
} else {
|
|
3192
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3193
|
+
pre.style.fontSize = `${fontSize}px`;
|
|
3194
|
+
}
|
|
3195
|
+
};
|
|
3057
3196
|
return {
|
|
3058
3197
|
destroy: cleanup,
|
|
3059
3198
|
getPageCount: () => totalPages,
|
|
3060
3199
|
getCurrentPage: () => currentPage,
|
|
3061
3200
|
goToPage: (page) => showPage(page),
|
|
3062
3201
|
zoomIn: () => {
|
|
3063
|
-
|
|
3064
|
-
|
|
3202
|
+
if (isTxt) {
|
|
3203
|
+
zoomLevel = Math.min(3, zoomLevel + 0.1);
|
|
3204
|
+
} else {
|
|
3205
|
+
fontSize = Math.min(32, fontSize + 2);
|
|
3206
|
+
}
|
|
3207
|
+
updateTransform();
|
|
3065
3208
|
},
|
|
3066
3209
|
zoomOut: () => {
|
|
3067
|
-
|
|
3068
|
-
|
|
3210
|
+
if (isTxt) {
|
|
3211
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.1);
|
|
3212
|
+
} else {
|
|
3213
|
+
fontSize = Math.max(8, fontSize - 2);
|
|
3214
|
+
}
|
|
3215
|
+
updateTransform();
|
|
3069
3216
|
},
|
|
3070
|
-
getZoom: () => fontSize / 13,
|
|
3217
|
+
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
3071
3218
|
setZoom: (level) => {
|
|
3072
|
-
|
|
3073
|
-
|
|
3219
|
+
if (isTxt) {
|
|
3220
|
+
zoomLevel = level;
|
|
3221
|
+
} else {
|
|
3222
|
+
fontSize = Math.round(13 * level);
|
|
3223
|
+
}
|
|
3224
|
+
updateTransform();
|
|
3074
3225
|
},
|
|
3075
3226
|
fitToPage: () => {
|
|
3076
3227
|
fontSize = 13;
|
|
3077
3228
|
rotation = 0;
|
|
3078
|
-
|
|
3079
|
-
|
|
3229
|
+
zoomLevel = 1;
|
|
3230
|
+
updateTransform();
|
|
3080
3231
|
},
|
|
3081
3232
|
rotateCW: () => {
|
|
3082
3233
|
rotation = (rotation + 90) % 360;
|
|
3083
|
-
|
|
3084
|
-
pre.style.transformOrigin = "top left";
|
|
3234
|
+
updateTransform();
|
|
3085
3235
|
},
|
|
3086
3236
|
rotateCCW: () => {
|
|
3087
3237
|
rotation = (rotation - 90 + 360) % 360;
|
|
3088
|
-
|
|
3089
|
-
pre.style.transformOrigin = "top left";
|
|
3238
|
+
updateTransform();
|
|
3090
3239
|
},
|
|
3091
3240
|
download: () => {
|
|
3092
3241
|
const mimeType = ctx.metadata.mimeType || "text/plain";
|
|
@@ -3385,7 +3534,7 @@ var MarkdownPlugin = class {
|
|
|
3385
3534
|
gfm: true,
|
|
3386
3535
|
breaks: true
|
|
3387
3536
|
});
|
|
3388
|
-
const cleanHtml =
|
|
3537
|
+
const cleanHtml = DOMPurify6.sanitize(rawHtml, {
|
|
3389
3538
|
USE_PROFILES: { html: true }
|
|
3390
3539
|
});
|
|
3391
3540
|
const wrapper = document.createElement("div");
|
|
@@ -4021,6 +4170,14 @@ var RtfPlugin = class {
|
|
|
4021
4170
|
group: "actions",
|
|
4022
4171
|
execute: () => instance.download?.()
|
|
4023
4172
|
},
|
|
4173
|
+
{
|
|
4174
|
+
id: "copy",
|
|
4175
|
+
icon: "copy",
|
|
4176
|
+
label: "Copy Text",
|
|
4177
|
+
type: "button",
|
|
4178
|
+
group: "actions",
|
|
4179
|
+
execute: () => instance.copy?.()
|
|
4180
|
+
},
|
|
4024
4181
|
{
|
|
4025
4182
|
id: "print",
|
|
4026
4183
|
icon: "print",
|
|
@@ -4082,14 +4239,31 @@ var RtfPlugin = class {
|
|
|
4082
4239
|
} catch (err) {
|
|
4083
4240
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
4084
4241
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
4085
|
-
const
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4242
|
+
const rawPages = text.split(/\\page\b/).map((segment) => {
|
|
4243
|
+
return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
|
|
4244
|
+
}).filter((p) => p.length > 0);
|
|
4245
|
+
const pages = rawPages.length > 0 ? rawPages : [text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim()];
|
|
4246
|
+
for (let i = 0; i < pages.length; i++) {
|
|
4247
|
+
const pageCard = document.createElement("div");
|
|
4248
|
+
pageCard.className = "fp-rtf-page-card";
|
|
4249
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4250
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4251
|
+
pageCard.style.borderRadius = "4px";
|
|
4252
|
+
pageCard.style.padding = "72px 56px";
|
|
4253
|
+
pageCard.style.width = "816px";
|
|
4254
|
+
pageCard.style.minHeight = "1056px";
|
|
4255
|
+
pageCard.style.maxWidth = "100%";
|
|
4256
|
+
pageCard.style.boxSizing = "border-box";
|
|
4257
|
+
pageCard.style.fontFamily = "serif";
|
|
4258
|
+
pageCard.style.fontSize = "12pt";
|
|
4259
|
+
pageCard.style.lineHeight = "1.6";
|
|
4260
|
+
pageCard.style.color = "#1e293b";
|
|
4261
|
+
pageCard.style.whiteSpace = "pre-wrap";
|
|
4262
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4263
|
+
pageCard.textContent = pages[i];
|
|
4264
|
+
wrapper.appendChild(pageCard);
|
|
4265
|
+
pageElements.push(pageCard);
|
|
4266
|
+
}
|
|
4093
4267
|
}
|
|
4094
4268
|
const totalPages = Math.max(1, pageElements.length);
|
|
4095
4269
|
let currentPage = 1;
|
|
@@ -4177,6 +4351,10 @@ var RtfPlugin = class {
|
|
|
4177
4351
|
a.click();
|
|
4178
4352
|
URL.revokeObjectURL(url);
|
|
4179
4353
|
},
|
|
4354
|
+
copy: () => {
|
|
4355
|
+
const text = wrapper.textContent || "";
|
|
4356
|
+
navigator.clipboard?.writeText(text);
|
|
4357
|
+
},
|
|
4180
4358
|
print: () => {
|
|
4181
4359
|
window.print();
|
|
4182
4360
|
}
|
|
@@ -4251,7 +4429,7 @@ var HtmlPreviewPlugin = class {
|
|
|
4251
4429
|
}
|
|
4252
4430
|
async render(ctx) {
|
|
4253
4431
|
const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
|
|
4254
|
-
const sanitized =
|
|
4432
|
+
const sanitized = DOMPurify6.sanitize(rawHtml, {
|
|
4255
4433
|
WHOLE_DOCUMENT: true,
|
|
4256
4434
|
ADD_TAGS: ["style", "link"],
|
|
4257
4435
|
ADD_ATTR: ["target", "rel"]
|
|
@@ -4517,14 +4695,97 @@ var OpenDocumentPlugin = class {
|
|
|
4517
4695
|
wrapper.textContent = contentDoc.documentElement.textContent || "Formula content";
|
|
4518
4696
|
}
|
|
4519
4697
|
} else {
|
|
4520
|
-
wrapper.style.maxWidth = "
|
|
4521
|
-
wrapper.style.padding = "
|
|
4698
|
+
wrapper.style.maxWidth = "none";
|
|
4699
|
+
wrapper.style.padding = "0";
|
|
4522
4700
|
wrapper.style.minHeight = "100%";
|
|
4701
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4702
|
+
wrapper.style.boxShadow = "none";
|
|
4703
|
+
wrapper.style.position = "relative";
|
|
4704
|
+
const dims = this.getPageDimensions(stylesDoc, contentDoc);
|
|
4523
4705
|
const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
|
|
4524
|
-
|
|
4525
|
-
|
|
4706
|
+
const tempDiv = document.createElement("div");
|
|
4707
|
+
tempDiv.style.width = `${dims.width - dims.marginLeft - dims.marginRight}px`;
|
|
4708
|
+
tempDiv.style.position = "absolute";
|
|
4709
|
+
tempDiv.style.visibility = "hidden";
|
|
4710
|
+
tempDiv.innerHTML = DOMPurify6.sanitize(bodyHtml, {
|
|
4711
|
+
ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub", "hr"],
|
|
4526
4712
|
ADD_ATTR: ["style", "colspan", "rowspan"]
|
|
4527
4713
|
});
|
|
4714
|
+
document.body.appendChild(tempDiv);
|
|
4715
|
+
const contentHeight = dims.height - dims.marginTop - dims.marginBottom;
|
|
4716
|
+
const pageElements = [[]];
|
|
4717
|
+
let currentHeight = 0;
|
|
4718
|
+
let currentPageIdx = 0;
|
|
4719
|
+
Array.from(tempDiv.children).forEach((child) => {
|
|
4720
|
+
const el = child;
|
|
4721
|
+
const style = el.getAttribute("style") || "";
|
|
4722
|
+
const isBreakBefore = style.includes("page-break-before: always");
|
|
4723
|
+
const isBreakAfter = style.includes("page-break-after: always");
|
|
4724
|
+
const isSoftBreak = el.classList.contains("odf-page-break");
|
|
4725
|
+
if (isBreakBefore) {
|
|
4726
|
+
if (pageElements[currentPageIdx].length > 0) {
|
|
4727
|
+
currentPageIdx++;
|
|
4728
|
+
pageElements.push([]);
|
|
4729
|
+
currentHeight = 0;
|
|
4730
|
+
}
|
|
4731
|
+
}
|
|
4732
|
+
const h = el.offsetHeight || 0;
|
|
4733
|
+
if (currentHeight + h > contentHeight && pageElements[currentPageIdx].length > 0 && !isSoftBreak) {
|
|
4734
|
+
currentPageIdx++;
|
|
4735
|
+
pageElements.push([]);
|
|
4736
|
+
currentHeight = 0;
|
|
4737
|
+
}
|
|
4738
|
+
if (!isSoftBreak) {
|
|
4739
|
+
pageElements[currentPageIdx].push(el.cloneNode(true));
|
|
4740
|
+
currentHeight += h;
|
|
4741
|
+
}
|
|
4742
|
+
if (isBreakAfter || isSoftBreak) {
|
|
4743
|
+
currentPageIdx++;
|
|
4744
|
+
pageElements.push([]);
|
|
4745
|
+
currentHeight = 0;
|
|
4746
|
+
}
|
|
4747
|
+
});
|
|
4748
|
+
document.body.removeChild(tempDiv);
|
|
4749
|
+
if (pageElements.length > 1 && pageElements[pageElements.length - 1].length === 0) {
|
|
4750
|
+
pageElements.pop();
|
|
4751
|
+
}
|
|
4752
|
+
totalPages = Math.max(1, pageElements.length);
|
|
4753
|
+
pageElements.forEach((elements, idx) => {
|
|
4754
|
+
const page = document.createElement("div");
|
|
4755
|
+
page.className = `fp-odt-page fp-odt-page-${idx + 1}`;
|
|
4756
|
+
page.style.width = `${dims.width}px`;
|
|
4757
|
+
page.style.minHeight = `${dims.height}px`;
|
|
4758
|
+
page.style.padding = `${dims.marginTop}px ${dims.marginRight}px ${dims.marginBottom}px ${dims.marginLeft}px`;
|
|
4759
|
+
page.style.margin = "0 auto";
|
|
4760
|
+
page.style.backgroundColor = "#ffffff";
|
|
4761
|
+
page.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
4762
|
+
page.style.borderRadius = "4px";
|
|
4763
|
+
page.style.boxSizing = "border-box";
|
|
4764
|
+
page.style.display = idx === 0 ? "block" : "none";
|
|
4765
|
+
page.style.position = "absolute";
|
|
4766
|
+
page.style.top = "0";
|
|
4767
|
+
page.style.left = "50%";
|
|
4768
|
+
page.style.transform = "translateX(-50%)";
|
|
4769
|
+
elements.forEach((el) => page.appendChild(el));
|
|
4770
|
+
wrapper.appendChild(page);
|
|
4771
|
+
slides.push(page);
|
|
4772
|
+
});
|
|
4773
|
+
const pageIndicator = document.createElement("div");
|
|
4774
|
+
pageIndicator.className = "fp-odt-page-indicator";
|
|
4775
|
+
pageIndicator.style.position = "sticky";
|
|
4776
|
+
pageIndicator.style.bottom = "16px";
|
|
4777
|
+
pageIndicator.style.left = "50%";
|
|
4778
|
+
pageIndicator.style.transform = "translateX(-50%)";
|
|
4779
|
+
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
4780
|
+
pageIndicator.style.color = "#fff";
|
|
4781
|
+
pageIndicator.style.padding = "6px 12px";
|
|
4782
|
+
pageIndicator.style.borderRadius = "16px";
|
|
4783
|
+
pageIndicator.style.fontSize = "12px";
|
|
4784
|
+
pageIndicator.style.zIndex = "100";
|
|
4785
|
+
pageIndicator.style.display = "inline-block";
|
|
4786
|
+
pageIndicator.style.width = "fit-content";
|
|
4787
|
+
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
4788
|
+
container.appendChild(pageIndicator);
|
|
4528
4789
|
}
|
|
4529
4790
|
const cleanup = () => {
|
|
4530
4791
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
@@ -4533,11 +4794,15 @@ var OpenDocumentPlugin = class {
|
|
|
4533
4794
|
};
|
|
4534
4795
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4535
4796
|
const goToPage = (page) => {
|
|
4536
|
-
if (
|
|
4797
|
+
if (page < 1 || page > totalPages) return;
|
|
4537
4798
|
currentPage = page;
|
|
4538
4799
|
slides.forEach((s, idx) => {
|
|
4539
4800
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
4540
4801
|
});
|
|
4802
|
+
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
4803
|
+
if (indicator) {
|
|
4804
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4805
|
+
}
|
|
4541
4806
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4542
4807
|
};
|
|
4543
4808
|
return {
|
|
@@ -4606,6 +4871,43 @@ var OpenDocumentPlugin = class {
|
|
|
4606
4871
|
}
|
|
4607
4872
|
};
|
|
4608
4873
|
}
|
|
4874
|
+
getPageDimensions(stylesDoc, contentDoc) {
|
|
4875
|
+
let width = 850;
|
|
4876
|
+
let height = 1123;
|
|
4877
|
+
let marginTop = 48;
|
|
4878
|
+
let marginBottom = 48;
|
|
4879
|
+
let marginLeft = 48;
|
|
4880
|
+
let marginRight = 48;
|
|
4881
|
+
const parseUnit = (val) => {
|
|
4882
|
+
if (!val) return null;
|
|
4883
|
+
if (val.endsWith("cm")) return parseFloat(val) * 37.8;
|
|
4884
|
+
if (val.endsWith("mm")) return parseFloat(val) * 3.78;
|
|
4885
|
+
if (val.endsWith("in")) return parseFloat(val) * 96;
|
|
4886
|
+
if (val.endsWith("pt")) return parseFloat(val) * 1.33;
|
|
4887
|
+
if (val.endsWith("px")) return parseFloat(val);
|
|
4888
|
+
return parseFloat(val);
|
|
4889
|
+
};
|
|
4890
|
+
const docs = [stylesDoc, contentDoc].filter(Boolean);
|
|
4891
|
+
for (const doc of docs) {
|
|
4892
|
+
const pageLayout = doc.querySelector("page-layout-properties, [page-width]");
|
|
4893
|
+
if (pageLayout) {
|
|
4894
|
+
const w = parseUnit(pageLayout.getAttribute("fo:page-width") || pageLayout.getAttribute("page-width"));
|
|
4895
|
+
const h = parseUnit(pageLayout.getAttribute("fo:page-height") || pageLayout.getAttribute("page-height"));
|
|
4896
|
+
const mt = parseUnit(pageLayout.getAttribute("fo:margin-top") || pageLayout.getAttribute("margin-top"));
|
|
4897
|
+
const mb = parseUnit(pageLayout.getAttribute("fo:margin-bottom") || pageLayout.getAttribute("margin-bottom"));
|
|
4898
|
+
const ml = parseUnit(pageLayout.getAttribute("fo:margin-left") || pageLayout.getAttribute("margin-left"));
|
|
4899
|
+
const mr = parseUnit(pageLayout.getAttribute("fo:margin-right") || pageLayout.getAttribute("margin-right"));
|
|
4900
|
+
if (w !== null) width = w;
|
|
4901
|
+
if (h !== null) height = h;
|
|
4902
|
+
if (mt !== null) marginTop = mt;
|
|
4903
|
+
if (mb !== null) marginBottom = mb;
|
|
4904
|
+
if (ml !== null) marginLeft = ml;
|
|
4905
|
+
if (mr !== null) marginRight = mr;
|
|
4906
|
+
break;
|
|
4907
|
+
}
|
|
4908
|
+
}
|
|
4909
|
+
return { width, height, marginTop, marginBottom, marginLeft, marginRight };
|
|
4910
|
+
}
|
|
4609
4911
|
extractStyles(stylesDoc, contentDoc) {
|
|
4610
4912
|
const map = /* @__PURE__ */ new Map();
|
|
4611
4913
|
const styleNodes = [];
|
|
@@ -4628,14 +4930,21 @@ var OpenDocumentPlugin = class {
|
|
|
4628
4930
|
if (color) css += `color: ${color}; `;
|
|
4629
4931
|
if (size) css += `font-size: ${size}; `;
|
|
4630
4932
|
}
|
|
4631
|
-
|
|
4933
|
+
let paraProp = node.querySelector("paragraph-properties, [text-align]");
|
|
4934
|
+
if (!paraProp) {
|
|
4935
|
+
paraProp = Array.from(node.children).find((c) => c.tagName.includes("paragraph-properties")) || null;
|
|
4936
|
+
}
|
|
4632
4937
|
if (paraProp) {
|
|
4633
4938
|
const align = paraProp.getAttribute("fo:text-align") || paraProp.getAttribute("text-align");
|
|
4634
4939
|
const mt = paraProp.getAttribute("fo:margin-top") || paraProp.getAttribute("margin-top");
|
|
4635
4940
|
const mb = paraProp.getAttribute("fo:margin-bottom") || paraProp.getAttribute("margin-bottom");
|
|
4941
|
+
const breakBefore = paraProp.getAttribute("fo:break-before") || paraProp.getAttribute("break-before");
|
|
4942
|
+
const breakAfter = paraProp.getAttribute("fo:break-after") || paraProp.getAttribute("break-after");
|
|
4636
4943
|
if (align) css += `text-align: ${align}; `;
|
|
4637
4944
|
if (mt) css += `margin-top: ${mt}; `;
|
|
4638
4945
|
if (mb) css += `margin-bottom: ${mb}; `;
|
|
4946
|
+
if (breakBefore === "page") css += "page-break-before: always; ";
|
|
4947
|
+
if (breakAfter === "page") css += "page-break-after: always; ";
|
|
4639
4948
|
}
|
|
4640
4949
|
if (css) map.set(name, css);
|
|
4641
4950
|
}
|
|
@@ -4720,6 +5029,8 @@ var OpenDocumentPlugin = class {
|
|
|
4720
5029
|
result += " ";
|
|
4721
5030
|
} else if (tag === "line-break") {
|
|
4722
5031
|
result += "<br/>";
|
|
5032
|
+
} else if (tag === "soft-page-break") {
|
|
5033
|
+
result += '<hr class="odf-page-break" style="page-break-after: always; border: none; margin: 0; padding: 0; height: 0;" />';
|
|
4723
5034
|
} else {
|
|
4724
5035
|
result += el.textContent || "";
|
|
4725
5036
|
}
|
|
@@ -4880,20 +5191,9 @@ var DocPlugin = class {
|
|
|
4880
5191
|
container.style.overflow = "auto";
|
|
4881
5192
|
container.style.padding = "32px 16px";
|
|
4882
5193
|
container.style.backgroundColor = "#f1f5f9";
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
wrapper.style.margin = "0 auto";
|
|
4887
|
-
wrapper.style.backgroundColor = "#ffffff";
|
|
4888
|
-
wrapper.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4889
|
-
wrapper.style.borderRadius = "4px";
|
|
4890
|
-
wrapper.style.padding = "56px 48px";
|
|
4891
|
-
wrapper.style.minHeight = "100%";
|
|
4892
|
-
wrapper.style.transformOrigin = "top center";
|
|
4893
|
-
wrapper.style.transition = "transform 0.2s ease";
|
|
4894
|
-
wrapper.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4895
|
-
wrapper.style.color = "#1e293b";
|
|
4896
|
-
container.appendChild(wrapper);
|
|
5194
|
+
container.style.display = "flex";
|
|
5195
|
+
container.style.justifyContent = "center";
|
|
5196
|
+
container.style.alignItems = "flex-start";
|
|
4897
5197
|
ctx.container.appendChild(container);
|
|
4898
5198
|
let scale = 1;
|
|
4899
5199
|
let extractedRawText = "";
|
|
@@ -4920,21 +5220,27 @@ var DocPlugin = class {
|
|
|
4920
5220
|
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4921
5221
|
const totalPages = Math.max(1, rawPages.length);
|
|
4922
5222
|
let currentPage = 1;
|
|
4923
|
-
wrapper.innerHTML = "";
|
|
4924
5223
|
const pageCards = [];
|
|
4925
5224
|
for (let i = 0; i < totalPages; i++) {
|
|
4926
5225
|
const pageCard = document.createElement("div");
|
|
4927
5226
|
pageCard.className = "fp-doc-page-card";
|
|
5227
|
+
pageCard.style.width = "816px";
|
|
5228
|
+
pageCard.style.height = "1056px";
|
|
4928
5229
|
pageCard.style.backgroundColor = "#ffffff";
|
|
4929
5230
|
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4930
5231
|
pageCard.style.borderRadius = "4px";
|
|
4931
|
-
pageCard.style.padding = "
|
|
4932
|
-
pageCard.style.
|
|
5232
|
+
pageCard.style.padding = "96px 72px";
|
|
5233
|
+
pageCard.style.boxSizing = "border-box";
|
|
5234
|
+
pageCard.style.overflow = "hidden";
|
|
4933
5235
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5236
|
+
pageCard.style.transformOrigin = "top center";
|
|
5237
|
+
pageCard.style.transition = "transform 0.2s ease";
|
|
5238
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5239
|
+
pageCard.style.color = "#1e293b";
|
|
4934
5240
|
if (isFallback && i === 0) {
|
|
4935
5241
|
pageCard.innerHTML = `
|
|
4936
5242
|
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4937
|
-
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${
|
|
5243
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify6.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4938
5244
|
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4939
5245
|
</div>
|
|
4940
5246
|
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
@@ -4942,15 +5248,17 @@ var DocPlugin = class {
|
|
|
4942
5248
|
} else {
|
|
4943
5249
|
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4944
5250
|
}
|
|
4945
|
-
|
|
5251
|
+
container.appendChild(pageCard);
|
|
4946
5252
|
pageCards.push(pageCard);
|
|
4947
5253
|
}
|
|
4948
5254
|
let indicator = null;
|
|
4949
5255
|
if (totalPages > 1) {
|
|
4950
5256
|
indicator = document.createElement("div");
|
|
4951
5257
|
indicator.className = "fp-doc-page-indicator";
|
|
4952
|
-
indicator.style.position = "
|
|
5258
|
+
indicator.style.position = "fixed";
|
|
4953
5259
|
indicator.style.bottom = "16px";
|
|
5260
|
+
indicator.style.left = "50%";
|
|
5261
|
+
indicator.style.transform = "translateX(-50%)";
|
|
4954
5262
|
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4955
5263
|
indicator.style.backdropFilter = "blur(8px)";
|
|
4956
5264
|
indicator.style.color = "#f8fafc";
|
|
@@ -4964,17 +5272,25 @@ var DocPlugin = class {
|
|
|
4964
5272
|
indicator.style.userSelect = "none";
|
|
4965
5273
|
indicator.style.pointerEvents = "none";
|
|
4966
5274
|
indicator.style.textAlign = "center";
|
|
4967
|
-
indicator.style.width = "fit-content";
|
|
4968
|
-
indicator.style.margin = "16px auto 0";
|
|
4969
5275
|
container.appendChild(indicator);
|
|
4970
5276
|
}
|
|
5277
|
+
let rotation = 0;
|
|
5278
|
+
const applyTransform = () => {
|
|
5279
|
+
const activeCard = pageCards[currentPage - 1];
|
|
5280
|
+
if (activeCard) {
|
|
5281
|
+
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5282
|
+
}
|
|
5283
|
+
};
|
|
4971
5284
|
const showPage = (pageNum) => {
|
|
4972
5285
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
card.style.display =
|
|
4976
|
-
|
|
4977
|
-
|
|
5286
|
+
pageCards.forEach((card, idx) => {
|
|
5287
|
+
if (idx + 1 === currentPage) {
|
|
5288
|
+
card.style.display = "block";
|
|
5289
|
+
card.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5290
|
+
} else {
|
|
5291
|
+
card.style.display = "none";
|
|
5292
|
+
}
|
|
5293
|
+
});
|
|
4978
5294
|
if (indicator) {
|
|
4979
5295
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4980
5296
|
}
|
|
@@ -4983,19 +5299,13 @@ var DocPlugin = class {
|
|
|
4983
5299
|
if (totalPages > 1) {
|
|
4984
5300
|
showPage(1);
|
|
4985
5301
|
}
|
|
4986
|
-
let rotation = 0;
|
|
4987
5302
|
const calculateFitScale = () => {
|
|
4988
|
-
const
|
|
4989
|
-
const
|
|
4990
|
-
const elH = activeCard.offsetHeight || 1e3;
|
|
5303
|
+
const elW = 816;
|
|
5304
|
+
const elH = 1056;
|
|
4991
5305
|
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4992
5306
|
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4993
5307
|
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
4994
5308
|
};
|
|
4995
|
-
const applyTransform = () => {
|
|
4996
|
-
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4997
|
-
wrapper.style.transformOrigin = "top center";
|
|
4998
|
-
};
|
|
4999
5309
|
setTimeout(() => {
|
|
5000
5310
|
scale = calculateFitScale();
|
|
5001
5311
|
applyTransform();
|
|
@@ -5153,8 +5463,28 @@ var DocPlugin = class {
|
|
|
5153
5463
|
}
|
|
5154
5464
|
splitIntoPages(text) {
|
|
5155
5465
|
if (!text) return [""];
|
|
5156
|
-
const
|
|
5157
|
-
|
|
5466
|
+
const explicitParts = text.split(/[\x0C\f]|\r?\n\s*[-=_]{3,}\s*(?:PAGE|Page|page break)[\s\d\w-]*[-=_]{3,}\s*\r?\n/i).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
5467
|
+
if (explicitParts.length === 0) explicitParts.push(text);
|
|
5468
|
+
const maxLinesPerPage = 48;
|
|
5469
|
+
const finalPages = [];
|
|
5470
|
+
for (const part of explicitParts) {
|
|
5471
|
+
const lines = part.split(/\r?\n/);
|
|
5472
|
+
let currentLines = [];
|
|
5473
|
+
let count = 0;
|
|
5474
|
+
for (const line of lines) {
|
|
5475
|
+
currentLines.push(line);
|
|
5476
|
+
count++;
|
|
5477
|
+
if (count >= maxLinesPerPage) {
|
|
5478
|
+
finalPages.push(currentLines.join("\n"));
|
|
5479
|
+
currentLines = [];
|
|
5480
|
+
count = 0;
|
|
5481
|
+
}
|
|
5482
|
+
}
|
|
5483
|
+
if (currentLines.length > 0) {
|
|
5484
|
+
finalPages.push(currentLines.join("\n"));
|
|
5485
|
+
}
|
|
5486
|
+
}
|
|
5487
|
+
return finalPages.length > 0 ? finalPages : [text];
|
|
5158
5488
|
}
|
|
5159
5489
|
/**
|
|
5160
5490
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
@@ -5163,17 +5493,65 @@ var DocPlugin = class {
|
|
|
5163
5493
|
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
5164
5494
|
let html = "";
|
|
5165
5495
|
let inList = false;
|
|
5166
|
-
|
|
5167
|
-
|
|
5496
|
+
let tableLines = [];
|
|
5497
|
+
const flushTable = () => {
|
|
5498
|
+
if (tableLines.length > 0) {
|
|
5499
|
+
html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12px;">';
|
|
5500
|
+
for (const tLine of tableLines) {
|
|
5501
|
+
html += "<tr>";
|
|
5502
|
+
const cols = tLine.split(" ");
|
|
5503
|
+
for (const col of cols) {
|
|
5504
|
+
html += `<td style="border: 1px solid #cbd5e1; padding: 6px 8px;">${DOMPurify6.sanitize(col.trim())}</td>`;
|
|
5505
|
+
}
|
|
5506
|
+
html += "</tr>";
|
|
5507
|
+
}
|
|
5508
|
+
html += "</table>";
|
|
5509
|
+
tableLines = [];
|
|
5510
|
+
}
|
|
5511
|
+
};
|
|
5512
|
+
let i = 0;
|
|
5513
|
+
while (i < lines.length) {
|
|
5514
|
+
let line = lines[i];
|
|
5515
|
+
let tabCount = (line.match(/\t/g) || []).length;
|
|
5516
|
+
if (tabCount > 0) {
|
|
5517
|
+
let consecutiveTableLines = 1;
|
|
5518
|
+
let j = i + 1;
|
|
5519
|
+
while (j < lines.length) {
|
|
5520
|
+
const nextTabCount = (lines[j].match(/\t/g) || []).length;
|
|
5521
|
+
if (nextTabCount === tabCount) {
|
|
5522
|
+
consecutiveTableLines++;
|
|
5523
|
+
j++;
|
|
5524
|
+
} else {
|
|
5525
|
+
break;
|
|
5526
|
+
}
|
|
5527
|
+
}
|
|
5528
|
+
if (consecutiveTableLines >= 3) {
|
|
5529
|
+
if (inList) {
|
|
5530
|
+
html += "</ul>";
|
|
5531
|
+
inList = false;
|
|
5532
|
+
}
|
|
5533
|
+
tableLines = lines.slice(i, j);
|
|
5534
|
+
flushTable();
|
|
5535
|
+
i = j;
|
|
5536
|
+
continue;
|
|
5537
|
+
}
|
|
5538
|
+
}
|
|
5539
|
+
line = line.trim();
|
|
5168
5540
|
if (!line) {
|
|
5169
5541
|
if (inList) {
|
|
5170
5542
|
html += "</ul>";
|
|
5171
5543
|
inList = false;
|
|
5172
5544
|
}
|
|
5545
|
+
html += '<div style="height: 1.15em;"></div>';
|
|
5546
|
+
i++;
|
|
5547
|
+
continue;
|
|
5548
|
+
}
|
|
5549
|
+
if (/^[\x00-\x1F\x7F-\x9F]+$/.test(line)) {
|
|
5550
|
+
i++;
|
|
5173
5551
|
continue;
|
|
5174
5552
|
}
|
|
5175
|
-
if (
|
|
5176
|
-
|
|
5553
|
+
if ((line.includes("Normal.dot") || line.includes("Microsoft Word") || line.includes("Times New Roman")) && line.length < 30) {
|
|
5554
|
+
i++;
|
|
5177
5555
|
continue;
|
|
5178
5556
|
}
|
|
5179
5557
|
if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
|
|
@@ -5181,24 +5559,26 @@ var DocPlugin = class {
|
|
|
5181
5559
|
html += "</ul>";
|
|
5182
5560
|
inList = false;
|
|
5183
5561
|
}
|
|
5184
|
-
html += `<h2 style="font-size:
|
|
5562
|
+
html += `<h2 style="font-size: 16px; font-weight: 700; color: #1e3a8a; margin: 16px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6.sanitize(line)}</h2>`;
|
|
5185
5563
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
5186
5564
|
if (!inList) {
|
|
5187
5565
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
5188
5566
|
inList = true;
|
|
5189
5567
|
}
|
|
5190
5568
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
5191
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
5569
|
+
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6.sanitize(bulletText)}</li>`;
|
|
5192
5570
|
} else {
|
|
5193
5571
|
if (inList) {
|
|
5194
5572
|
html += "</ul>";
|
|
5195
5573
|
inList = false;
|
|
5196
5574
|
}
|
|
5197
|
-
html += `<p style="line-height: 1.
|
|
5575
|
+
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6.sanitize(line)}</p>`;
|
|
5198
5576
|
}
|
|
5577
|
+
i++;
|
|
5199
5578
|
}
|
|
5200
5579
|
if (inList) html += "</ul>";
|
|
5201
|
-
|
|
5580
|
+
flushTable();
|
|
5581
|
+
return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify6.sanitize(filename)})</p>`;
|
|
5202
5582
|
}
|
|
5203
5583
|
};
|
|
5204
5584
|
function docPlugin() {
|
|
@@ -5376,7 +5756,7 @@ var PptPlugin = class {
|
|
|
5376
5756
|
if (s.pictureUrl) {
|
|
5377
5757
|
contentHtml = `
|
|
5378
5758
|
<div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
|
|
5379
|
-
<img src="${s.pictureUrl}" alt="${
|
|
5759
|
+
<img src="${s.pictureUrl}" alt="${DOMPurify6.sanitize(s.title)}" style="max-width: 95%; max-height: 95%; object-fit: contain; border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,0.1); background: #ffffff;" />
|
|
5380
5760
|
</div>
|
|
5381
5761
|
`;
|
|
5382
5762
|
} else if (s.tableColumns.length > 0) {
|
|
@@ -5386,7 +5766,7 @@ var PptPlugin = class {
|
|
|
5386
5766
|
<table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
|
|
5387
5767
|
<thead>
|
|
5388
5768
|
<tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
|
|
5389
|
-
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${
|
|
5769
|
+
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify6.sanitize(c)}</th>`).join("")}
|
|
5390
5770
|
</tr>
|
|
5391
5771
|
</thead>
|
|
5392
5772
|
<tbody>
|
|
@@ -5402,7 +5782,7 @@ var PptPlugin = class {
|
|
|
5402
5782
|
} else {
|
|
5403
5783
|
const pTags = s.paragraphs.map((p) => {
|
|
5404
5784
|
const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
|
|
5405
|
-
return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${
|
|
5785
|
+
return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${DOMPurify6.sanitize(l)}</p>`).join("");
|
|
5406
5786
|
}).join("");
|
|
5407
5787
|
contentHtml = `
|
|
5408
5788
|
<div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
|
|
@@ -5415,11 +5795,11 @@ var PptPlugin = class {
|
|
|
5415
5795
|
<!-- Header Banner matching PowerPoint design -->
|
|
5416
5796
|
<div style="background: linear-gradient(90deg, #a3e635 0%, #84cc16 100%); padding: 12px 24px; border-radius: 4px; display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); flex-shrink: 0;">
|
|
5417
5797
|
<h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
|
|
5418
|
-
${
|
|
5798
|
+
${DOMPurify6.sanitize(s.title)}
|
|
5419
5799
|
</h1>
|
|
5420
5800
|
${s.subtitle ? `
|
|
5421
5801
|
<span style="background: #38bdf8; color: #ffffff; padding: 4px 14px; border-radius: 4px; font-weight: 700; font-size: 13px; letter-spacing: 0.5px; box-shadow: 0 1px 4px rgba(0,0,0,0.15);">
|
|
5422
|
-
${
|
|
5802
|
+
${DOMPurify6.sanitize(s.subtitle)}
|
|
5423
5803
|
</span>
|
|
5424
5804
|
` : `
|
|
5425
5805
|
<span style="font-size: 12px; color: #365314; font-weight: 600;">
|