@files-preview-app/preview-file 1.2.9 → 1.3.1
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 +668 -154
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +667 -154
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +711 -154
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +709 -155
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +668 -154
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +667 -154
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +668 -154
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +667 -154
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
package/dist/angular.cjs
CHANGED
|
@@ -18,6 +18,7 @@ var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
|
|
|
18
18
|
var OrbitControls_js = require('three/examples/jsm/controls/OrbitControls.js');
|
|
19
19
|
var RTFJS = require('rtf.js/dist/RTFJS.bundle.js');
|
|
20
20
|
|
|
21
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
21
22
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
22
23
|
|
|
23
24
|
function _interopNamespace(e) {
|
|
@@ -41,6 +42,7 @@ function _interopNamespace(e) {
|
|
|
41
42
|
var DOMPurify6__default = /*#__PURE__*/_interopDefault(DOMPurify6);
|
|
42
43
|
var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
|
|
43
44
|
var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
45
|
+
var fflate__namespace = /*#__PURE__*/_interopNamespace(fflate);
|
|
44
46
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
45
47
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
46
48
|
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
@@ -417,16 +419,21 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
417
419
|
metadata.mimeType = source.type || void 0;
|
|
418
420
|
metadata.extension = extractExtension(source.name);
|
|
419
421
|
buffer = await source.arrayBuffer();
|
|
420
|
-
} else if (source instanceof Blob) {
|
|
422
|
+
} else if (source instanceof Blob || source && typeof source.arrayBuffer === "function" && typeof source.size === "number") {
|
|
421
423
|
metadata.size = source.size;
|
|
422
424
|
metadata.mimeType = source.type || void 0;
|
|
425
|
+
if (source.name) {
|
|
426
|
+
metadata.name = source.name;
|
|
427
|
+
metadata.extension = extractExtension(source.name);
|
|
428
|
+
}
|
|
423
429
|
buffer = await source.arrayBuffer();
|
|
424
|
-
} else if (source instanceof ArrayBuffer) {
|
|
430
|
+
} else if (source instanceof ArrayBuffer || Object.prototype.toString.call(source) === "[object ArrayBuffer]" || source && typeof source.byteLength === "number" && typeof source.slice === "function") {
|
|
425
431
|
buffer = source;
|
|
426
|
-
} else if (source instanceof Uint8Array) {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
432
|
+
} else if (source instanceof Uint8Array || ArrayBuffer.isView(source)) {
|
|
433
|
+
const view = source;
|
|
434
|
+
buffer = view.buffer.slice(
|
|
435
|
+
view.byteOffset,
|
|
436
|
+
view.byteOffset + view.byteLength
|
|
430
437
|
);
|
|
431
438
|
} else {
|
|
432
439
|
throw new Error("Unsupported file source type");
|
|
@@ -511,6 +518,45 @@ function createElement(tag, attrs, ...children) {
|
|
|
511
518
|
}
|
|
512
519
|
return el;
|
|
513
520
|
}
|
|
521
|
+
var DB_NAME = "PreviewFileTransferDB";
|
|
522
|
+
var DB_STORE = "transfers";
|
|
523
|
+
function openDB() {
|
|
524
|
+
return new Promise((resolve, reject) => {
|
|
525
|
+
if (typeof indexedDB === "undefined") {
|
|
526
|
+
return reject(new Error("IndexedDB is not available"));
|
|
527
|
+
}
|
|
528
|
+
const req = indexedDB.open(DB_NAME, 1);
|
|
529
|
+
req.onupgradeneeded = () => {
|
|
530
|
+
const db = req.result;
|
|
531
|
+
if (!db.objectStoreNames.contains(DB_STORE)) {
|
|
532
|
+
db.createObjectStore(DB_STORE, { keyPath: "id" });
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
req.onsuccess = () => resolve(req.result);
|
|
536
|
+
req.onerror = () => reject(req.error);
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
async function saveTransferPayload(id, payload) {
|
|
540
|
+
if (typeof window !== "undefined") {
|
|
541
|
+
try {
|
|
542
|
+
window[id] = payload;
|
|
543
|
+
window.__lastTransfer = payload;
|
|
544
|
+
} catch {
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
try {
|
|
548
|
+
const db = await openDB();
|
|
549
|
+
return new Promise((resolve, reject) => {
|
|
550
|
+
const tx = db.transaction(DB_STORE, "readwrite");
|
|
551
|
+
const store = tx.objectStore(DB_STORE);
|
|
552
|
+
store.put({ id, ...payload, timestamp: Date.now() });
|
|
553
|
+
tx.oncomplete = () => resolve();
|
|
554
|
+
tx.onerror = () => reject(tx.error);
|
|
555
|
+
});
|
|
556
|
+
} catch (e) {
|
|
557
|
+
console.warn("[saveTransferPayload] IndexedDB store warning:", e);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
514
560
|
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>`;
|
|
515
561
|
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>`;
|
|
516
562
|
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>`;
|
|
@@ -530,6 +576,7 @@ var ICON_COPY = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" str
|
|
|
530
576
|
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>`;
|
|
531
577
|
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>`;
|
|
532
578
|
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>`;
|
|
579
|
+
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>`;
|
|
533
580
|
var ICON_MAP = {
|
|
534
581
|
"zoom-in": ICON_ZOOM_IN,
|
|
535
582
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -556,7 +603,9 @@ var ICON_MAP = {
|
|
|
556
603
|
"forward-10": ICON_FAST_FORWARD,
|
|
557
604
|
"rewind": ICON_REWIND,
|
|
558
605
|
"replay-10": ICON_REWIND,
|
|
559
|
-
"speed": ICON_SPEED
|
|
606
|
+
"speed": ICON_SPEED,
|
|
607
|
+
"open-window": ICON_EXTERNAL_WINDOW,
|
|
608
|
+
"external-window": ICON_EXTERNAL_WINDOW
|
|
560
609
|
};
|
|
561
610
|
var ToolbarController = class {
|
|
562
611
|
el;
|
|
@@ -699,9 +748,11 @@ var ToolbarController = class {
|
|
|
699
748
|
type: "button",
|
|
700
749
|
"data-action-id": id
|
|
701
750
|
});
|
|
702
|
-
const
|
|
703
|
-
if (
|
|
704
|
-
btn.innerHTML =
|
|
751
|
+
const internalSvg = ICON_MAP[iconHtml] || ICON_MAP[id];
|
|
752
|
+
if (internalSvg) {
|
|
753
|
+
btn.innerHTML = internalSvg;
|
|
754
|
+
} else if (iconHtml && iconHtml.startsWith("<svg")) {
|
|
755
|
+
btn.innerHTML = sanitizeSVG(iconHtml);
|
|
705
756
|
} else {
|
|
706
757
|
btn.textContent = title || id;
|
|
707
758
|
}
|
|
@@ -773,7 +824,7 @@ var ThumbnailPanel = class {
|
|
|
773
824
|
}
|
|
774
825
|
}
|
|
775
826
|
};
|
|
776
|
-
var FilePreviewViewer = class {
|
|
827
|
+
var FilePreviewViewer = class _FilePreviewViewer {
|
|
777
828
|
plugins = [];
|
|
778
829
|
activeInstance = null;
|
|
779
830
|
abortController = null;
|
|
@@ -810,6 +861,7 @@ var FilePreviewViewer = class {
|
|
|
810
861
|
* Preview a file in the given container element.
|
|
811
862
|
*/
|
|
812
863
|
async preview(container, source, options = {}) {
|
|
864
|
+
this.currentOptions = options;
|
|
813
865
|
this.abort();
|
|
814
866
|
this.abortController = new AbortController();
|
|
815
867
|
const { signal } = this.abortController;
|
|
@@ -819,7 +871,10 @@ var FilePreviewViewer = class {
|
|
|
819
871
|
this.showLoading();
|
|
820
872
|
try {
|
|
821
873
|
const { buffer, metadata } = await sourceToArrayBuffer(source, signal);
|
|
822
|
-
|
|
874
|
+
if (options.metadata) {
|
|
875
|
+
Object.assign(metadata, options.metadata);
|
|
876
|
+
}
|
|
877
|
+
this.currentBuffer = buffer.slice(0);
|
|
823
878
|
this.currentMetadata = metadata;
|
|
824
879
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
825
880
|
const fileInfo = { metadata, buffer };
|
|
@@ -849,6 +904,7 @@ var FilePreviewViewer = class {
|
|
|
849
904
|
}
|
|
850
905
|
});
|
|
851
906
|
this.activeInstance = instance;
|
|
907
|
+
instance.openInSeparateWindow = () => this.openInSeparateWindow();
|
|
852
908
|
this.hideLoading();
|
|
853
909
|
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
854
910
|
if (options.showToolbar !== false && this.toolbar) {
|
|
@@ -858,26 +914,16 @@ var FilePreviewViewer = class {
|
|
|
858
914
|
actions.push({
|
|
859
915
|
id: "fullscreen",
|
|
860
916
|
icon: "fullscreen",
|
|
861
|
-
label: "
|
|
917
|
+
label: "Fullscreen",
|
|
862
918
|
type: "button",
|
|
863
919
|
group: "view",
|
|
864
|
-
execute:
|
|
920
|
+
execute: () => {
|
|
865
921
|
try {
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
if (this.wrapperEl?.requestFullscreen) {
|
|
870
|
-
await this.wrapperEl.requestFullscreen().catch(() => {
|
|
871
|
-
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
872
|
-
});
|
|
873
|
-
} else {
|
|
874
|
-
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
875
|
-
}
|
|
922
|
+
if (!document.fullscreenElement) {
|
|
923
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
924
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
876
925
|
} else {
|
|
877
|
-
|
|
878
|
-
await document.exitFullscreen().catch(() => {
|
|
879
|
-
});
|
|
880
|
-
}
|
|
926
|
+
document.exitFullscreen?.();
|
|
881
927
|
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
882
928
|
}
|
|
883
929
|
} catch {
|
|
@@ -889,6 +935,28 @@ var FilePreviewViewer = class {
|
|
|
889
935
|
}
|
|
890
936
|
});
|
|
891
937
|
}
|
|
938
|
+
const openWinAction = actions.find((a) => a.id === "open-window");
|
|
939
|
+
if (openWinAction) {
|
|
940
|
+
if (options?._isSeparateWindow) {
|
|
941
|
+
const idx = actions.indexOf(openWinAction);
|
|
942
|
+
if (idx !== -1) actions.splice(idx, 1);
|
|
943
|
+
} else {
|
|
944
|
+
openWinAction.execute = () => {
|
|
945
|
+
this.openInSeparateWindow();
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
} else if (!options?._isSeparateWindow) {
|
|
949
|
+
actions.push({
|
|
950
|
+
id: "open-window",
|
|
951
|
+
icon: "open-window",
|
|
952
|
+
label: "Open in Separate Full Window",
|
|
953
|
+
type: "button",
|
|
954
|
+
group: "actions",
|
|
955
|
+
execute: () => {
|
|
956
|
+
this.openInSeparateWindow();
|
|
957
|
+
}
|
|
958
|
+
});
|
|
959
|
+
}
|
|
892
960
|
this.toolbar.update(actions);
|
|
893
961
|
this.toolbar.show();
|
|
894
962
|
}
|
|
@@ -921,6 +989,104 @@ var FilePreviewViewer = class {
|
|
|
921
989
|
throw error;
|
|
922
990
|
}
|
|
923
991
|
}
|
|
992
|
+
/**
|
|
993
|
+
* Opens the current file preview in a separate full browser window.
|
|
994
|
+
*/
|
|
995
|
+
openInSeparateWindow() {
|
|
996
|
+
if (!this.currentBuffer) {
|
|
997
|
+
console.warn("[FilePreviewViewer] No active file buffer to open in separate window");
|
|
998
|
+
return null;
|
|
999
|
+
}
|
|
1000
|
+
if (this.currentOptions.onOpenSeparateWindow) {
|
|
1001
|
+
return this.currentOptions.onOpenSeparateWindow({
|
|
1002
|
+
buffer: this.currentBuffer,
|
|
1003
|
+
metadata: this.currentMetadata || { name: "Document" },
|
|
1004
|
+
options: this.currentOptions
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
const transferId = "fp_win_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8);
|
|
1008
|
+
let clonedBuffer;
|
|
1009
|
+
try {
|
|
1010
|
+
clonedBuffer = this.currentBuffer.slice(0);
|
|
1011
|
+
} catch {
|
|
1012
|
+
clonedBuffer = this.currentBuffer;
|
|
1013
|
+
}
|
|
1014
|
+
const payload = {
|
|
1015
|
+
buffer: clonedBuffer,
|
|
1016
|
+
metadata: this.currentMetadata ? { ...this.currentMetadata } : void 0,
|
|
1017
|
+
options: { ...this.currentOptions, _isSeparateWindow: true }
|
|
1018
|
+
};
|
|
1019
|
+
if (typeof window !== "undefined") {
|
|
1020
|
+
try {
|
|
1021
|
+
window[transferId] = payload;
|
|
1022
|
+
window.__lastTransfer = payload;
|
|
1023
|
+
} catch {
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
saveTransferPayload(transferId, payload).catch((err) => {
|
|
1027
|
+
console.warn("[FilePreviewViewer] Transfer payload save warning:", err);
|
|
1028
|
+
});
|
|
1029
|
+
let targetUrl = null;
|
|
1030
|
+
if (this.currentOptions.standaloneViewerUrl) {
|
|
1031
|
+
const u = new URL(this.currentOptions.standaloneViewerUrl, window.location.href);
|
|
1032
|
+
u.searchParams.set("mode", "fullscreen");
|
|
1033
|
+
u.searchParams.set("transferId", transferId);
|
|
1034
|
+
targetUrl = u.toString();
|
|
1035
|
+
} else if (typeof window !== "undefined" && window.location?.href && !window.location.href.startsWith("about:")) {
|
|
1036
|
+
const u = new URL(window.location.href);
|
|
1037
|
+
u.searchParams.set("mode", "fullscreen");
|
|
1038
|
+
u.searchParams.set("transferId", transferId);
|
|
1039
|
+
targetUrl = u.toString();
|
|
1040
|
+
}
|
|
1041
|
+
if (targetUrl) {
|
|
1042
|
+
const newWin2 = window.open(targetUrl, "_blank");
|
|
1043
|
+
if (!newWin2) {
|
|
1044
|
+
alert("Popup blocker prevented opening the preview in a separate window. Please allow popups for this site.");
|
|
1045
|
+
return null;
|
|
1046
|
+
}
|
|
1047
|
+
return newWin2;
|
|
1048
|
+
}
|
|
1049
|
+
const title = (this.currentMetadata?.name || "Document Preview") + " - Full Preview";
|
|
1050
|
+
const newWin = window.open("", "_blank");
|
|
1051
|
+
if (!newWin) {
|
|
1052
|
+
alert("Popup blocker prevented opening the preview in a separate window. Please allow popups for this site.");
|
|
1053
|
+
return null;
|
|
1054
|
+
}
|
|
1055
|
+
newWin.document.title = title;
|
|
1056
|
+
newWin.document.body.style.margin = "0";
|
|
1057
|
+
newWin.document.body.style.padding = "0";
|
|
1058
|
+
newWin.document.body.style.width = "100vw";
|
|
1059
|
+
newWin.document.body.style.height = "100vh";
|
|
1060
|
+
newWin.document.body.style.overflow = "hidden";
|
|
1061
|
+
newWin.document.body.style.backgroundColor = "#f8fafc";
|
|
1062
|
+
const headNodes = document.querySelectorAll('link[rel="stylesheet"], style');
|
|
1063
|
+
headNodes.forEach((node) => {
|
|
1064
|
+
newWin.document.head.appendChild(node.cloneNode(true));
|
|
1065
|
+
});
|
|
1066
|
+
const root = newWin.document.createElement("div");
|
|
1067
|
+
root.id = "full-window-preview-root";
|
|
1068
|
+
root.style.width = "100%";
|
|
1069
|
+
root.style.height = "100%";
|
|
1070
|
+
root.style.overflow = "hidden";
|
|
1071
|
+
newWin.document.body.appendChild(root);
|
|
1072
|
+
const separateViewer = new _FilePreviewViewer();
|
|
1073
|
+
for (const plugin of this.plugins) {
|
|
1074
|
+
separateViewer.registerPlugin(plugin);
|
|
1075
|
+
}
|
|
1076
|
+
separateViewer.preview(root, this.currentBuffer.slice(0), {
|
|
1077
|
+
...this.currentOptions,
|
|
1078
|
+
showToolbar: true,
|
|
1079
|
+
toolbarPosition: "top",
|
|
1080
|
+
metadata: this.currentMetadata || void 0,
|
|
1081
|
+
_isSeparateWindow: true
|
|
1082
|
+
}).catch((err) => {
|
|
1083
|
+
console.error("[FilePreviewViewer] Error rendering in separate window:", err);
|
|
1084
|
+
});
|
|
1085
|
+
newWin.addEventListener("beforeunload", () => {
|
|
1086
|
+
separateViewer.destroy();
|
|
1087
|
+
});
|
|
1088
|
+
return newWin;
|
|
1089
|
+
}
|
|
924
1090
|
/**
|
|
925
1091
|
* Subscribe to viewer events.
|
|
926
1092
|
*/
|
|
@@ -1326,8 +1492,20 @@ var CfbfReader = class {
|
|
|
1326
1492
|
}
|
|
1327
1493
|
};
|
|
1328
1494
|
if (typeof window !== "undefined" && pdfjsLib__namespace.GlobalWorkerOptions) {
|
|
1329
|
-
if (!pdfjsLib__namespace.GlobalWorkerOptions.workerSrc) {
|
|
1330
|
-
|
|
1495
|
+
if (!pdfjsLib__namespace.GlobalWorkerOptions.workerPort && !pdfjsLib__namespace.GlobalWorkerOptions.workerSrc) {
|
|
1496
|
+
const customWorker = window.__PDF_WORKER_SRC__;
|
|
1497
|
+
if (customWorker) {
|
|
1498
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = customWorker;
|
|
1499
|
+
} else {
|
|
1500
|
+
try {
|
|
1501
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerPort = new Worker(
|
|
1502
|
+
new URL("pdfjs-dist/build/pdf.worker.min.mjs", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('angular.cjs', document.baseURI).href))),
|
|
1503
|
+
{ type: "module" }
|
|
1504
|
+
);
|
|
1505
|
+
} catch {
|
|
1506
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = "./pdf.worker.min.mjs";
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1331
1509
|
}
|
|
1332
1510
|
}
|
|
1333
1511
|
var PdfPlugin = class {
|
|
@@ -1421,6 +1599,14 @@ var PdfPlugin = class {
|
|
|
1421
1599
|
type: "button",
|
|
1422
1600
|
group: "actions",
|
|
1423
1601
|
execute: () => instance.print?.()
|
|
1602
|
+
},
|
|
1603
|
+
{
|
|
1604
|
+
id: "open-window",
|
|
1605
|
+
icon: "open-window",
|
|
1606
|
+
label: "Open in Separate Full Window",
|
|
1607
|
+
type: "button",
|
|
1608
|
+
group: "actions",
|
|
1609
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
1424
1610
|
}
|
|
1425
1611
|
];
|
|
1426
1612
|
}
|
|
@@ -1470,18 +1656,21 @@ var PdfPlugin = class {
|
|
|
1470
1656
|
indicator.style.pointerEvents = "none";
|
|
1471
1657
|
container.appendChild(indicator);
|
|
1472
1658
|
ctx.container.appendChild(container);
|
|
1659
|
+
const standardFontsUrl = typeof window !== "undefined" && window.__PDF_STANDARD_FONTS_URL__ || "./standard_fonts/";
|
|
1660
|
+
const cmapsUrl = typeof window !== "undefined" && window.__PDF_CMAPS_URL__ || "./cmaps/";
|
|
1473
1661
|
const loadingTask = pdfjsLib__namespace.getDocument({
|
|
1474
|
-
data: new Uint8Array(ctx.buffer),
|
|
1475
|
-
cMapUrl:
|
|
1662
|
+
data: new Uint8Array(ctx.buffer.slice(0)),
|
|
1663
|
+
cMapUrl: cmapsUrl,
|
|
1476
1664
|
cMapPacked: true,
|
|
1477
|
-
standardFontDataUrl:
|
|
1665
|
+
standardFontDataUrl: standardFontsUrl,
|
|
1666
|
+
verbosity: 0
|
|
1478
1667
|
});
|
|
1479
1668
|
const pdfDoc = await loadingTask.promise;
|
|
1480
1669
|
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1481
1670
|
let currentPage = 1;
|
|
1482
1671
|
let zoomScale = 1;
|
|
1483
1672
|
let rotation = 0;
|
|
1484
|
-
let fitMode = "
|
|
1673
|
+
let fitMode = "page";
|
|
1485
1674
|
let currentRenderTask = null;
|
|
1486
1675
|
const renderPage = async (pageNum) => {
|
|
1487
1676
|
if (currentRenderTask) {
|
|
@@ -1501,15 +1690,15 @@ var PdfPlugin = class {
|
|
|
1501
1690
|
const containerWidth = container.clientWidth || 900;
|
|
1502
1691
|
const containerHeight = container.clientHeight || 700;
|
|
1503
1692
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1504
|
-
const availWidth = Math.max(
|
|
1505
|
-
const availHeight = Math.max(
|
|
1693
|
+
const availWidth = Math.max(320, containerWidth - 48);
|
|
1694
|
+
const availHeight = Math.max(550, containerHeight - 88);
|
|
1506
1695
|
const scaleW = availWidth / unscaledVp.width;
|
|
1507
1696
|
const scaleH = availHeight / unscaledVp.height;
|
|
1508
1697
|
let fitScale;
|
|
1509
1698
|
if (fitMode === "page") {
|
|
1510
|
-
fitScale = Math.max(0.
|
|
1699
|
+
fitScale = Math.max(0.4, Math.min(scaleW, scaleH));
|
|
1511
1700
|
} else {
|
|
1512
|
-
fitScale = Math.max(0.65, Math.min(1.
|
|
1701
|
+
fitScale = Math.max(0.65, Math.min(1.25, scaleW));
|
|
1513
1702
|
}
|
|
1514
1703
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1515
1704
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
@@ -1535,7 +1724,7 @@ var PdfPlugin = class {
|
|
|
1535
1724
|
currentRenderTask = null;
|
|
1536
1725
|
}
|
|
1537
1726
|
};
|
|
1538
|
-
|
|
1727
|
+
renderPage(1);
|
|
1539
1728
|
let resizeTimer = null;
|
|
1540
1729
|
const resizeObserver = new ResizeObserver(() => {
|
|
1541
1730
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
@@ -1579,7 +1768,7 @@ var PdfPlugin = class {
|
|
|
1579
1768
|
renderPage(currentPage);
|
|
1580
1769
|
},
|
|
1581
1770
|
fitToPage: () => {
|
|
1582
|
-
fitMode = fitMode === "
|
|
1771
|
+
fitMode = fitMode === "page" ? "width" : "page";
|
|
1583
1772
|
zoomScale = 1;
|
|
1584
1773
|
rotation = 0;
|
|
1585
1774
|
renderPage(currentPage);
|
|
@@ -2056,6 +2245,14 @@ var DocxPlugin = class {
|
|
|
2056
2245
|
type: "button",
|
|
2057
2246
|
group: "actions",
|
|
2058
2247
|
execute: () => instance.print?.()
|
|
2248
|
+
},
|
|
2249
|
+
{
|
|
2250
|
+
id: "open-window",
|
|
2251
|
+
icon: "open-window",
|
|
2252
|
+
label: "Open in Separate Full Window",
|
|
2253
|
+
type: "button",
|
|
2254
|
+
group: "actions",
|
|
2255
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
2059
2256
|
}
|
|
2060
2257
|
);
|
|
2061
2258
|
return actions;
|
|
@@ -2115,6 +2312,31 @@ var DocxPlugin = class {
|
|
|
2115
2312
|
}
|
|
2116
2313
|
if (wrapper.children.length > 0 && (wrapper.textContent?.trim().length ?? 0) > 0) {
|
|
2117
2314
|
renderedSuccessfully = true;
|
|
2315
|
+
try {
|
|
2316
|
+
const unzipped = fflate.unzipSync(new Uint8Array(ctx.buffer));
|
|
2317
|
+
const chartKeys = Object.keys(unzipped).filter((k) => k.replace(/^[./\\]+/, "").toLowerCase().startsWith("word/charts/chart") && k.endsWith(".xml")).sort();
|
|
2318
|
+
if (chartKeys.length > 0) {
|
|
2319
|
+
const allDivs = Array.from(wrapper.querySelectorAll("div"));
|
|
2320
|
+
const emptyContainers = allDivs.filter((div) => {
|
|
2321
|
+
const st = div.getAttribute("style") || "";
|
|
2322
|
+
return st.includes("width:") && st.includes("height:") && div.children.length === 0 && (div.textContent?.trim().length ?? 0) === 0;
|
|
2323
|
+
});
|
|
2324
|
+
chartKeys.forEach((cKey, idx) => {
|
|
2325
|
+
const target = emptyContainers[idx];
|
|
2326
|
+
if (target) {
|
|
2327
|
+
const xmlStr = fflate.strFromU8(unzipped[cKey]);
|
|
2328
|
+
const svg = this.parseAndRenderChartSvg(xmlStr);
|
|
2329
|
+
if (svg) {
|
|
2330
|
+
target.innerHTML = svg;
|
|
2331
|
+
target.style.display = "block";
|
|
2332
|
+
target.style.margin = "12px auto";
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
});
|
|
2336
|
+
}
|
|
2337
|
+
} catch (chartErr) {
|
|
2338
|
+
console.warn("[DocxPlugin] Non-critical error rendering DrawingML charts:", chartErr);
|
|
2339
|
+
}
|
|
2118
2340
|
}
|
|
2119
2341
|
} catch (err) {
|
|
2120
2342
|
console.warn("[DocxPlugin] docx-preview failed, triggering native fallback:", err);
|
|
@@ -2146,64 +2368,74 @@ var DocxPlugin = class {
|
|
|
2146
2368
|
}
|
|
2147
2369
|
let sections = Array.from(wrapper.querySelectorAll("section.docx"));
|
|
2148
2370
|
const cards = Array.from(wrapper.querySelectorAll(".fp-docx-page-card"));
|
|
2149
|
-
if (sections.length
|
|
2150
|
-
const
|
|
2151
|
-
const
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
const
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
nextSec.
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
nextArticle
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
nextSec.appendChild(
|
|
2371
|
+
if (sections.length > 0 && cards.length === 0) {
|
|
2372
|
+
const finalSections = [];
|
|
2373
|
+
for (const singleSec of sections) {
|
|
2374
|
+
const contentContainer = singleSec.querySelector("article") || singleSec;
|
|
2375
|
+
const children = Array.from(contentContainer.children);
|
|
2376
|
+
const pageH = singleSec.offsetHeight > 1300 ? 1122 : Math.max(1056, singleSec.offsetHeight);
|
|
2377
|
+
const secH = singleSec.scrollHeight || singleSec.offsetHeight;
|
|
2378
|
+
if (secH > pageH * 1.25 && children.length > 1) {
|
|
2379
|
+
const childHeights = children.map((c) => {
|
|
2380
|
+
const rectH = c.getBoundingClientRect().height;
|
|
2381
|
+
const offH = c.offsetHeight;
|
|
2382
|
+
const textLen = c.textContent?.trim().length || 0;
|
|
2383
|
+
const estH = Math.max(24, Math.ceil(textLen / 80) * 22 + 16);
|
|
2384
|
+
return Math.max(rectH, offH, estH);
|
|
2385
|
+
});
|
|
2386
|
+
const parent = singleSec.parentElement || wrapper;
|
|
2387
|
+
const headerEl = singleSec.querySelector("header");
|
|
2388
|
+
const footerEl = singleSec.querySelector("footer");
|
|
2389
|
+
contentContainer.innerHTML = "";
|
|
2390
|
+
singleSec.style.minHeight = `${pageH}px`;
|
|
2391
|
+
singleSec.style.boxSizing = "border-box";
|
|
2392
|
+
let curContent = contentContainer;
|
|
2393
|
+
let curSec = singleSec;
|
|
2394
|
+
let curH = 0;
|
|
2395
|
+
const maxH = pageH - 140;
|
|
2396
|
+
finalSections.push(singleSec);
|
|
2397
|
+
for (let i = 0; i < children.length; i++) {
|
|
2398
|
+
const child = children[i];
|
|
2399
|
+
const chH = childHeights[i];
|
|
2400
|
+
curContent.appendChild(child);
|
|
2401
|
+
curH += chH;
|
|
2402
|
+
if (curH >= maxH && i < children.length - 1) {
|
|
2403
|
+
const nextSec = document.createElement("section");
|
|
2404
|
+
nextSec.className = singleSec.className;
|
|
2405
|
+
nextSec.style.cssText = singleSec.style.cssText;
|
|
2406
|
+
nextSec.style.minHeight = `${pageH}px`;
|
|
2407
|
+
nextSec.style.boxSizing = "border-box";
|
|
2408
|
+
nextSec.style.backgroundColor = "#ffffff";
|
|
2409
|
+
nextSec.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
2410
|
+
nextSec.style.borderRadius = "4px";
|
|
2411
|
+
nextSec.style.marginBottom = "24px";
|
|
2412
|
+
if (headerEl) {
|
|
2413
|
+
nextSec.appendChild(headerEl.cloneNode(true));
|
|
2414
|
+
}
|
|
2415
|
+
const nextArticle = document.createElement("article");
|
|
2416
|
+
if (contentContainer.tagName.toLowerCase() === "article") {
|
|
2417
|
+
nextArticle.style.cssText = contentContainer.style.cssText;
|
|
2418
|
+
}
|
|
2419
|
+
nextSec.appendChild(nextArticle);
|
|
2420
|
+
if (footerEl) {
|
|
2421
|
+
nextSec.appendChild(footerEl.cloneNode(true));
|
|
2422
|
+
}
|
|
2423
|
+
if (curSec.nextSibling) {
|
|
2424
|
+
parent.insertBefore(nextSec, curSec.nextSibling);
|
|
2425
|
+
} else {
|
|
2426
|
+
parent.appendChild(nextSec);
|
|
2427
|
+
}
|
|
2428
|
+
finalSections.push(nextSec);
|
|
2429
|
+
curSec = nextSec;
|
|
2430
|
+
curContent = nextArticle;
|
|
2431
|
+
curH = 0;
|
|
2198
2432
|
}
|
|
2199
|
-
parent.appendChild(nextSec);
|
|
2200
|
-
newSections.push(nextSec);
|
|
2201
|
-
curContent = nextArticle;
|
|
2202
|
-
curH = 0;
|
|
2203
2433
|
}
|
|
2434
|
+
} else {
|
|
2435
|
+
finalSections.push(singleSec);
|
|
2204
2436
|
}
|
|
2205
|
-
sections = newSections;
|
|
2206
2437
|
}
|
|
2438
|
+
sections = finalSections;
|
|
2207
2439
|
}
|
|
2208
2440
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2209
2441
|
const totalPages = Math.max(1, pageElements.length);
|
|
@@ -2595,6 +2827,88 @@ var DocxPlugin = class {
|
|
|
2595
2827
|
}
|
|
2596
2828
|
return result;
|
|
2597
2829
|
}
|
|
2830
|
+
parseAndRenderChartSvg(xmlStr, width = 500, height = 260) {
|
|
2831
|
+
const catMatches = [...xmlStr.matchAll(/<c:cat>[\s\S]*?<c:strCache>([\s\S]*?)<\/c:strCache>/g)];
|
|
2832
|
+
let categories = [];
|
|
2833
|
+
if (catMatches.length > 0) {
|
|
2834
|
+
categories = [...catMatches[0][1].matchAll(/<c:v>([^<]+)<\/c:v>/g)].map((m) => m[1]);
|
|
2835
|
+
}
|
|
2836
|
+
if (categories.length === 0) {
|
|
2837
|
+
categories = ["Category 1", "Category 2", "Category 3", "Category 4"];
|
|
2838
|
+
}
|
|
2839
|
+
const defaultColors = ["#004586", "#ff420e", "#ffd320", "#579d1c", "#7e0021", "#83caff"];
|
|
2840
|
+
const sers = [...xmlStr.matchAll(/<c:ser>([\s\S]*?)<\/c:ser>/g)];
|
|
2841
|
+
const series = [];
|
|
2842
|
+
sers.forEach((s, sIdx) => {
|
|
2843
|
+
const titleMatch = s[1].match(/<c:tx>[\s\S]*?<c:v>([^<]+)<\/c:v>/);
|
|
2844
|
+
const title = titleMatch ? titleMatch[1] : `Series ${sIdx + 1}`;
|
|
2845
|
+
const clrMatch = s[1].match(/<a:srgbClr\s+val="([^"]+)"/);
|
|
2846
|
+
const color = clrMatch ? "#" + clrMatch[1] : defaultColors[sIdx % defaultColors.length];
|
|
2847
|
+
const valMatch = s[1].match(/<c:val>[\s\S]*?<c:numCache>([\s\S]*?)<\/c:numCache>/);
|
|
2848
|
+
let values = [];
|
|
2849
|
+
if (valMatch) {
|
|
2850
|
+
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);
|
|
2851
|
+
}
|
|
2852
|
+
series.push({ title, color, values });
|
|
2853
|
+
});
|
|
2854
|
+
if (series.length === 0) return "";
|
|
2855
|
+
let maxVal = 10;
|
|
2856
|
+
series.forEach((s) => s.values.forEach((v) => {
|
|
2857
|
+
if (v > maxVal) maxVal = v;
|
|
2858
|
+
}));
|
|
2859
|
+
maxVal = Math.ceil(maxVal * 1.15);
|
|
2860
|
+
if (maxVal % 2 !== 0) maxVal++;
|
|
2861
|
+
const padLeft = 45;
|
|
2862
|
+
const padBottom = 55;
|
|
2863
|
+
const padTop = 20;
|
|
2864
|
+
const padRight = 20;
|
|
2865
|
+
const plotW = width - padLeft - padRight;
|
|
2866
|
+
const plotH = height - padTop - padBottom;
|
|
2867
|
+
const yTicks = 5;
|
|
2868
|
+
let gridLines = "";
|
|
2869
|
+
for (let i = 0; i <= yTicks; i++) {
|
|
2870
|
+
const val = maxVal / yTicks * i;
|
|
2871
|
+
const y = padTop + plotH - val / maxVal * plotH;
|
|
2872
|
+
gridLines += `<line x1="${padLeft}" y1="${y}" x2="${padLeft + plotW}" y2="${y}" stroke="#e2e8f0" stroke-width="1" />`;
|
|
2873
|
+
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>`;
|
|
2874
|
+
}
|
|
2875
|
+
const numCats = categories.length;
|
|
2876
|
+
const numSers = series.length;
|
|
2877
|
+
const groupW = plotW / numCats;
|
|
2878
|
+
const barW = Math.max(8, Math.min(28, groupW * 0.7 / numSers));
|
|
2879
|
+
const groupPad = (groupW - barW * numSers) / 2;
|
|
2880
|
+
let bars = "";
|
|
2881
|
+
let catLabels = "";
|
|
2882
|
+
for (let c = 0; c < numCats; c++) {
|
|
2883
|
+
const catX = padLeft + c * groupW;
|
|
2884
|
+
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>`;
|
|
2885
|
+
for (let s = 0; s < numSers; s++) {
|
|
2886
|
+
const val = series[s].values[c] ?? 0;
|
|
2887
|
+
const bH = Math.max(0, val / maxVal * plotH);
|
|
2888
|
+
const bX = catX + groupPad + s * barW;
|
|
2889
|
+
const bY = padTop + plotH - bH;
|
|
2890
|
+
bars += `<rect x="${bX}" y="${bY}" width="${barW - 2}" height="${bH}" fill="${series[s].color}" rx="1" />`;
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
let legend = "";
|
|
2894
|
+
const legY = height - 12;
|
|
2895
|
+
let legX = padLeft + (plotW - numSers * 100) / 2;
|
|
2896
|
+
series.forEach((s) => {
|
|
2897
|
+
legend += `<rect x="${legX}" y="${legY - 9}" width="10" height="10" fill="${s.color}" rx="2" />`;
|
|
2898
|
+
legend += `<text x="${legX + 15}" y="${legY}" font-size="11" fill="#475569" font-family="Calibri, sans-serif">${s.title}</text>`;
|
|
2899
|
+
legX += 95;
|
|
2900
|
+
});
|
|
2901
|
+
return `
|
|
2902
|
+
<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">
|
|
2903
|
+
${gridLines}
|
|
2904
|
+
<line x1="${padLeft}" y1="${padTop + plotH}" x2="${padLeft + plotW}" y2="${padTop + plotH}" stroke="#94a3b8" stroke-width="1.5" />
|
|
2905
|
+
<line x1="${padLeft}" y1="${padTop}" x2="${padLeft}" y2="${padTop + plotH}" stroke="#94a3b8" stroke-width="1.5" />
|
|
2906
|
+
${bars}
|
|
2907
|
+
${catLabels}
|
|
2908
|
+
${legend}
|
|
2909
|
+
</svg>
|
|
2910
|
+
`.trim();
|
|
2911
|
+
}
|
|
2598
2912
|
};
|
|
2599
2913
|
function docxPlugin() {
|
|
2600
2914
|
return new DocxPlugin();
|
|
@@ -3161,6 +3475,16 @@ var CodePlugin = class {
|
|
|
3161
3475
|
execute: () => {
|
|
3162
3476
|
instance.print?.();
|
|
3163
3477
|
}
|
|
3478
|
+
},
|
|
3479
|
+
{
|
|
3480
|
+
id: "open-window",
|
|
3481
|
+
icon: "open-window",
|
|
3482
|
+
label: "Open in Separate Full Window",
|
|
3483
|
+
type: "button",
|
|
3484
|
+
group: "actions",
|
|
3485
|
+
execute: () => {
|
|
3486
|
+
instance.openInSeparateWindow?.();
|
|
3487
|
+
}
|
|
3164
3488
|
}
|
|
3165
3489
|
);
|
|
3166
3490
|
return actions;
|
|
@@ -4329,6 +4653,14 @@ var RtfPlugin = class {
|
|
|
4329
4653
|
type: "button",
|
|
4330
4654
|
group: "actions",
|
|
4331
4655
|
execute: () => instance.print?.()
|
|
4656
|
+
},
|
|
4657
|
+
{
|
|
4658
|
+
id: "open-window",
|
|
4659
|
+
icon: "open-window",
|
|
4660
|
+
label: "Open in Separate Full Window",
|
|
4661
|
+
type: "button",
|
|
4662
|
+
group: "actions",
|
|
4663
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
4332
4664
|
}
|
|
4333
4665
|
);
|
|
4334
4666
|
return actions;
|
|
@@ -4381,59 +4713,54 @@ var RtfPlugin = class {
|
|
|
4381
4713
|
}
|
|
4382
4714
|
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
4383
4715
|
const htmlElements = await doc.render();
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
const secH = singleEl.offsetHeight || singleEl.scrollHeight;
|
|
4389
|
-
if (secH > 1300 && children.length > 1) {
|
|
4390
|
-
const childHeights = children.map((c) => {
|
|
4391
|
-
const rectH = c.getBoundingClientRect().height;
|
|
4392
|
-
const offH = c.offsetHeight;
|
|
4393
|
-
const textLen = c.textContent?.trim().length || 0;
|
|
4394
|
-
const estH = Math.max(24, Math.ceil(textLen / 80) * 22 + 16);
|
|
4395
|
-
return Math.max(rectH, offH, estH);
|
|
4396
|
-
});
|
|
4397
|
-
wrapper.innerHTML = "";
|
|
4398
|
-
const createRtfCard = () => {
|
|
4399
|
-
const card = document.createElement("div");
|
|
4400
|
-
card.className = "fp-rtf-page-card";
|
|
4401
|
-
card.style.backgroundColor = "#ffffff";
|
|
4402
|
-
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
4403
|
-
card.style.borderRadius = "4px";
|
|
4404
|
-
card.style.padding = "72px 56px";
|
|
4405
|
-
card.style.width = "816px";
|
|
4406
|
-
card.style.minHeight = "1056px";
|
|
4407
|
-
card.style.boxSizing = "border-box";
|
|
4408
|
-
card.style.marginBottom = "24px";
|
|
4409
|
-
return card;
|
|
4410
|
-
};
|
|
4411
|
-
let curCard = createRtfCard();
|
|
4412
|
-
wrapper.appendChild(curCard);
|
|
4413
|
-
pageElements = [curCard];
|
|
4414
|
-
let curH = 0;
|
|
4415
|
-
const maxH = 920;
|
|
4416
|
-
for (let i = 0; i < children.length; i++) {
|
|
4417
|
-
const child = children[i];
|
|
4418
|
-
const chH = childHeights[i];
|
|
4419
|
-
curCard.appendChild(child);
|
|
4420
|
-
curH += chH;
|
|
4421
|
-
if (curH >= maxH && i < children.length - 1) {
|
|
4422
|
-
curCard = createRtfCard();
|
|
4423
|
-
wrapper.appendChild(curCard);
|
|
4424
|
-
pageElements.push(curCard);
|
|
4425
|
-
curH = 0;
|
|
4426
|
-
}
|
|
4427
|
-
}
|
|
4716
|
+
const contentNodes = [];
|
|
4717
|
+
for (const item of htmlElements) {
|
|
4718
|
+
if (item.children && item.children.length > 0 && !item.tagName.toLowerCase().startsWith("table")) {
|
|
4719
|
+
contentNodes.push(...Array.from(item.children));
|
|
4428
4720
|
} else {
|
|
4429
|
-
|
|
4721
|
+
contentNodes.push(item);
|
|
4430
4722
|
}
|
|
4431
|
-
}
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4723
|
+
}
|
|
4724
|
+
wrapper.innerHTML = "";
|
|
4725
|
+
contentNodes.forEach((node) => wrapper.appendChild(node));
|
|
4726
|
+
const childHeights = contentNodes.map((c) => {
|
|
4727
|
+
const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
|
|
4728
|
+
const offH = c.offsetHeight || 0;
|
|
4729
|
+
const textLen = c.textContent?.trim().length || 0;
|
|
4730
|
+
const estH = Math.max(24, Math.ceil(textLen / 75) * 22 + 14);
|
|
4731
|
+
return Math.max(rectH, offH, estH);
|
|
4732
|
+
});
|
|
4733
|
+
wrapper.innerHTML = "";
|
|
4734
|
+
const createRtfCard = () => {
|
|
4735
|
+
const card = document.createElement("div");
|
|
4736
|
+
card.className = "fp-rtf-page-card";
|
|
4737
|
+
card.style.backgroundColor = "#ffffff";
|
|
4738
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
4739
|
+
card.style.borderRadius = "4px";
|
|
4740
|
+
card.style.padding = "72px 56px";
|
|
4741
|
+
card.style.width = "816px";
|
|
4742
|
+
card.style.minHeight = "1056px";
|
|
4743
|
+
card.style.boxSizing = "border-box";
|
|
4744
|
+
card.style.marginBottom = "24px";
|
|
4745
|
+
card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4746
|
+
card.style.lineHeight = "1.6";
|
|
4747
|
+
return card;
|
|
4748
|
+
};
|
|
4749
|
+
let curCard = createRtfCard();
|
|
4750
|
+
wrapper.appendChild(curCard);
|
|
4751
|
+
pageElements = [curCard];
|
|
4752
|
+
let curH = 0;
|
|
4753
|
+
const maxH = 912;
|
|
4754
|
+
for (let i = 0; i < contentNodes.length; i++) {
|
|
4755
|
+
const child = contentNodes[i];
|
|
4756
|
+
const chH = childHeights[i];
|
|
4757
|
+
curCard.appendChild(child);
|
|
4758
|
+
curH += chH;
|
|
4759
|
+
if (curH >= maxH && i < contentNodes.length - 1) {
|
|
4760
|
+
curCard = createRtfCard();
|
|
4761
|
+
wrapper.appendChild(curCard);
|
|
4762
|
+
pageElements.push(curCard);
|
|
4763
|
+
curH = 0;
|
|
4437
4764
|
}
|
|
4438
4765
|
}
|
|
4439
4766
|
} catch (err) {
|
|
@@ -4802,6 +5129,14 @@ var OpenDocumentPlugin = class {
|
|
|
4802
5129
|
type: "button",
|
|
4803
5130
|
group: "actions",
|
|
4804
5131
|
execute: () => instance.print?.()
|
|
5132
|
+
},
|
|
5133
|
+
{
|
|
5134
|
+
id: "open-window",
|
|
5135
|
+
icon: "open-window",
|
|
5136
|
+
label: "Open in Separate Full Window",
|
|
5137
|
+
type: "button",
|
|
5138
|
+
group: "actions",
|
|
5139
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
4805
5140
|
}
|
|
4806
5141
|
);
|
|
4807
5142
|
return actions;
|
|
@@ -5390,6 +5725,14 @@ var DocPlugin = class {
|
|
|
5390
5725
|
type: "button",
|
|
5391
5726
|
group: "actions",
|
|
5392
5727
|
execute: () => instance.print?.()
|
|
5728
|
+
},
|
|
5729
|
+
{
|
|
5730
|
+
id: "open-window",
|
|
5731
|
+
icon: "open-window",
|
|
5732
|
+
label: "Open in Separate Full Window",
|
|
5733
|
+
type: "button",
|
|
5734
|
+
group: "actions",
|
|
5735
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
5393
5736
|
}
|
|
5394
5737
|
);
|
|
5395
5738
|
return actions;
|
|
@@ -5409,8 +5752,17 @@ var DocPlugin = class {
|
|
|
5409
5752
|
let scale = 1;
|
|
5410
5753
|
let extractedRawText = "";
|
|
5411
5754
|
let isFallback = false;
|
|
5755
|
+
let chartSvg = "";
|
|
5412
5756
|
try {
|
|
5413
5757
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
5758
|
+
try {
|
|
5759
|
+
const pkg = cfbf.readStream("package_stream");
|
|
5760
|
+
if (pkg && pkg.length > 100) {
|
|
5761
|
+
chartSvg = this.parseOdfChartToSvg(pkg);
|
|
5762
|
+
}
|
|
5763
|
+
} catch (chartErr) {
|
|
5764
|
+
console.warn("[DocPlugin] Chart stream parsing info:", chartErr);
|
|
5765
|
+
}
|
|
5414
5766
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
5415
5767
|
if (!wordDocStream || wordDocStream.length < 512) {
|
|
5416
5768
|
throw new Error("WordDocument stream not found or invalid in CFBF archive");
|
|
@@ -5428,7 +5780,7 @@ var DocPlugin = class {
|
|
|
5428
5780
|
extractedRawText = fallback;
|
|
5429
5781
|
isFallback = true;
|
|
5430
5782
|
}
|
|
5431
|
-
const rawPages = this.splitIntoPages(extractedRawText);
|
|
5783
|
+
const rawPages = this.splitIntoPages(extractedRawText, chartSvg);
|
|
5432
5784
|
const totalPages = Math.max(1, rawPages.length);
|
|
5433
5785
|
let currentPage = 1;
|
|
5434
5786
|
const pageCards = [];
|
|
@@ -5670,7 +6022,7 @@ var DocPlugin = class {
|
|
|
5670
6022
|
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
5671
6023
|
const trimmed = run.trim();
|
|
5672
6024
|
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
5673
|
-
if (!trimmed.includes("Normal.dot") && !trimmed.includes("Microsoft Word") && !trimmed.includes("Times New Roman") && !trimmed.startsWith("\xD0\xCF\xE0\xA1\xB1\xE1") && !/^[\W_0-9]+$/.test(trimmed)) {
|
|
6025
|
+
if (!trimmed.includes("Normal.dot") && !trimmed.includes("Microsoft Word") && !trimmed.includes("Times New Roman") && !trimmed.startsWith("\xD0\xCF\xE0\xA1\xB1\xE1") && !/^EMBED\b/i.test(trimmed) && !trimmed.includes("ChartDocument") && !/^[\W_0-9]+$/.test(trimmed)) {
|
|
5674
6026
|
seen.add(trimmed);
|
|
5675
6027
|
candidateLines.push(trimmed);
|
|
5676
6028
|
}
|
|
@@ -5681,12 +6033,138 @@ var DocPlugin = class {
|
|
|
5681
6033
|
heuristicTextExtraction(buffer) {
|
|
5682
6034
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
5683
6035
|
}
|
|
5684
|
-
|
|
6036
|
+
/**
|
|
6037
|
+
* Parses an embedded OpenDocument Chart package into a vector SVG bar/column chart
|
|
6038
|
+
*/
|
|
6039
|
+
parseOdfChartToSvg(zipBytes) {
|
|
6040
|
+
try {
|
|
6041
|
+
const unzipped = fflate__namespace.unzipSync(zipBytes);
|
|
6042
|
+
const contentXml = unzipped["content.xml"] ? new TextDecoder("utf-8").decode(unzipped["content.xml"]) : "";
|
|
6043
|
+
if (!contentXml) return "";
|
|
6044
|
+
const rowsMatch = contentXml.match(/<table:table-row[\s\S]*?<\/table:table-row>/g) || [];
|
|
6045
|
+
if (rowsMatch.length < 2) return "";
|
|
6046
|
+
const headers = [];
|
|
6047
|
+
const firstRow = rowsMatch[0];
|
|
6048
|
+
const headerCells = firstRow ? firstRow.match(/<text:p>([^<]+)<\/text:p>/g) || [] : [];
|
|
6049
|
+
for (const h of headerCells) {
|
|
6050
|
+
headers.push(h.replace(/<\/?text:p>/g, "").trim());
|
|
6051
|
+
}
|
|
6052
|
+
const categories = [];
|
|
6053
|
+
const seriesValues = headers.map(() => []);
|
|
6054
|
+
for (let r = 1; r < rowsMatch.length; r++) {
|
|
6055
|
+
const rowStr = rowsMatch[r];
|
|
6056
|
+
if (!rowStr) continue;
|
|
6057
|
+
const cells = rowStr.match(/<table:table-cell[\s\S]*?<\/table:table-cell>/g) || [];
|
|
6058
|
+
if (cells.length > 0 && cells[0]) {
|
|
6059
|
+
const catMatch = cells[0].match(/<text:p>([^<]+)<\/text:p>/);
|
|
6060
|
+
categories.push(catMatch ? catMatch[1] : "Row " + r);
|
|
6061
|
+
for (let c = 1; c < cells.length && c - 1 < headers.length; c++) {
|
|
6062
|
+
const cellStr = cells[c];
|
|
6063
|
+
if (!cellStr) continue;
|
|
6064
|
+
const valMatch = cellStr.match(/office:value="([0-9.]+)"/) || cellStr.match(/<text:p>([0-9.]+)<\/text:p>/);
|
|
6065
|
+
const series = seriesValues[c - 1];
|
|
6066
|
+
if (series) {
|
|
6067
|
+
series.push(valMatch ? parseFloat(valMatch[1]) : 0);
|
|
6068
|
+
}
|
|
6069
|
+
}
|
|
6070
|
+
}
|
|
6071
|
+
}
|
|
6072
|
+
const colors = ["#004586", "#ff420e", "#ffd320", "#579d1c", "#7e0021"];
|
|
6073
|
+
const colorMatches = contentXml.matchAll(/draw:fill-color="(#[0-9a-fA-F]{6})"/g);
|
|
6074
|
+
let cIdx = 0;
|
|
6075
|
+
for (const cm of colorMatches) {
|
|
6076
|
+
if (cIdx < colors.length) colors[cIdx] = cm[1];
|
|
6077
|
+
cIdx++;
|
|
6078
|
+
}
|
|
6079
|
+
let maxVal = 10;
|
|
6080
|
+
for (const s of seriesValues) {
|
|
6081
|
+
for (const v of s) {
|
|
6082
|
+
if (v > maxVal) maxVal = v;
|
|
6083
|
+
}
|
|
6084
|
+
}
|
|
6085
|
+
maxVal = Math.ceil(maxVal * 1.15);
|
|
6086
|
+
const width = 560;
|
|
6087
|
+
const height = 280;
|
|
6088
|
+
const padLeft = 45;
|
|
6089
|
+
const padRight = 100;
|
|
6090
|
+
const padTop = 20;
|
|
6091
|
+
const padBottom = 40;
|
|
6092
|
+
const chartW = width - padLeft - padRight;
|
|
6093
|
+
const chartH = height - padTop - padBottom;
|
|
6094
|
+
let svg = `<svg viewBox="0 0 ${width} ${height}" width="100%" height="auto" style="max-width: 560px; height: 280px; margin: 16px auto; display: block; font-family: Calibri, sans-serif; background: #ffffff; border: 1px solid #e2e8f0; border-radius: 6px; box-shadow: 0 1px 4px rgba(0,0,0,0.05);">`;
|
|
6095
|
+
for (let step = 0; step <= 4; step++) {
|
|
6096
|
+
const yVal = (maxVal / 4 * step).toFixed(1);
|
|
6097
|
+
const yPos = padTop + chartH - step / 4 * chartH;
|
|
6098
|
+
svg += `<line x1="${padLeft}" y1="${yPos}" x2="${padLeft + chartW}" y2="${yPos}" stroke="#e2e8f0" stroke-dasharray="2,2" />`;
|
|
6099
|
+
svg += `<text x="${padLeft - 8}" y="${yPos + 4}" font-size="11" fill="#64748b" text-anchor="end">${yVal}</text>`;
|
|
6100
|
+
}
|
|
6101
|
+
const numCats = categories.length;
|
|
6102
|
+
const numSeries = headers.length;
|
|
6103
|
+
const groupW = chartW / numCats;
|
|
6104
|
+
const barW = Math.max(8, groupW * 0.7 / numSeries);
|
|
6105
|
+
const groupPad = (groupW - barW * numSeries) / 2;
|
|
6106
|
+
for (let catIdx = 0; catIdx < numCats; catIdx++) {
|
|
6107
|
+
const groupX = padLeft + catIdx * groupW + groupPad;
|
|
6108
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6109
|
+
const val = seriesValues[sIdx][catIdx] || 0;
|
|
6110
|
+
const barH = val / maxVal * chartH;
|
|
6111
|
+
const barX = groupX + sIdx * barW;
|
|
6112
|
+
const barY = padTop + chartH - barH;
|
|
6113
|
+
const col = colors[sIdx % colors.length];
|
|
6114
|
+
svg += `<rect x="${barX}" y="${barY}" width="${barW - 2}" height="${barH}" fill="${col}" rx="2"><title>${headers[sIdx]}: ${val}</title></rect>`;
|
|
6115
|
+
}
|
|
6116
|
+
const catX = padLeft + catIdx * groupW + groupW / 2;
|
|
6117
|
+
svg += `<text x="${catX}" y="${padTop + chartH + 18}" font-size="11" fill="#475569" text-anchor="middle">${categories[catIdx]}</text>`;
|
|
6118
|
+
}
|
|
6119
|
+
let legendY = padTop + 20;
|
|
6120
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6121
|
+
const col = colors[sIdx % colors.length];
|
|
6122
|
+
svg += `<rect x="${padLeft + chartW + 15}" y="${legendY}" width="12" height="12" fill="${col}" rx="2" />`;
|
|
6123
|
+
svg += `<text x="${padLeft + chartW + 32}" y="${legendY + 10}" font-size="11" fill="#334155">${headers[sIdx]}</text>`;
|
|
6124
|
+
legendY += 20;
|
|
6125
|
+
}
|
|
6126
|
+
svg += "</svg>";
|
|
6127
|
+
return svg;
|
|
6128
|
+
} catch (e) {
|
|
6129
|
+
console.warn("[DocPlugin] Error generating chart SVG:", e);
|
|
6130
|
+
return "";
|
|
6131
|
+
}
|
|
6132
|
+
}
|
|
6133
|
+
cleanWordDocFields(text, chartSvg = "") {
|
|
6134
|
+
if (!text) return "";
|
|
6135
|
+
let cleaned = text.replace(
|
|
6136
|
+
/\x13\s*EMBED\b[\s\S]*?\x15/gi,
|
|
6137
|
+
() => chartSvg ? `
|
|
6138
|
+
|
|
6139
|
+
${chartSvg}
|
|
6140
|
+
|
|
6141
|
+
` : ""
|
|
6142
|
+
);
|
|
6143
|
+
cleaned = cleaned.replace(
|
|
6144
|
+
/\x13\s*HYPERLINK\s*"?([^"\x14]+)"?\s*\x14([\s\S]*?)\x15/gi,
|
|
6145
|
+
(_match, url, label) => {
|
|
6146
|
+
const cleanUrl = url.trim();
|
|
6147
|
+
const cleanLabel = label.trim() || cleanUrl;
|
|
6148
|
+
return `<a href="${cleanUrl}" target="_blank" rel="noopener noreferrer" style="color: #2563eb; text-decoration: underline;">${cleanLabel}</a>`;
|
|
6149
|
+
}
|
|
6150
|
+
);
|
|
6151
|
+
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g, (_m, res) => {
|
|
6152
|
+
if (/[\x00-\x1F]/.test(res)) return "";
|
|
6153
|
+
return res.trim();
|
|
6154
|
+
});
|
|
6155
|
+
cleaned = cleaned.replace(/\x13[^\x15]*\x15/g, "");
|
|
6156
|
+
cleaned = cleaned.replace(/[\x13\x14\x15]/g, "");
|
|
6157
|
+
cleaned = cleaned.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/g, "");
|
|
6158
|
+
cleaned = cleaned.replace(/EMBED\s+LibreOffice\.ChartDocument\.[0-9]+/gi, chartSvg || "");
|
|
6159
|
+
return cleaned;
|
|
6160
|
+
}
|
|
6161
|
+
splitIntoPages(text, chartSvg = "") {
|
|
5685
6162
|
if (!text) return [""];
|
|
5686
|
-
const
|
|
6163
|
+
const cleanedText = this.cleanWordDocFields(text, chartSvg);
|
|
6164
|
+
const normalized = cleanedText.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ");
|
|
5687
6165
|
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);
|
|
5688
6166
|
if (explicitParts.length === 0) explicitParts.push(normalized);
|
|
5689
|
-
const maxLinesPerPage =
|
|
6167
|
+
const maxLinesPerPage = 34;
|
|
5690
6168
|
const charsPerLine = 80;
|
|
5691
6169
|
const finalPages = [];
|
|
5692
6170
|
for (const part of explicitParts) {
|
|
@@ -5694,7 +6172,8 @@ var DocPlugin = class {
|
|
|
5694
6172
|
let currentLines = [];
|
|
5695
6173
|
let count = 0;
|
|
5696
6174
|
for (const line of lines) {
|
|
5697
|
-
const
|
|
6175
|
+
const isSvg = line.includes("<svg");
|
|
6176
|
+
const vLines = isSvg ? 12 : Math.max(1, Math.ceil((line.replace(/<[^>]+>/g, "").length || 1) / charsPerLine));
|
|
5698
6177
|
if (count + vLines > maxLinesPerPage && currentLines.length > 0) {
|
|
5699
6178
|
finalPages.push(currentLines.join("\n"));
|
|
5700
6179
|
currentLines = [];
|
|
@@ -5734,9 +6213,44 @@ var DocPlugin = class {
|
|
|
5734
6213
|
tableLines = [];
|
|
5735
6214
|
}
|
|
5736
6215
|
};
|
|
6216
|
+
const sanitizeOptions = {
|
|
6217
|
+
ADD_TAGS: ["a", "svg", "g", "path", "line", "rect", "circle", "text", "title"],
|
|
6218
|
+
ADD_ATTR: [
|
|
6219
|
+
"href",
|
|
6220
|
+
"target",
|
|
6221
|
+
"rel",
|
|
6222
|
+
"style",
|
|
6223
|
+
"viewBox",
|
|
6224
|
+
"width",
|
|
6225
|
+
"height",
|
|
6226
|
+
"x",
|
|
6227
|
+
"y",
|
|
6228
|
+
"x1",
|
|
6229
|
+
"y1",
|
|
6230
|
+
"x2",
|
|
6231
|
+
"y2",
|
|
6232
|
+
"fill",
|
|
6233
|
+
"stroke",
|
|
6234
|
+
"stroke-width",
|
|
6235
|
+
"stroke-dasharray",
|
|
6236
|
+
"rx",
|
|
6237
|
+
"font-size",
|
|
6238
|
+
"text-anchor"
|
|
6239
|
+
]
|
|
6240
|
+
};
|
|
5737
6241
|
let i = 0;
|
|
5738
6242
|
while (i < lines.length) {
|
|
5739
6243
|
let line = lines[i];
|
|
6244
|
+
if (line.includes("<svg")) {
|
|
6245
|
+
if (inList) {
|
|
6246
|
+
html += "</ul>";
|
|
6247
|
+
inList = false;
|
|
6248
|
+
}
|
|
6249
|
+
flushTable();
|
|
6250
|
+
html += line;
|
|
6251
|
+
i++;
|
|
6252
|
+
continue;
|
|
6253
|
+
}
|
|
5740
6254
|
let tabCount = (line.match(/\t/g) || []).length;
|
|
5741
6255
|
if (tabCount > 0) {
|
|
5742
6256
|
let j = i;
|
|
@@ -5775,20 +6289,20 @@ var DocPlugin = class {
|
|
|
5775
6289
|
html += "</ul>";
|
|
5776
6290
|
inList = false;
|
|
5777
6291
|
}
|
|
5778
|
-
html += `<h2 style="font-size: 16px; font-weight: 700; color: #1e3a8a; margin: 16px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6__default.default.sanitize(line)}</h2>`;
|
|
6292
|
+
html += `<h2 style="font-size: 16px; font-weight: 700; color: #1e3a8a; margin: 16px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6__default.default.sanitize(line, sanitizeOptions)}</h2>`;
|
|
5779
6293
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
5780
6294
|
if (!inList) {
|
|
5781
6295
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
5782
6296
|
inList = true;
|
|
5783
6297
|
}
|
|
5784
6298
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
5785
|
-
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6__default.default.sanitize(bulletText)}</li>`;
|
|
6299
|
+
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6__default.default.sanitize(bulletText, sanitizeOptions)}</li>`;
|
|
5786
6300
|
} else {
|
|
5787
6301
|
if (inList) {
|
|
5788
6302
|
html += "</ul>";
|
|
5789
6303
|
inList = false;
|
|
5790
6304
|
}
|
|
5791
|
-
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6__default.default.sanitize(line)}</p>`;
|
|
6305
|
+
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6__default.default.sanitize(line, sanitizeOptions)}</p>`;
|
|
5792
6306
|
}
|
|
5793
6307
|
i++;
|
|
5794
6308
|
}
|