@files-preview-app/preview-file 1.2.9 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular.cjs +505 -147
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +504 -147
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +548 -147
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +546 -148
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +505 -147
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +504 -147
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +505 -147
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +504 -147
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
package/dist/angular.js
CHANGED
|
@@ -385,16 +385,21 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
385
385
|
metadata.mimeType = source.type || void 0;
|
|
386
386
|
metadata.extension = extractExtension(source.name);
|
|
387
387
|
buffer = await source.arrayBuffer();
|
|
388
|
-
} else if (source instanceof Blob) {
|
|
388
|
+
} else if (source instanceof Blob || source && typeof source.arrayBuffer === "function" && typeof source.size === "number") {
|
|
389
389
|
metadata.size = source.size;
|
|
390
390
|
metadata.mimeType = source.type || void 0;
|
|
391
|
+
if (source.name) {
|
|
392
|
+
metadata.name = source.name;
|
|
393
|
+
metadata.extension = extractExtension(source.name);
|
|
394
|
+
}
|
|
391
395
|
buffer = await source.arrayBuffer();
|
|
392
|
-
} else if (source instanceof ArrayBuffer) {
|
|
396
|
+
} else if (source instanceof ArrayBuffer || Object.prototype.toString.call(source) === "[object ArrayBuffer]" || source && typeof source.byteLength === "number" && typeof source.slice === "function") {
|
|
393
397
|
buffer = source;
|
|
394
|
-
} else if (source instanceof Uint8Array) {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
+
} else if (source instanceof Uint8Array || ArrayBuffer.isView(source)) {
|
|
399
|
+
const view = source;
|
|
400
|
+
buffer = view.buffer.slice(
|
|
401
|
+
view.byteOffset,
|
|
402
|
+
view.byteOffset + view.byteLength
|
|
398
403
|
);
|
|
399
404
|
} else {
|
|
400
405
|
throw new Error("Unsupported file source type");
|
|
@@ -479,6 +484,45 @@ function createElement(tag, attrs, ...children) {
|
|
|
479
484
|
}
|
|
480
485
|
return el;
|
|
481
486
|
}
|
|
487
|
+
var DB_NAME = "PreviewFileTransferDB";
|
|
488
|
+
var DB_STORE = "transfers";
|
|
489
|
+
function openDB() {
|
|
490
|
+
return new Promise((resolve, reject) => {
|
|
491
|
+
if (typeof indexedDB === "undefined") {
|
|
492
|
+
return reject(new Error("IndexedDB is not available"));
|
|
493
|
+
}
|
|
494
|
+
const req = indexedDB.open(DB_NAME, 1);
|
|
495
|
+
req.onupgradeneeded = () => {
|
|
496
|
+
const db = req.result;
|
|
497
|
+
if (!db.objectStoreNames.contains(DB_STORE)) {
|
|
498
|
+
db.createObjectStore(DB_STORE, { keyPath: "id" });
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
req.onsuccess = () => resolve(req.result);
|
|
502
|
+
req.onerror = () => reject(req.error);
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
async function saveTransferPayload(id, payload) {
|
|
506
|
+
if (typeof window !== "undefined") {
|
|
507
|
+
try {
|
|
508
|
+
window[id] = payload;
|
|
509
|
+
window.__lastTransfer = payload;
|
|
510
|
+
} catch {
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
try {
|
|
514
|
+
const db = await openDB();
|
|
515
|
+
return new Promise((resolve, reject) => {
|
|
516
|
+
const tx = db.transaction(DB_STORE, "readwrite");
|
|
517
|
+
const store = tx.objectStore(DB_STORE);
|
|
518
|
+
store.put({ id, ...payload, timestamp: Date.now() });
|
|
519
|
+
tx.oncomplete = () => resolve();
|
|
520
|
+
tx.onerror = () => reject(tx.error);
|
|
521
|
+
});
|
|
522
|
+
} catch (e) {
|
|
523
|
+
console.warn("[saveTransferPayload] IndexedDB store warning:", e);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
482
526
|
var ICON_ZOOM_IN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="11" y1="8" x2="11" y2="14"></line><line x1="8" y1="11" x2="14" y2="11"></line></svg>`;
|
|
483
527
|
var ICON_ZOOM_OUT = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="8" y1="11" x2="14" y2="11"></line></svg>`;
|
|
484
528
|
var ICON_FIT_PAGE = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"></rect><line x1="8" y1="12" x2="16" y2="12"></line><polyline points="11 9 8 12 11 15"></polyline><polyline points="13 9 16 12 13 15"></polyline></svg>`;
|
|
@@ -498,6 +542,7 @@ var ICON_COPY = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" str
|
|
|
498
542
|
var ICON_FAST_FORWARD = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 19 22 12 13 5 13 19"></polygon><polygon points="2 19 11 12 2 5 2 19"></polygon></svg>`;
|
|
499
543
|
var ICON_REWIND = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="11 19 2 12 11 5 11 19"></polygon><polygon points="22 19 13 12 22 5 22 19"></polygon></svg>`;
|
|
500
544
|
var ICON_SPEED = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>`;
|
|
545
|
+
var ICON_EXTERNAL_WINDOW = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>`;
|
|
501
546
|
var ICON_MAP = {
|
|
502
547
|
"zoom-in": ICON_ZOOM_IN,
|
|
503
548
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -524,7 +569,9 @@ var ICON_MAP = {
|
|
|
524
569
|
"forward-10": ICON_FAST_FORWARD,
|
|
525
570
|
"rewind": ICON_REWIND,
|
|
526
571
|
"replay-10": ICON_REWIND,
|
|
527
|
-
"speed": ICON_SPEED
|
|
572
|
+
"speed": ICON_SPEED,
|
|
573
|
+
"open-window": ICON_EXTERNAL_WINDOW,
|
|
574
|
+
"external-window": ICON_EXTERNAL_WINDOW
|
|
528
575
|
};
|
|
529
576
|
var ToolbarController = class {
|
|
530
577
|
el;
|
|
@@ -741,7 +788,7 @@ var ThumbnailPanel = class {
|
|
|
741
788
|
}
|
|
742
789
|
}
|
|
743
790
|
};
|
|
744
|
-
var FilePreviewViewer = class {
|
|
791
|
+
var FilePreviewViewer = class _FilePreviewViewer {
|
|
745
792
|
plugins = [];
|
|
746
793
|
activeInstance = null;
|
|
747
794
|
abortController = null;
|
|
@@ -778,6 +825,7 @@ var FilePreviewViewer = class {
|
|
|
778
825
|
* Preview a file in the given container element.
|
|
779
826
|
*/
|
|
780
827
|
async preview(container, source, options = {}) {
|
|
828
|
+
this.currentOptions = options;
|
|
781
829
|
this.abort();
|
|
782
830
|
this.abortController = new AbortController();
|
|
783
831
|
const { signal } = this.abortController;
|
|
@@ -787,7 +835,10 @@ var FilePreviewViewer = class {
|
|
|
787
835
|
this.showLoading();
|
|
788
836
|
try {
|
|
789
837
|
const { buffer, metadata } = await sourceToArrayBuffer(source, signal);
|
|
790
|
-
|
|
838
|
+
if (options.metadata) {
|
|
839
|
+
Object.assign(metadata, options.metadata);
|
|
840
|
+
}
|
|
841
|
+
this.currentBuffer = buffer.slice(0);
|
|
791
842
|
this.currentMetadata = metadata;
|
|
792
843
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
793
844
|
const fileInfo = { metadata, buffer };
|
|
@@ -817,6 +868,7 @@ var FilePreviewViewer = class {
|
|
|
817
868
|
}
|
|
818
869
|
});
|
|
819
870
|
this.activeInstance = instance;
|
|
871
|
+
instance.openInSeparateWindow = () => this.openInSeparateWindow();
|
|
820
872
|
this.hideLoading();
|
|
821
873
|
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
822
874
|
if (options.showToolbar !== false && this.toolbar) {
|
|
@@ -826,26 +878,16 @@ var FilePreviewViewer = class {
|
|
|
826
878
|
actions.push({
|
|
827
879
|
id: "fullscreen",
|
|
828
880
|
icon: "fullscreen",
|
|
829
|
-
label: "
|
|
881
|
+
label: "Fullscreen",
|
|
830
882
|
type: "button",
|
|
831
883
|
group: "view",
|
|
832
|
-
execute:
|
|
884
|
+
execute: () => {
|
|
833
885
|
try {
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
if (this.wrapperEl?.requestFullscreen) {
|
|
838
|
-
await this.wrapperEl.requestFullscreen().catch(() => {
|
|
839
|
-
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
840
|
-
});
|
|
841
|
-
} else {
|
|
842
|
-
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
843
|
-
}
|
|
886
|
+
if (!document.fullscreenElement) {
|
|
887
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
888
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
844
889
|
} else {
|
|
845
|
-
|
|
846
|
-
await document.exitFullscreen().catch(() => {
|
|
847
|
-
});
|
|
848
|
-
}
|
|
890
|
+
document.exitFullscreen?.();
|
|
849
891
|
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
850
892
|
}
|
|
851
893
|
} catch {
|
|
@@ -857,6 +899,28 @@ var FilePreviewViewer = class {
|
|
|
857
899
|
}
|
|
858
900
|
});
|
|
859
901
|
}
|
|
902
|
+
const openWinAction = actions.find((a) => a.id === "open-window");
|
|
903
|
+
if (openWinAction) {
|
|
904
|
+
if (options?._isSeparateWindow) {
|
|
905
|
+
const idx = actions.indexOf(openWinAction);
|
|
906
|
+
if (idx !== -1) actions.splice(idx, 1);
|
|
907
|
+
} else {
|
|
908
|
+
openWinAction.execute = () => {
|
|
909
|
+
this.openInSeparateWindow();
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
} else if (!options?._isSeparateWindow) {
|
|
913
|
+
actions.push({
|
|
914
|
+
id: "open-window",
|
|
915
|
+
icon: "open-window",
|
|
916
|
+
label: "Open in Separate Full Window",
|
|
917
|
+
type: "button",
|
|
918
|
+
group: "actions",
|
|
919
|
+
execute: () => {
|
|
920
|
+
this.openInSeparateWindow();
|
|
921
|
+
}
|
|
922
|
+
});
|
|
923
|
+
}
|
|
860
924
|
this.toolbar.update(actions);
|
|
861
925
|
this.toolbar.show();
|
|
862
926
|
}
|
|
@@ -889,6 +953,104 @@ var FilePreviewViewer = class {
|
|
|
889
953
|
throw error;
|
|
890
954
|
}
|
|
891
955
|
}
|
|
956
|
+
/**
|
|
957
|
+
* Opens the current file preview in a separate full browser window.
|
|
958
|
+
*/
|
|
959
|
+
openInSeparateWindow() {
|
|
960
|
+
if (!this.currentBuffer) {
|
|
961
|
+
console.warn("[FilePreviewViewer] No active file buffer to open in separate window");
|
|
962
|
+
return null;
|
|
963
|
+
}
|
|
964
|
+
if (this.currentOptions.onOpenSeparateWindow) {
|
|
965
|
+
return this.currentOptions.onOpenSeparateWindow({
|
|
966
|
+
buffer: this.currentBuffer,
|
|
967
|
+
metadata: this.currentMetadata || { name: "Document" },
|
|
968
|
+
options: this.currentOptions
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
const transferId = "fp_win_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8);
|
|
972
|
+
let clonedBuffer;
|
|
973
|
+
try {
|
|
974
|
+
clonedBuffer = this.currentBuffer.slice(0);
|
|
975
|
+
} catch {
|
|
976
|
+
clonedBuffer = this.currentBuffer;
|
|
977
|
+
}
|
|
978
|
+
const payload = {
|
|
979
|
+
buffer: clonedBuffer,
|
|
980
|
+
metadata: this.currentMetadata ? { ...this.currentMetadata } : void 0,
|
|
981
|
+
options: { ...this.currentOptions, _isSeparateWindow: true }
|
|
982
|
+
};
|
|
983
|
+
if (typeof window !== "undefined") {
|
|
984
|
+
try {
|
|
985
|
+
window[transferId] = payload;
|
|
986
|
+
window.__lastTransfer = payload;
|
|
987
|
+
} catch {
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
saveTransferPayload(transferId, payload).catch((err) => {
|
|
991
|
+
console.warn("[FilePreviewViewer] Transfer payload save warning:", err);
|
|
992
|
+
});
|
|
993
|
+
let targetUrl = null;
|
|
994
|
+
if (this.currentOptions.standaloneViewerUrl) {
|
|
995
|
+
const u = new URL(this.currentOptions.standaloneViewerUrl, window.location.href);
|
|
996
|
+
u.searchParams.set("mode", "fullscreen");
|
|
997
|
+
u.searchParams.set("transferId", transferId);
|
|
998
|
+
targetUrl = u.toString();
|
|
999
|
+
} else if (typeof window !== "undefined" && window.location?.href && !window.location.href.startsWith("about:")) {
|
|
1000
|
+
const u = new URL(window.location.href);
|
|
1001
|
+
u.searchParams.set("mode", "fullscreen");
|
|
1002
|
+
u.searchParams.set("transferId", transferId);
|
|
1003
|
+
targetUrl = u.toString();
|
|
1004
|
+
}
|
|
1005
|
+
if (targetUrl) {
|
|
1006
|
+
const newWin2 = window.open(targetUrl, "_blank");
|
|
1007
|
+
if (!newWin2) {
|
|
1008
|
+
alert("Popup blocker prevented opening the preview in a separate window. Please allow popups for this site.");
|
|
1009
|
+
return null;
|
|
1010
|
+
}
|
|
1011
|
+
return newWin2;
|
|
1012
|
+
}
|
|
1013
|
+
const title = (this.currentMetadata?.name || "Document Preview") + " - Full Preview";
|
|
1014
|
+
const newWin = window.open("", "_blank");
|
|
1015
|
+
if (!newWin) {
|
|
1016
|
+
alert("Popup blocker prevented opening the preview in a separate window. Please allow popups for this site.");
|
|
1017
|
+
return null;
|
|
1018
|
+
}
|
|
1019
|
+
newWin.document.title = title;
|
|
1020
|
+
newWin.document.body.style.margin = "0";
|
|
1021
|
+
newWin.document.body.style.padding = "0";
|
|
1022
|
+
newWin.document.body.style.width = "100vw";
|
|
1023
|
+
newWin.document.body.style.height = "100vh";
|
|
1024
|
+
newWin.document.body.style.overflow = "hidden";
|
|
1025
|
+
newWin.document.body.style.backgroundColor = "#f8fafc";
|
|
1026
|
+
const headNodes = document.querySelectorAll('link[rel="stylesheet"], style');
|
|
1027
|
+
headNodes.forEach((node) => {
|
|
1028
|
+
newWin.document.head.appendChild(node.cloneNode(true));
|
|
1029
|
+
});
|
|
1030
|
+
const root = newWin.document.createElement("div");
|
|
1031
|
+
root.id = "full-window-preview-root";
|
|
1032
|
+
root.style.width = "100%";
|
|
1033
|
+
root.style.height = "100%";
|
|
1034
|
+
root.style.overflow = "hidden";
|
|
1035
|
+
newWin.document.body.appendChild(root);
|
|
1036
|
+
const separateViewer = new _FilePreviewViewer();
|
|
1037
|
+
for (const plugin of this.plugins) {
|
|
1038
|
+
separateViewer.registerPlugin(plugin);
|
|
1039
|
+
}
|
|
1040
|
+
separateViewer.preview(root, this.currentBuffer.slice(0), {
|
|
1041
|
+
...this.currentOptions,
|
|
1042
|
+
showToolbar: true,
|
|
1043
|
+
toolbarPosition: "top",
|
|
1044
|
+
metadata: this.currentMetadata || void 0,
|
|
1045
|
+
_isSeparateWindow: true
|
|
1046
|
+
}).catch((err) => {
|
|
1047
|
+
console.error("[FilePreviewViewer] Error rendering in separate window:", err);
|
|
1048
|
+
});
|
|
1049
|
+
newWin.addEventListener("beforeunload", () => {
|
|
1050
|
+
separateViewer.destroy();
|
|
1051
|
+
});
|
|
1052
|
+
return newWin;
|
|
1053
|
+
}
|
|
892
1054
|
/**
|
|
893
1055
|
* Subscribe to viewer events.
|
|
894
1056
|
*/
|
|
@@ -1294,8 +1456,20 @@ var CfbfReader = class {
|
|
|
1294
1456
|
}
|
|
1295
1457
|
};
|
|
1296
1458
|
if (typeof window !== "undefined" && pdfjsLib.GlobalWorkerOptions) {
|
|
1297
|
-
if (!pdfjsLib.GlobalWorkerOptions.workerSrc) {
|
|
1298
|
-
|
|
1459
|
+
if (!pdfjsLib.GlobalWorkerOptions.workerPort && !pdfjsLib.GlobalWorkerOptions.workerSrc) {
|
|
1460
|
+
const customWorker = window.__PDF_WORKER_SRC__;
|
|
1461
|
+
if (customWorker) {
|
|
1462
|
+
pdfjsLib.GlobalWorkerOptions.workerSrc = customWorker;
|
|
1463
|
+
} else {
|
|
1464
|
+
try {
|
|
1465
|
+
pdfjsLib.GlobalWorkerOptions.workerPort = new Worker(
|
|
1466
|
+
new URL("pdfjs-dist/build/pdf.worker.min.mjs", import.meta.url),
|
|
1467
|
+
{ type: "module" }
|
|
1468
|
+
);
|
|
1469
|
+
} catch {
|
|
1470
|
+
pdfjsLib.GlobalWorkerOptions.workerSrc = "./pdf.worker.min.mjs";
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1299
1473
|
}
|
|
1300
1474
|
}
|
|
1301
1475
|
var PdfPlugin = class {
|
|
@@ -1389,6 +1563,14 @@ var PdfPlugin = class {
|
|
|
1389
1563
|
type: "button",
|
|
1390
1564
|
group: "actions",
|
|
1391
1565
|
execute: () => instance.print?.()
|
|
1566
|
+
},
|
|
1567
|
+
{
|
|
1568
|
+
id: "open-window",
|
|
1569
|
+
icon: "open-window",
|
|
1570
|
+
label: "Open in Separate Full Window",
|
|
1571
|
+
type: "button",
|
|
1572
|
+
group: "actions",
|
|
1573
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
1392
1574
|
}
|
|
1393
1575
|
];
|
|
1394
1576
|
}
|
|
@@ -1438,18 +1620,21 @@ var PdfPlugin = class {
|
|
|
1438
1620
|
indicator.style.pointerEvents = "none";
|
|
1439
1621
|
container.appendChild(indicator);
|
|
1440
1622
|
ctx.container.appendChild(container);
|
|
1623
|
+
const standardFontsUrl = typeof window !== "undefined" && window.__PDF_STANDARD_FONTS_URL__ || "./standard_fonts/";
|
|
1624
|
+
const cmapsUrl = typeof window !== "undefined" && window.__PDF_CMAPS_URL__ || "./cmaps/";
|
|
1441
1625
|
const loadingTask = pdfjsLib.getDocument({
|
|
1442
|
-
data: new Uint8Array(ctx.buffer),
|
|
1443
|
-
cMapUrl:
|
|
1626
|
+
data: new Uint8Array(ctx.buffer.slice(0)),
|
|
1627
|
+
cMapUrl: cmapsUrl,
|
|
1444
1628
|
cMapPacked: true,
|
|
1445
|
-
standardFontDataUrl:
|
|
1629
|
+
standardFontDataUrl: standardFontsUrl,
|
|
1630
|
+
verbosity: 0
|
|
1446
1631
|
});
|
|
1447
1632
|
const pdfDoc = await loadingTask.promise;
|
|
1448
1633
|
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1449
1634
|
let currentPage = 1;
|
|
1450
1635
|
let zoomScale = 1;
|
|
1451
1636
|
let rotation = 0;
|
|
1452
|
-
let fitMode = "
|
|
1637
|
+
let fitMode = "page";
|
|
1453
1638
|
let currentRenderTask = null;
|
|
1454
1639
|
const renderPage = async (pageNum) => {
|
|
1455
1640
|
if (currentRenderTask) {
|
|
@@ -1469,15 +1654,15 @@ var PdfPlugin = class {
|
|
|
1469
1654
|
const containerWidth = container.clientWidth || 900;
|
|
1470
1655
|
const containerHeight = container.clientHeight || 700;
|
|
1471
1656
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1472
|
-
const availWidth = Math.max(
|
|
1473
|
-
const availHeight = Math.max(
|
|
1657
|
+
const availWidth = Math.max(320, containerWidth - 48);
|
|
1658
|
+
const availHeight = Math.max(550, containerHeight - 88);
|
|
1474
1659
|
const scaleW = availWidth / unscaledVp.width;
|
|
1475
1660
|
const scaleH = availHeight / unscaledVp.height;
|
|
1476
1661
|
let fitScale;
|
|
1477
1662
|
if (fitMode === "page") {
|
|
1478
|
-
fitScale = Math.max(0.
|
|
1663
|
+
fitScale = Math.max(0.4, Math.min(scaleW, scaleH));
|
|
1479
1664
|
} else {
|
|
1480
|
-
fitScale = Math.max(0.65, Math.min(1.
|
|
1665
|
+
fitScale = Math.max(0.65, Math.min(1.25, scaleW));
|
|
1481
1666
|
}
|
|
1482
1667
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1483
1668
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
@@ -1503,7 +1688,7 @@ var PdfPlugin = class {
|
|
|
1503
1688
|
currentRenderTask = null;
|
|
1504
1689
|
}
|
|
1505
1690
|
};
|
|
1506
|
-
|
|
1691
|
+
renderPage(1);
|
|
1507
1692
|
let resizeTimer = null;
|
|
1508
1693
|
const resizeObserver = new ResizeObserver(() => {
|
|
1509
1694
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
@@ -1547,7 +1732,7 @@ var PdfPlugin = class {
|
|
|
1547
1732
|
renderPage(currentPage);
|
|
1548
1733
|
},
|
|
1549
1734
|
fitToPage: () => {
|
|
1550
|
-
fitMode = fitMode === "
|
|
1735
|
+
fitMode = fitMode === "page" ? "width" : "page";
|
|
1551
1736
|
zoomScale = 1;
|
|
1552
1737
|
rotation = 0;
|
|
1553
1738
|
renderPage(currentPage);
|
|
@@ -2024,6 +2209,14 @@ var DocxPlugin = class {
|
|
|
2024
2209
|
type: "button",
|
|
2025
2210
|
group: "actions",
|
|
2026
2211
|
execute: () => instance.print?.()
|
|
2212
|
+
},
|
|
2213
|
+
{
|
|
2214
|
+
id: "open-window",
|
|
2215
|
+
icon: "open-window",
|
|
2216
|
+
label: "Open in Separate Full Window",
|
|
2217
|
+
type: "button",
|
|
2218
|
+
group: "actions",
|
|
2219
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
2027
2220
|
}
|
|
2028
2221
|
);
|
|
2029
2222
|
return actions;
|
|
@@ -2083,6 +2276,31 @@ var DocxPlugin = class {
|
|
|
2083
2276
|
}
|
|
2084
2277
|
if (wrapper.children.length > 0 && (wrapper.textContent?.trim().length ?? 0) > 0) {
|
|
2085
2278
|
renderedSuccessfully = true;
|
|
2279
|
+
try {
|
|
2280
|
+
const unzipped = unzipSync(new Uint8Array(ctx.buffer));
|
|
2281
|
+
const chartKeys = Object.keys(unzipped).filter((k) => k.replace(/^[./\\]+/, "").toLowerCase().startsWith("word/charts/chart") && k.endsWith(".xml")).sort();
|
|
2282
|
+
if (chartKeys.length > 0) {
|
|
2283
|
+
const allDivs = Array.from(wrapper.querySelectorAll("div"));
|
|
2284
|
+
const emptyContainers = allDivs.filter((div) => {
|
|
2285
|
+
const st = div.getAttribute("style") || "";
|
|
2286
|
+
return st.includes("width:") && st.includes("height:") && div.children.length === 0 && (div.textContent?.trim().length ?? 0) === 0;
|
|
2287
|
+
});
|
|
2288
|
+
chartKeys.forEach((cKey, idx) => {
|
|
2289
|
+
const target = emptyContainers[idx];
|
|
2290
|
+
if (target) {
|
|
2291
|
+
const xmlStr = strFromU8(unzipped[cKey]);
|
|
2292
|
+
const svg = this.parseAndRenderChartSvg(xmlStr);
|
|
2293
|
+
if (svg) {
|
|
2294
|
+
target.innerHTML = svg;
|
|
2295
|
+
target.style.display = "block";
|
|
2296
|
+
target.style.margin = "12px auto";
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
});
|
|
2300
|
+
}
|
|
2301
|
+
} catch (chartErr) {
|
|
2302
|
+
console.warn("[DocxPlugin] Non-critical error rendering DrawingML charts:", chartErr);
|
|
2303
|
+
}
|
|
2086
2304
|
}
|
|
2087
2305
|
} catch (err) {
|
|
2088
2306
|
console.warn("[DocxPlugin] docx-preview failed, triggering native fallback:", err);
|
|
@@ -2114,64 +2332,74 @@ var DocxPlugin = class {
|
|
|
2114
2332
|
}
|
|
2115
2333
|
let sections = Array.from(wrapper.querySelectorAll("section.docx"));
|
|
2116
2334
|
const cards = Array.from(wrapper.querySelectorAll(".fp-docx-page-card"));
|
|
2117
|
-
if (sections.length
|
|
2118
|
-
const
|
|
2119
|
-
const
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
const
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
nextSec.
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
nextArticle
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
nextSec.appendChild(
|
|
2335
|
+
if (sections.length > 0 && cards.length === 0) {
|
|
2336
|
+
const finalSections = [];
|
|
2337
|
+
for (const singleSec of sections) {
|
|
2338
|
+
const contentContainer = singleSec.querySelector("article") || singleSec;
|
|
2339
|
+
const children = Array.from(contentContainer.children);
|
|
2340
|
+
const pageH = singleSec.offsetHeight > 1300 ? 1122 : Math.max(1056, singleSec.offsetHeight);
|
|
2341
|
+
const secH = singleSec.scrollHeight || singleSec.offsetHeight;
|
|
2342
|
+
if (secH > pageH * 1.25 && children.length > 1) {
|
|
2343
|
+
const childHeights = children.map((c) => {
|
|
2344
|
+
const rectH = c.getBoundingClientRect().height;
|
|
2345
|
+
const offH = c.offsetHeight;
|
|
2346
|
+
const textLen = c.textContent?.trim().length || 0;
|
|
2347
|
+
const estH = Math.max(24, Math.ceil(textLen / 80) * 22 + 16);
|
|
2348
|
+
return Math.max(rectH, offH, estH);
|
|
2349
|
+
});
|
|
2350
|
+
const parent = singleSec.parentElement || wrapper;
|
|
2351
|
+
const headerEl = singleSec.querySelector("header");
|
|
2352
|
+
const footerEl = singleSec.querySelector("footer");
|
|
2353
|
+
contentContainer.innerHTML = "";
|
|
2354
|
+
singleSec.style.minHeight = `${pageH}px`;
|
|
2355
|
+
singleSec.style.boxSizing = "border-box";
|
|
2356
|
+
let curContent = contentContainer;
|
|
2357
|
+
let curSec = singleSec;
|
|
2358
|
+
let curH = 0;
|
|
2359
|
+
const maxH = pageH - 140;
|
|
2360
|
+
finalSections.push(singleSec);
|
|
2361
|
+
for (let i = 0; i < children.length; i++) {
|
|
2362
|
+
const child = children[i];
|
|
2363
|
+
const chH = childHeights[i];
|
|
2364
|
+
curContent.appendChild(child);
|
|
2365
|
+
curH += chH;
|
|
2366
|
+
if (curH >= maxH && i < children.length - 1) {
|
|
2367
|
+
const nextSec = document.createElement("section");
|
|
2368
|
+
nextSec.className = singleSec.className;
|
|
2369
|
+
nextSec.style.cssText = singleSec.style.cssText;
|
|
2370
|
+
nextSec.style.minHeight = `${pageH}px`;
|
|
2371
|
+
nextSec.style.boxSizing = "border-box";
|
|
2372
|
+
nextSec.style.backgroundColor = "#ffffff";
|
|
2373
|
+
nextSec.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
2374
|
+
nextSec.style.borderRadius = "4px";
|
|
2375
|
+
nextSec.style.marginBottom = "24px";
|
|
2376
|
+
if (headerEl) {
|
|
2377
|
+
nextSec.appendChild(headerEl.cloneNode(true));
|
|
2378
|
+
}
|
|
2379
|
+
const nextArticle = document.createElement("article");
|
|
2380
|
+
if (contentContainer.tagName.toLowerCase() === "article") {
|
|
2381
|
+
nextArticle.style.cssText = contentContainer.style.cssText;
|
|
2382
|
+
}
|
|
2383
|
+
nextSec.appendChild(nextArticle);
|
|
2384
|
+
if (footerEl) {
|
|
2385
|
+
nextSec.appendChild(footerEl.cloneNode(true));
|
|
2386
|
+
}
|
|
2387
|
+
if (curSec.nextSibling) {
|
|
2388
|
+
parent.insertBefore(nextSec, curSec.nextSibling);
|
|
2389
|
+
} else {
|
|
2390
|
+
parent.appendChild(nextSec);
|
|
2391
|
+
}
|
|
2392
|
+
finalSections.push(nextSec);
|
|
2393
|
+
curSec = nextSec;
|
|
2394
|
+
curContent = nextArticle;
|
|
2395
|
+
curH = 0;
|
|
2166
2396
|
}
|
|
2167
|
-
parent.appendChild(nextSec);
|
|
2168
|
-
newSections.push(nextSec);
|
|
2169
|
-
curContent = nextArticle;
|
|
2170
|
-
curH = 0;
|
|
2171
2397
|
}
|
|
2398
|
+
} else {
|
|
2399
|
+
finalSections.push(singleSec);
|
|
2172
2400
|
}
|
|
2173
|
-
sections = newSections;
|
|
2174
2401
|
}
|
|
2402
|
+
sections = finalSections;
|
|
2175
2403
|
}
|
|
2176
2404
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2177
2405
|
const totalPages = Math.max(1, pageElements.length);
|
|
@@ -2563,6 +2791,88 @@ var DocxPlugin = class {
|
|
|
2563
2791
|
}
|
|
2564
2792
|
return result;
|
|
2565
2793
|
}
|
|
2794
|
+
parseAndRenderChartSvg(xmlStr, width = 500, height = 260) {
|
|
2795
|
+
const catMatches = [...xmlStr.matchAll(/<c:cat>[\s\S]*?<c:strCache>([\s\S]*?)<\/c:strCache>/g)];
|
|
2796
|
+
let categories = [];
|
|
2797
|
+
if (catMatches.length > 0) {
|
|
2798
|
+
categories = [...catMatches[0][1].matchAll(/<c:v>([^<]+)<\/c:v>/g)].map((m) => m[1]);
|
|
2799
|
+
}
|
|
2800
|
+
if (categories.length === 0) {
|
|
2801
|
+
categories = ["Category 1", "Category 2", "Category 3", "Category 4"];
|
|
2802
|
+
}
|
|
2803
|
+
const defaultColors = ["#004586", "#ff420e", "#ffd320", "#579d1c", "#7e0021", "#83caff"];
|
|
2804
|
+
const sers = [...xmlStr.matchAll(/<c:ser>([\s\S]*?)<\/c:ser>/g)];
|
|
2805
|
+
const series = [];
|
|
2806
|
+
sers.forEach((s, sIdx) => {
|
|
2807
|
+
const titleMatch = s[1].match(/<c:tx>[\s\S]*?<c:v>([^<]+)<\/c:v>/);
|
|
2808
|
+
const title = titleMatch ? titleMatch[1] : `Series ${sIdx + 1}`;
|
|
2809
|
+
const clrMatch = s[1].match(/<a:srgbClr\s+val="([^"]+)"/);
|
|
2810
|
+
const color = clrMatch ? "#" + clrMatch[1] : defaultColors[sIdx % defaultColors.length];
|
|
2811
|
+
const valMatch = s[1].match(/<c:val>[\s\S]*?<c:numCache>([\s\S]*?)<\/c:numCache>/);
|
|
2812
|
+
let values = [];
|
|
2813
|
+
if (valMatch) {
|
|
2814
|
+
values = [...valMatch[1].matchAll(/<c:pt\s+idx="(\d+)">\s*<c:v>([^<]+)<\/c:v>/g)].sort((a, b) => parseInt(a[1], 10) - parseInt(b[1], 10)).map((m) => parseFloat(m[2]) || 0);
|
|
2815
|
+
}
|
|
2816
|
+
series.push({ title, color, values });
|
|
2817
|
+
});
|
|
2818
|
+
if (series.length === 0) return "";
|
|
2819
|
+
let maxVal = 10;
|
|
2820
|
+
series.forEach((s) => s.values.forEach((v) => {
|
|
2821
|
+
if (v > maxVal) maxVal = v;
|
|
2822
|
+
}));
|
|
2823
|
+
maxVal = Math.ceil(maxVal * 1.15);
|
|
2824
|
+
if (maxVal % 2 !== 0) maxVal++;
|
|
2825
|
+
const padLeft = 45;
|
|
2826
|
+
const padBottom = 55;
|
|
2827
|
+
const padTop = 20;
|
|
2828
|
+
const padRight = 20;
|
|
2829
|
+
const plotW = width - padLeft - padRight;
|
|
2830
|
+
const plotH = height - padTop - padBottom;
|
|
2831
|
+
const yTicks = 5;
|
|
2832
|
+
let gridLines = "";
|
|
2833
|
+
for (let i = 0; i <= yTicks; i++) {
|
|
2834
|
+
const val = maxVal / yTicks * i;
|
|
2835
|
+
const y = padTop + plotH - val / maxVal * plotH;
|
|
2836
|
+
gridLines += `<line x1="${padLeft}" y1="${y}" x2="${padLeft + plotW}" y2="${y}" stroke="#e2e8f0" stroke-width="1" />`;
|
|
2837
|
+
gridLines += `<text x="${padLeft - 8}" y="${y + 4}" text-anchor="end" font-size="11" fill="#64748b" font-family="Calibri, sans-serif">${Math.round(val)}</text>`;
|
|
2838
|
+
}
|
|
2839
|
+
const numCats = categories.length;
|
|
2840
|
+
const numSers = series.length;
|
|
2841
|
+
const groupW = plotW / numCats;
|
|
2842
|
+
const barW = Math.max(8, Math.min(28, groupW * 0.7 / numSers));
|
|
2843
|
+
const groupPad = (groupW - barW * numSers) / 2;
|
|
2844
|
+
let bars = "";
|
|
2845
|
+
let catLabels = "";
|
|
2846
|
+
for (let c = 0; c < numCats; c++) {
|
|
2847
|
+
const catX = padLeft + c * groupW;
|
|
2848
|
+
catLabels += `<text x="${catX + groupW / 2}" y="${padTop + plotH + 18}" text-anchor="middle" font-size="11" fill="#334155" font-family="Calibri, sans-serif">${categories[c]}</text>`;
|
|
2849
|
+
for (let s = 0; s < numSers; s++) {
|
|
2850
|
+
const val = series[s].values[c] ?? 0;
|
|
2851
|
+
const bH = Math.max(0, val / maxVal * plotH);
|
|
2852
|
+
const bX = catX + groupPad + s * barW;
|
|
2853
|
+
const bY = padTop + plotH - bH;
|
|
2854
|
+
bars += `<rect x="${bX}" y="${bY}" width="${barW - 2}" height="${bH}" fill="${series[s].color}" rx="1" />`;
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2857
|
+
let legend = "";
|
|
2858
|
+
const legY = height - 12;
|
|
2859
|
+
let legX = padLeft + (plotW - numSers * 100) / 2;
|
|
2860
|
+
series.forEach((s) => {
|
|
2861
|
+
legend += `<rect x="${legX}" y="${legY - 9}" width="10" height="10" fill="${s.color}" rx="2" />`;
|
|
2862
|
+
legend += `<text x="${legX + 15}" y="${legY}" font-size="11" fill="#475569" font-family="Calibri, sans-serif">${s.title}</text>`;
|
|
2863
|
+
legX += 95;
|
|
2864
|
+
});
|
|
2865
|
+
return `
|
|
2866
|
+
<svg viewBox="0 0 ${width} ${height}" width="100%" height="100%" style="background:#ffffff; border-radius:4px; overflow:visible;" xmlns="http://www.w3.org/2000/svg">
|
|
2867
|
+
${gridLines}
|
|
2868
|
+
<line x1="${padLeft}" y1="${padTop + plotH}" x2="${padLeft + plotW}" y2="${padTop + plotH}" stroke="#94a3b8" stroke-width="1.5" />
|
|
2869
|
+
<line x1="${padLeft}" y1="${padTop}" x2="${padLeft}" y2="${padTop + plotH}" stroke="#94a3b8" stroke-width="1.5" />
|
|
2870
|
+
${bars}
|
|
2871
|
+
${catLabels}
|
|
2872
|
+
${legend}
|
|
2873
|
+
</svg>
|
|
2874
|
+
`.trim();
|
|
2875
|
+
}
|
|
2566
2876
|
};
|
|
2567
2877
|
function docxPlugin() {
|
|
2568
2878
|
return new DocxPlugin();
|
|
@@ -3129,6 +3439,16 @@ var CodePlugin = class {
|
|
|
3129
3439
|
execute: () => {
|
|
3130
3440
|
instance.print?.();
|
|
3131
3441
|
}
|
|
3442
|
+
},
|
|
3443
|
+
{
|
|
3444
|
+
id: "open-window",
|
|
3445
|
+
icon: "open-window",
|
|
3446
|
+
label: "Open in Separate Full Window",
|
|
3447
|
+
type: "button",
|
|
3448
|
+
group: "actions",
|
|
3449
|
+
execute: () => {
|
|
3450
|
+
instance.openInSeparateWindow?.();
|
|
3451
|
+
}
|
|
3132
3452
|
}
|
|
3133
3453
|
);
|
|
3134
3454
|
return actions;
|
|
@@ -4297,6 +4617,14 @@ var RtfPlugin = class {
|
|
|
4297
4617
|
type: "button",
|
|
4298
4618
|
group: "actions",
|
|
4299
4619
|
execute: () => instance.print?.()
|
|
4620
|
+
},
|
|
4621
|
+
{
|
|
4622
|
+
id: "open-window",
|
|
4623
|
+
icon: "open-window",
|
|
4624
|
+
label: "Open in Separate Full Window",
|
|
4625
|
+
type: "button",
|
|
4626
|
+
group: "actions",
|
|
4627
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
4300
4628
|
}
|
|
4301
4629
|
);
|
|
4302
4630
|
return actions;
|
|
@@ -4349,59 +4677,54 @@ var RtfPlugin = class {
|
|
|
4349
4677
|
}
|
|
4350
4678
|
const doc = new RTFJS.Document(ctx.buffer, {});
|
|
4351
4679
|
const htmlElements = await doc.render();
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
const secH = singleEl.offsetHeight || singleEl.scrollHeight;
|
|
4357
|
-
if (secH > 1300 && children.length > 1) {
|
|
4358
|
-
const childHeights = children.map((c) => {
|
|
4359
|
-
const rectH = c.getBoundingClientRect().height;
|
|
4360
|
-
const offH = c.offsetHeight;
|
|
4361
|
-
const textLen = c.textContent?.trim().length || 0;
|
|
4362
|
-
const estH = Math.max(24, Math.ceil(textLen / 80) * 22 + 16);
|
|
4363
|
-
return Math.max(rectH, offH, estH);
|
|
4364
|
-
});
|
|
4365
|
-
wrapper.innerHTML = "";
|
|
4366
|
-
const createRtfCard = () => {
|
|
4367
|
-
const card = document.createElement("div");
|
|
4368
|
-
card.className = "fp-rtf-page-card";
|
|
4369
|
-
card.style.backgroundColor = "#ffffff";
|
|
4370
|
-
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
4371
|
-
card.style.borderRadius = "4px";
|
|
4372
|
-
card.style.padding = "72px 56px";
|
|
4373
|
-
card.style.width = "816px";
|
|
4374
|
-
card.style.minHeight = "1056px";
|
|
4375
|
-
card.style.boxSizing = "border-box";
|
|
4376
|
-
card.style.marginBottom = "24px";
|
|
4377
|
-
return card;
|
|
4378
|
-
};
|
|
4379
|
-
let curCard = createRtfCard();
|
|
4380
|
-
wrapper.appendChild(curCard);
|
|
4381
|
-
pageElements = [curCard];
|
|
4382
|
-
let curH = 0;
|
|
4383
|
-
const maxH = 920;
|
|
4384
|
-
for (let i = 0; i < children.length; i++) {
|
|
4385
|
-
const child = children[i];
|
|
4386
|
-
const chH = childHeights[i];
|
|
4387
|
-
curCard.appendChild(child);
|
|
4388
|
-
curH += chH;
|
|
4389
|
-
if (curH >= maxH && i < children.length - 1) {
|
|
4390
|
-
curCard = createRtfCard();
|
|
4391
|
-
wrapper.appendChild(curCard);
|
|
4392
|
-
pageElements.push(curCard);
|
|
4393
|
-
curH = 0;
|
|
4394
|
-
}
|
|
4395
|
-
}
|
|
4680
|
+
const contentNodes = [];
|
|
4681
|
+
for (const item of htmlElements) {
|
|
4682
|
+
if (item.children && item.children.length > 0 && !item.tagName.toLowerCase().startsWith("table")) {
|
|
4683
|
+
contentNodes.push(...Array.from(item.children));
|
|
4396
4684
|
} else {
|
|
4397
|
-
|
|
4685
|
+
contentNodes.push(item);
|
|
4398
4686
|
}
|
|
4399
|
-
}
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4687
|
+
}
|
|
4688
|
+
wrapper.innerHTML = "";
|
|
4689
|
+
contentNodes.forEach((node) => wrapper.appendChild(node));
|
|
4690
|
+
const childHeights = contentNodes.map((c) => {
|
|
4691
|
+
const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
|
|
4692
|
+
const offH = c.offsetHeight || 0;
|
|
4693
|
+
const textLen = c.textContent?.trim().length || 0;
|
|
4694
|
+
const estH = Math.max(24, Math.ceil(textLen / 75) * 22 + 14);
|
|
4695
|
+
return Math.max(rectH, offH, estH);
|
|
4696
|
+
});
|
|
4697
|
+
wrapper.innerHTML = "";
|
|
4698
|
+
const createRtfCard = () => {
|
|
4699
|
+
const card = document.createElement("div");
|
|
4700
|
+
card.className = "fp-rtf-page-card";
|
|
4701
|
+
card.style.backgroundColor = "#ffffff";
|
|
4702
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
4703
|
+
card.style.borderRadius = "4px";
|
|
4704
|
+
card.style.padding = "72px 56px";
|
|
4705
|
+
card.style.width = "816px";
|
|
4706
|
+
card.style.minHeight = "1056px";
|
|
4707
|
+
card.style.boxSizing = "border-box";
|
|
4708
|
+
card.style.marginBottom = "24px";
|
|
4709
|
+
card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4710
|
+
card.style.lineHeight = "1.6";
|
|
4711
|
+
return card;
|
|
4712
|
+
};
|
|
4713
|
+
let curCard = createRtfCard();
|
|
4714
|
+
wrapper.appendChild(curCard);
|
|
4715
|
+
pageElements = [curCard];
|
|
4716
|
+
let curH = 0;
|
|
4717
|
+
const maxH = 912;
|
|
4718
|
+
for (let i = 0; i < contentNodes.length; i++) {
|
|
4719
|
+
const child = contentNodes[i];
|
|
4720
|
+
const chH = childHeights[i];
|
|
4721
|
+
curCard.appendChild(child);
|
|
4722
|
+
curH += chH;
|
|
4723
|
+
if (curH >= maxH && i < contentNodes.length - 1) {
|
|
4724
|
+
curCard = createRtfCard();
|
|
4725
|
+
wrapper.appendChild(curCard);
|
|
4726
|
+
pageElements.push(curCard);
|
|
4727
|
+
curH = 0;
|
|
4405
4728
|
}
|
|
4406
4729
|
}
|
|
4407
4730
|
} catch (err) {
|
|
@@ -4770,6 +5093,14 @@ var OpenDocumentPlugin = class {
|
|
|
4770
5093
|
type: "button",
|
|
4771
5094
|
group: "actions",
|
|
4772
5095
|
execute: () => instance.print?.()
|
|
5096
|
+
},
|
|
5097
|
+
{
|
|
5098
|
+
id: "open-window",
|
|
5099
|
+
icon: "open-window",
|
|
5100
|
+
label: "Open in Separate Full Window",
|
|
5101
|
+
type: "button",
|
|
5102
|
+
group: "actions",
|
|
5103
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
4773
5104
|
}
|
|
4774
5105
|
);
|
|
4775
5106
|
return actions;
|
|
@@ -5358,6 +5689,14 @@ var DocPlugin = class {
|
|
|
5358
5689
|
type: "button",
|
|
5359
5690
|
group: "actions",
|
|
5360
5691
|
execute: () => instance.print?.()
|
|
5692
|
+
},
|
|
5693
|
+
{
|
|
5694
|
+
id: "open-window",
|
|
5695
|
+
icon: "open-window",
|
|
5696
|
+
label: "Open in Separate Full Window",
|
|
5697
|
+
type: "button",
|
|
5698
|
+
group: "actions",
|
|
5699
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
5361
5700
|
}
|
|
5362
5701
|
);
|
|
5363
5702
|
return actions;
|
|
@@ -5649,9 +5988,25 @@ var DocPlugin = class {
|
|
|
5649
5988
|
heuristicTextExtraction(buffer) {
|
|
5650
5989
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
5651
5990
|
}
|
|
5991
|
+
cleanWordDocFields(text) {
|
|
5992
|
+
if (!text) return "";
|
|
5993
|
+
let cleaned = text.replace(
|
|
5994
|
+
/\x13\s*HYPERLINK\s*"?([^"\x14]+)"?\s*\x14([\s\S]*?)\x15/gi,
|
|
5995
|
+
(_match, url, label) => {
|
|
5996
|
+
const cleanUrl = url.trim();
|
|
5997
|
+
const cleanLabel = label.trim() || cleanUrl;
|
|
5998
|
+
return `<a href="${cleanUrl}" target="_blank" rel="noopener noreferrer" style="color: #2563eb; text-decoration: underline;">${cleanLabel}</a>`;
|
|
5999
|
+
}
|
|
6000
|
+
);
|
|
6001
|
+
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g, "$1");
|
|
6002
|
+
cleaned = cleaned.replace(/\x13[^\x15]*\x15/g, "");
|
|
6003
|
+
cleaned = cleaned.replace(/[\x13\x14\x15]/g, "");
|
|
6004
|
+
return cleaned;
|
|
6005
|
+
}
|
|
5652
6006
|
splitIntoPages(text) {
|
|
5653
6007
|
if (!text) return [""];
|
|
5654
|
-
const
|
|
6008
|
+
const cleanedText = this.cleanWordDocFields(text);
|
|
6009
|
+
const normalized = cleanedText.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ");
|
|
5655
6010
|
const explicitParts = normalized.split(/[\x0C\f]|\n\s*[-=_]{3,}\s*(?:PAGE|Page|page break)[\s\d\w-]*[-=_]{3,}\s*\n/i).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
5656
6011
|
if (explicitParts.length === 0) explicitParts.push(normalized);
|
|
5657
6012
|
const maxLinesPerPage = 32;
|
|
@@ -5662,7 +6017,8 @@ var DocPlugin = class {
|
|
|
5662
6017
|
let currentLines = [];
|
|
5663
6018
|
let count = 0;
|
|
5664
6019
|
for (const line of lines) {
|
|
5665
|
-
const
|
|
6020
|
+
const plainLine = line.replace(/<[^>]+>/g, "");
|
|
6021
|
+
const vLines = Math.max(1, Math.ceil((plainLine.length || 1) / charsPerLine));
|
|
5666
6022
|
if (count + vLines > maxLinesPerPage && currentLines.length > 0) {
|
|
5667
6023
|
finalPages.push(currentLines.join("\n"));
|
|
5668
6024
|
currentLines = [];
|
|
@@ -5738,25 +6094,26 @@ var DocPlugin = class {
|
|
|
5738
6094
|
i++;
|
|
5739
6095
|
continue;
|
|
5740
6096
|
}
|
|
6097
|
+
const sanitizeOptions = { ADD_TAGS: ["a"], ADD_ATTR: ["href", "target", "rel", "style"] };
|
|
5741
6098
|
if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
|
|
5742
6099
|
if (inList) {
|
|
5743
6100
|
html += "</ul>";
|
|
5744
6101
|
inList = false;
|
|
5745
6102
|
}
|
|
5746
|
-
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>`;
|
|
6103
|
+
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, sanitizeOptions)}</h2>`;
|
|
5747
6104
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
5748
6105
|
if (!inList) {
|
|
5749
6106
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
5750
6107
|
inList = true;
|
|
5751
6108
|
}
|
|
5752
6109
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
5753
|
-
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6.sanitize(bulletText)}</li>`;
|
|
6110
|
+
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6.sanitize(bulletText, sanitizeOptions)}</li>`;
|
|
5754
6111
|
} else {
|
|
5755
6112
|
if (inList) {
|
|
5756
6113
|
html += "</ul>";
|
|
5757
6114
|
inList = false;
|
|
5758
6115
|
}
|
|
5759
|
-
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6.sanitize(line)}</p>`;
|
|
6116
|
+
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6.sanitize(line, sanitizeOptions)}</p>`;
|
|
5760
6117
|
}
|
|
5761
6118
|
i++;
|
|
5762
6119
|
}
|