@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/vue.cjs
CHANGED
|
@@ -17,6 +17,7 @@ var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
|
|
|
17
17
|
var OrbitControls_js = require('three/examples/jsm/controls/OrbitControls.js');
|
|
18
18
|
var RTFJS = require('rtf.js/dist/RTFJS.bundle.js');
|
|
19
19
|
|
|
20
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
20
21
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
21
22
|
|
|
22
23
|
function _interopNamespace(e) {
|
|
@@ -369,16 +370,21 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
369
370
|
metadata.mimeType = source.type || void 0;
|
|
370
371
|
metadata.extension = extractExtension(source.name);
|
|
371
372
|
buffer = await source.arrayBuffer();
|
|
372
|
-
} else if (source instanceof Blob) {
|
|
373
|
+
} else if (source instanceof Blob || source && typeof source.arrayBuffer === "function" && typeof source.size === "number") {
|
|
373
374
|
metadata.size = source.size;
|
|
374
375
|
metadata.mimeType = source.type || void 0;
|
|
376
|
+
if (source.name) {
|
|
377
|
+
metadata.name = source.name;
|
|
378
|
+
metadata.extension = extractExtension(source.name);
|
|
379
|
+
}
|
|
375
380
|
buffer = await source.arrayBuffer();
|
|
376
|
-
} else if (source instanceof ArrayBuffer) {
|
|
381
|
+
} else if (source instanceof ArrayBuffer || Object.prototype.toString.call(source) === "[object ArrayBuffer]" || source && typeof source.byteLength === "number" && typeof source.slice === "function") {
|
|
377
382
|
buffer = source;
|
|
378
|
-
} else if (source instanceof Uint8Array) {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
383
|
+
} else if (source instanceof Uint8Array || ArrayBuffer.isView(source)) {
|
|
384
|
+
const view = source;
|
|
385
|
+
buffer = view.buffer.slice(
|
|
386
|
+
view.byteOffset,
|
|
387
|
+
view.byteOffset + view.byteLength
|
|
382
388
|
);
|
|
383
389
|
} else {
|
|
384
390
|
throw new Error("Unsupported file source type");
|
|
@@ -463,6 +469,45 @@ function createElement(tag, attrs, ...children) {
|
|
|
463
469
|
}
|
|
464
470
|
return el;
|
|
465
471
|
}
|
|
472
|
+
var DB_NAME = "PreviewFileTransferDB";
|
|
473
|
+
var DB_STORE = "transfers";
|
|
474
|
+
function openDB() {
|
|
475
|
+
return new Promise((resolve, reject) => {
|
|
476
|
+
if (typeof indexedDB === "undefined") {
|
|
477
|
+
return reject(new Error("IndexedDB is not available"));
|
|
478
|
+
}
|
|
479
|
+
const req = indexedDB.open(DB_NAME, 1);
|
|
480
|
+
req.onupgradeneeded = () => {
|
|
481
|
+
const db = req.result;
|
|
482
|
+
if (!db.objectStoreNames.contains(DB_STORE)) {
|
|
483
|
+
db.createObjectStore(DB_STORE, { keyPath: "id" });
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
req.onsuccess = () => resolve(req.result);
|
|
487
|
+
req.onerror = () => reject(req.error);
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
async function saveTransferPayload(id, payload) {
|
|
491
|
+
if (typeof window !== "undefined") {
|
|
492
|
+
try {
|
|
493
|
+
window[id] = payload;
|
|
494
|
+
window.__lastTransfer = payload;
|
|
495
|
+
} catch {
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
try {
|
|
499
|
+
const db = await openDB();
|
|
500
|
+
return new Promise((resolve, reject) => {
|
|
501
|
+
const tx = db.transaction(DB_STORE, "readwrite");
|
|
502
|
+
const store = tx.objectStore(DB_STORE);
|
|
503
|
+
store.put({ id, ...payload, timestamp: Date.now() });
|
|
504
|
+
tx.oncomplete = () => resolve();
|
|
505
|
+
tx.onerror = () => reject(tx.error);
|
|
506
|
+
});
|
|
507
|
+
} catch (e) {
|
|
508
|
+
console.warn("[saveTransferPayload] IndexedDB store warning:", e);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
466
511
|
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>`;
|
|
467
512
|
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>`;
|
|
468
513
|
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>`;
|
|
@@ -482,6 +527,7 @@ var ICON_COPY = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" str
|
|
|
482
527
|
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>`;
|
|
483
528
|
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>`;
|
|
484
529
|
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>`;
|
|
530
|
+
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>`;
|
|
485
531
|
var ICON_MAP = {
|
|
486
532
|
"zoom-in": ICON_ZOOM_IN,
|
|
487
533
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -508,7 +554,9 @@ var ICON_MAP = {
|
|
|
508
554
|
"forward-10": ICON_FAST_FORWARD,
|
|
509
555
|
"rewind": ICON_REWIND,
|
|
510
556
|
"replay-10": ICON_REWIND,
|
|
511
|
-
"speed": ICON_SPEED
|
|
557
|
+
"speed": ICON_SPEED,
|
|
558
|
+
"open-window": ICON_EXTERNAL_WINDOW,
|
|
559
|
+
"external-window": ICON_EXTERNAL_WINDOW
|
|
512
560
|
};
|
|
513
561
|
var ToolbarController = class {
|
|
514
562
|
el;
|
|
@@ -725,7 +773,7 @@ var ThumbnailPanel = class {
|
|
|
725
773
|
}
|
|
726
774
|
}
|
|
727
775
|
};
|
|
728
|
-
var FilePreviewViewer = class {
|
|
776
|
+
var FilePreviewViewer = class _FilePreviewViewer {
|
|
729
777
|
plugins = [];
|
|
730
778
|
activeInstance = null;
|
|
731
779
|
abortController = null;
|
|
@@ -762,6 +810,7 @@ var FilePreviewViewer = class {
|
|
|
762
810
|
* Preview a file in the given container element.
|
|
763
811
|
*/
|
|
764
812
|
async preview(container, source, options = {}) {
|
|
813
|
+
this.currentOptions = options;
|
|
765
814
|
this.abort();
|
|
766
815
|
this.abortController = new AbortController();
|
|
767
816
|
const { signal } = this.abortController;
|
|
@@ -771,7 +820,10 @@ var FilePreviewViewer = class {
|
|
|
771
820
|
this.showLoading();
|
|
772
821
|
try {
|
|
773
822
|
const { buffer, metadata } = await sourceToArrayBuffer(source, signal);
|
|
774
|
-
|
|
823
|
+
if (options.metadata) {
|
|
824
|
+
Object.assign(metadata, options.metadata);
|
|
825
|
+
}
|
|
826
|
+
this.currentBuffer = buffer.slice(0);
|
|
775
827
|
this.currentMetadata = metadata;
|
|
776
828
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
777
829
|
const fileInfo = { metadata, buffer };
|
|
@@ -801,6 +853,7 @@ var FilePreviewViewer = class {
|
|
|
801
853
|
}
|
|
802
854
|
});
|
|
803
855
|
this.activeInstance = instance;
|
|
856
|
+
instance.openInSeparateWindow = () => this.openInSeparateWindow();
|
|
804
857
|
this.hideLoading();
|
|
805
858
|
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
806
859
|
if (options.showToolbar !== false && this.toolbar) {
|
|
@@ -810,26 +863,16 @@ var FilePreviewViewer = class {
|
|
|
810
863
|
actions.push({
|
|
811
864
|
id: "fullscreen",
|
|
812
865
|
icon: "fullscreen",
|
|
813
|
-
label: "
|
|
866
|
+
label: "Fullscreen",
|
|
814
867
|
type: "button",
|
|
815
868
|
group: "view",
|
|
816
|
-
execute:
|
|
869
|
+
execute: () => {
|
|
817
870
|
try {
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
if (this.wrapperEl?.requestFullscreen) {
|
|
822
|
-
await this.wrapperEl.requestFullscreen().catch(() => {
|
|
823
|
-
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
824
|
-
});
|
|
825
|
-
} else {
|
|
826
|
-
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
827
|
-
}
|
|
871
|
+
if (!document.fullscreenElement) {
|
|
872
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
873
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
828
874
|
} else {
|
|
829
|
-
|
|
830
|
-
await document.exitFullscreen().catch(() => {
|
|
831
|
-
});
|
|
832
|
-
}
|
|
875
|
+
document.exitFullscreen?.();
|
|
833
876
|
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
834
877
|
}
|
|
835
878
|
} catch {
|
|
@@ -841,6 +884,28 @@ var FilePreviewViewer = class {
|
|
|
841
884
|
}
|
|
842
885
|
});
|
|
843
886
|
}
|
|
887
|
+
const openWinAction = actions.find((a) => a.id === "open-window");
|
|
888
|
+
if (openWinAction) {
|
|
889
|
+
if (options?._isSeparateWindow) {
|
|
890
|
+
const idx = actions.indexOf(openWinAction);
|
|
891
|
+
if (idx !== -1) actions.splice(idx, 1);
|
|
892
|
+
} else {
|
|
893
|
+
openWinAction.execute = () => {
|
|
894
|
+
this.openInSeparateWindow();
|
|
895
|
+
};
|
|
896
|
+
}
|
|
897
|
+
} else if (!options?._isSeparateWindow) {
|
|
898
|
+
actions.push({
|
|
899
|
+
id: "open-window",
|
|
900
|
+
icon: "open-window",
|
|
901
|
+
label: "Open in Separate Full Window",
|
|
902
|
+
type: "button",
|
|
903
|
+
group: "actions",
|
|
904
|
+
execute: () => {
|
|
905
|
+
this.openInSeparateWindow();
|
|
906
|
+
}
|
|
907
|
+
});
|
|
908
|
+
}
|
|
844
909
|
this.toolbar.update(actions);
|
|
845
910
|
this.toolbar.show();
|
|
846
911
|
}
|
|
@@ -873,6 +938,104 @@ var FilePreviewViewer = class {
|
|
|
873
938
|
throw error;
|
|
874
939
|
}
|
|
875
940
|
}
|
|
941
|
+
/**
|
|
942
|
+
* Opens the current file preview in a separate full browser window.
|
|
943
|
+
*/
|
|
944
|
+
openInSeparateWindow() {
|
|
945
|
+
if (!this.currentBuffer) {
|
|
946
|
+
console.warn("[FilePreviewViewer] No active file buffer to open in separate window");
|
|
947
|
+
return null;
|
|
948
|
+
}
|
|
949
|
+
if (this.currentOptions.onOpenSeparateWindow) {
|
|
950
|
+
return this.currentOptions.onOpenSeparateWindow({
|
|
951
|
+
buffer: this.currentBuffer,
|
|
952
|
+
metadata: this.currentMetadata || { name: "Document" },
|
|
953
|
+
options: this.currentOptions
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
const transferId = "fp_win_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8);
|
|
957
|
+
let clonedBuffer;
|
|
958
|
+
try {
|
|
959
|
+
clonedBuffer = this.currentBuffer.slice(0);
|
|
960
|
+
} catch {
|
|
961
|
+
clonedBuffer = this.currentBuffer;
|
|
962
|
+
}
|
|
963
|
+
const payload = {
|
|
964
|
+
buffer: clonedBuffer,
|
|
965
|
+
metadata: this.currentMetadata ? { ...this.currentMetadata } : void 0,
|
|
966
|
+
options: { ...this.currentOptions, _isSeparateWindow: true }
|
|
967
|
+
};
|
|
968
|
+
if (typeof window !== "undefined") {
|
|
969
|
+
try {
|
|
970
|
+
window[transferId] = payload;
|
|
971
|
+
window.__lastTransfer = payload;
|
|
972
|
+
} catch {
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
saveTransferPayload(transferId, payload).catch((err) => {
|
|
976
|
+
console.warn("[FilePreviewViewer] Transfer payload save warning:", err);
|
|
977
|
+
});
|
|
978
|
+
let targetUrl = null;
|
|
979
|
+
if (this.currentOptions.standaloneViewerUrl) {
|
|
980
|
+
const u = new URL(this.currentOptions.standaloneViewerUrl, window.location.href);
|
|
981
|
+
u.searchParams.set("mode", "fullscreen");
|
|
982
|
+
u.searchParams.set("transferId", transferId);
|
|
983
|
+
targetUrl = u.toString();
|
|
984
|
+
} else if (typeof window !== "undefined" && window.location?.href && !window.location.href.startsWith("about:")) {
|
|
985
|
+
const u = new URL(window.location.href);
|
|
986
|
+
u.searchParams.set("mode", "fullscreen");
|
|
987
|
+
u.searchParams.set("transferId", transferId);
|
|
988
|
+
targetUrl = u.toString();
|
|
989
|
+
}
|
|
990
|
+
if (targetUrl) {
|
|
991
|
+
const newWin2 = window.open(targetUrl, "_blank");
|
|
992
|
+
if (!newWin2) {
|
|
993
|
+
alert("Popup blocker prevented opening the preview in a separate window. Please allow popups for this site.");
|
|
994
|
+
return null;
|
|
995
|
+
}
|
|
996
|
+
return newWin2;
|
|
997
|
+
}
|
|
998
|
+
const title = (this.currentMetadata?.name || "Document Preview") + " - Full Preview";
|
|
999
|
+
const newWin = window.open("", "_blank");
|
|
1000
|
+
if (!newWin) {
|
|
1001
|
+
alert("Popup blocker prevented opening the preview in a separate window. Please allow popups for this site.");
|
|
1002
|
+
return null;
|
|
1003
|
+
}
|
|
1004
|
+
newWin.document.title = title;
|
|
1005
|
+
newWin.document.body.style.margin = "0";
|
|
1006
|
+
newWin.document.body.style.padding = "0";
|
|
1007
|
+
newWin.document.body.style.width = "100vw";
|
|
1008
|
+
newWin.document.body.style.height = "100vh";
|
|
1009
|
+
newWin.document.body.style.overflow = "hidden";
|
|
1010
|
+
newWin.document.body.style.backgroundColor = "#f8fafc";
|
|
1011
|
+
const headNodes = document.querySelectorAll('link[rel="stylesheet"], style');
|
|
1012
|
+
headNodes.forEach((node) => {
|
|
1013
|
+
newWin.document.head.appendChild(node.cloneNode(true));
|
|
1014
|
+
});
|
|
1015
|
+
const root = newWin.document.createElement("div");
|
|
1016
|
+
root.id = "full-window-preview-root";
|
|
1017
|
+
root.style.width = "100%";
|
|
1018
|
+
root.style.height = "100%";
|
|
1019
|
+
root.style.overflow = "hidden";
|
|
1020
|
+
newWin.document.body.appendChild(root);
|
|
1021
|
+
const separateViewer = new _FilePreviewViewer();
|
|
1022
|
+
for (const plugin of this.plugins) {
|
|
1023
|
+
separateViewer.registerPlugin(plugin);
|
|
1024
|
+
}
|
|
1025
|
+
separateViewer.preview(root, this.currentBuffer.slice(0), {
|
|
1026
|
+
...this.currentOptions,
|
|
1027
|
+
showToolbar: true,
|
|
1028
|
+
toolbarPosition: "top",
|
|
1029
|
+
metadata: this.currentMetadata || void 0,
|
|
1030
|
+
_isSeparateWindow: true
|
|
1031
|
+
}).catch((err) => {
|
|
1032
|
+
console.error("[FilePreviewViewer] Error rendering in separate window:", err);
|
|
1033
|
+
});
|
|
1034
|
+
newWin.addEventListener("beforeunload", () => {
|
|
1035
|
+
separateViewer.destroy();
|
|
1036
|
+
});
|
|
1037
|
+
return newWin;
|
|
1038
|
+
}
|
|
876
1039
|
/**
|
|
877
1040
|
* Subscribe to viewer events.
|
|
878
1041
|
*/
|
|
@@ -1278,8 +1441,20 @@ var CfbfReader = class {
|
|
|
1278
1441
|
}
|
|
1279
1442
|
};
|
|
1280
1443
|
if (typeof window !== "undefined" && pdfjsLib__namespace.GlobalWorkerOptions) {
|
|
1281
|
-
if (!pdfjsLib__namespace.GlobalWorkerOptions.workerSrc) {
|
|
1282
|
-
|
|
1444
|
+
if (!pdfjsLib__namespace.GlobalWorkerOptions.workerPort && !pdfjsLib__namespace.GlobalWorkerOptions.workerSrc) {
|
|
1445
|
+
const customWorker = window.__PDF_WORKER_SRC__;
|
|
1446
|
+
if (customWorker) {
|
|
1447
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = customWorker;
|
|
1448
|
+
} else {
|
|
1449
|
+
try {
|
|
1450
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerPort = new Worker(
|
|
1451
|
+
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('vue.cjs', document.baseURI).href))),
|
|
1452
|
+
{ type: "module" }
|
|
1453
|
+
);
|
|
1454
|
+
} catch {
|
|
1455
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = "./pdf.worker.min.mjs";
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1283
1458
|
}
|
|
1284
1459
|
}
|
|
1285
1460
|
var PdfPlugin = class {
|
|
@@ -1373,6 +1548,14 @@ var PdfPlugin = class {
|
|
|
1373
1548
|
type: "button",
|
|
1374
1549
|
group: "actions",
|
|
1375
1550
|
execute: () => instance.print?.()
|
|
1551
|
+
},
|
|
1552
|
+
{
|
|
1553
|
+
id: "open-window",
|
|
1554
|
+
icon: "open-window",
|
|
1555
|
+
label: "Open in Separate Full Window",
|
|
1556
|
+
type: "button",
|
|
1557
|
+
group: "actions",
|
|
1558
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
1376
1559
|
}
|
|
1377
1560
|
];
|
|
1378
1561
|
}
|
|
@@ -1422,18 +1605,21 @@ var PdfPlugin = class {
|
|
|
1422
1605
|
indicator.style.pointerEvents = "none";
|
|
1423
1606
|
container.appendChild(indicator);
|
|
1424
1607
|
ctx.container.appendChild(container);
|
|
1608
|
+
const standardFontsUrl = typeof window !== "undefined" && window.__PDF_STANDARD_FONTS_URL__ || "./standard_fonts/";
|
|
1609
|
+
const cmapsUrl = typeof window !== "undefined" && window.__PDF_CMAPS_URL__ || "./cmaps/";
|
|
1425
1610
|
const loadingTask = pdfjsLib__namespace.getDocument({
|
|
1426
|
-
data: new Uint8Array(ctx.buffer),
|
|
1427
|
-
cMapUrl:
|
|
1611
|
+
data: new Uint8Array(ctx.buffer.slice(0)),
|
|
1612
|
+
cMapUrl: cmapsUrl,
|
|
1428
1613
|
cMapPacked: true,
|
|
1429
|
-
standardFontDataUrl:
|
|
1614
|
+
standardFontDataUrl: standardFontsUrl,
|
|
1615
|
+
verbosity: 0
|
|
1430
1616
|
});
|
|
1431
1617
|
const pdfDoc = await loadingTask.promise;
|
|
1432
1618
|
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1433
1619
|
let currentPage = 1;
|
|
1434
1620
|
let zoomScale = 1;
|
|
1435
1621
|
let rotation = 0;
|
|
1436
|
-
let fitMode = "
|
|
1622
|
+
let fitMode = "page";
|
|
1437
1623
|
let currentRenderTask = null;
|
|
1438
1624
|
const renderPage = async (pageNum) => {
|
|
1439
1625
|
if (currentRenderTask) {
|
|
@@ -1453,15 +1639,15 @@ var PdfPlugin = class {
|
|
|
1453
1639
|
const containerWidth = container.clientWidth || 900;
|
|
1454
1640
|
const containerHeight = container.clientHeight || 700;
|
|
1455
1641
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1456
|
-
const availWidth = Math.max(
|
|
1457
|
-
const availHeight = Math.max(
|
|
1642
|
+
const availWidth = Math.max(320, containerWidth - 48);
|
|
1643
|
+
const availHeight = Math.max(550, containerHeight - 88);
|
|
1458
1644
|
const scaleW = availWidth / unscaledVp.width;
|
|
1459
1645
|
const scaleH = availHeight / unscaledVp.height;
|
|
1460
1646
|
let fitScale;
|
|
1461
1647
|
if (fitMode === "page") {
|
|
1462
|
-
fitScale = Math.max(0.
|
|
1648
|
+
fitScale = Math.max(0.4, Math.min(scaleW, scaleH));
|
|
1463
1649
|
} else {
|
|
1464
|
-
fitScale = Math.max(0.65, Math.min(1.
|
|
1650
|
+
fitScale = Math.max(0.65, Math.min(1.25, scaleW));
|
|
1465
1651
|
}
|
|
1466
1652
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1467
1653
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
@@ -1487,7 +1673,7 @@ var PdfPlugin = class {
|
|
|
1487
1673
|
currentRenderTask = null;
|
|
1488
1674
|
}
|
|
1489
1675
|
};
|
|
1490
|
-
|
|
1676
|
+
renderPage(1);
|
|
1491
1677
|
let resizeTimer = null;
|
|
1492
1678
|
const resizeObserver = new ResizeObserver(() => {
|
|
1493
1679
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
@@ -1531,7 +1717,7 @@ var PdfPlugin = class {
|
|
|
1531
1717
|
renderPage(currentPage);
|
|
1532
1718
|
},
|
|
1533
1719
|
fitToPage: () => {
|
|
1534
|
-
fitMode = fitMode === "
|
|
1720
|
+
fitMode = fitMode === "page" ? "width" : "page";
|
|
1535
1721
|
zoomScale = 1;
|
|
1536
1722
|
rotation = 0;
|
|
1537
1723
|
renderPage(currentPage);
|
|
@@ -2008,6 +2194,14 @@ var DocxPlugin = class {
|
|
|
2008
2194
|
type: "button",
|
|
2009
2195
|
group: "actions",
|
|
2010
2196
|
execute: () => instance.print?.()
|
|
2197
|
+
},
|
|
2198
|
+
{
|
|
2199
|
+
id: "open-window",
|
|
2200
|
+
icon: "open-window",
|
|
2201
|
+
label: "Open in Separate Full Window",
|
|
2202
|
+
type: "button",
|
|
2203
|
+
group: "actions",
|
|
2204
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
2011
2205
|
}
|
|
2012
2206
|
);
|
|
2013
2207
|
return actions;
|
|
@@ -2067,6 +2261,31 @@ var DocxPlugin = class {
|
|
|
2067
2261
|
}
|
|
2068
2262
|
if (wrapper.children.length > 0 && (wrapper.textContent?.trim().length ?? 0) > 0) {
|
|
2069
2263
|
renderedSuccessfully = true;
|
|
2264
|
+
try {
|
|
2265
|
+
const unzipped = fflate.unzipSync(new Uint8Array(ctx.buffer));
|
|
2266
|
+
const chartKeys = Object.keys(unzipped).filter((k) => k.replace(/^[./\\]+/, "").toLowerCase().startsWith("word/charts/chart") && k.endsWith(".xml")).sort();
|
|
2267
|
+
if (chartKeys.length > 0) {
|
|
2268
|
+
const allDivs = Array.from(wrapper.querySelectorAll("div"));
|
|
2269
|
+
const emptyContainers = allDivs.filter((div) => {
|
|
2270
|
+
const st = div.getAttribute("style") || "";
|
|
2271
|
+
return st.includes("width:") && st.includes("height:") && div.children.length === 0 && (div.textContent?.trim().length ?? 0) === 0;
|
|
2272
|
+
});
|
|
2273
|
+
chartKeys.forEach((cKey, idx) => {
|
|
2274
|
+
const target = emptyContainers[idx];
|
|
2275
|
+
if (target) {
|
|
2276
|
+
const xmlStr = fflate.strFromU8(unzipped[cKey]);
|
|
2277
|
+
const svg = this.parseAndRenderChartSvg(xmlStr);
|
|
2278
|
+
if (svg) {
|
|
2279
|
+
target.innerHTML = svg;
|
|
2280
|
+
target.style.display = "block";
|
|
2281
|
+
target.style.margin = "12px auto";
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
});
|
|
2285
|
+
}
|
|
2286
|
+
} catch (chartErr) {
|
|
2287
|
+
console.warn("[DocxPlugin] Non-critical error rendering DrawingML charts:", chartErr);
|
|
2288
|
+
}
|
|
2070
2289
|
}
|
|
2071
2290
|
} catch (err) {
|
|
2072
2291
|
console.warn("[DocxPlugin] docx-preview failed, triggering native fallback:", err);
|
|
@@ -2098,64 +2317,74 @@ var DocxPlugin = class {
|
|
|
2098
2317
|
}
|
|
2099
2318
|
let sections = Array.from(wrapper.querySelectorAll("section.docx"));
|
|
2100
2319
|
const cards = Array.from(wrapper.querySelectorAll(".fp-docx-page-card"));
|
|
2101
|
-
if (sections.length
|
|
2102
|
-
const
|
|
2103
|
-
const
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
const
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
nextSec.
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
nextArticle
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
nextSec.appendChild(
|
|
2320
|
+
if (sections.length > 0 && cards.length === 0) {
|
|
2321
|
+
const finalSections = [];
|
|
2322
|
+
for (const singleSec of sections) {
|
|
2323
|
+
const contentContainer = singleSec.querySelector("article") || singleSec;
|
|
2324
|
+
const children = Array.from(contentContainer.children);
|
|
2325
|
+
const pageH = singleSec.offsetHeight > 1300 ? 1122 : Math.max(1056, singleSec.offsetHeight);
|
|
2326
|
+
const secH = singleSec.scrollHeight || singleSec.offsetHeight;
|
|
2327
|
+
if (secH > pageH * 1.25 && children.length > 1) {
|
|
2328
|
+
const childHeights = children.map((c) => {
|
|
2329
|
+
const rectH = c.getBoundingClientRect().height;
|
|
2330
|
+
const offH = c.offsetHeight;
|
|
2331
|
+
const textLen = c.textContent?.trim().length || 0;
|
|
2332
|
+
const estH = Math.max(24, Math.ceil(textLen / 80) * 22 + 16);
|
|
2333
|
+
return Math.max(rectH, offH, estH);
|
|
2334
|
+
});
|
|
2335
|
+
const parent = singleSec.parentElement || wrapper;
|
|
2336
|
+
const headerEl = singleSec.querySelector("header");
|
|
2337
|
+
const footerEl = singleSec.querySelector("footer");
|
|
2338
|
+
contentContainer.innerHTML = "";
|
|
2339
|
+
singleSec.style.minHeight = `${pageH}px`;
|
|
2340
|
+
singleSec.style.boxSizing = "border-box";
|
|
2341
|
+
let curContent = contentContainer;
|
|
2342
|
+
let curSec = singleSec;
|
|
2343
|
+
let curH = 0;
|
|
2344
|
+
const maxH = pageH - 140;
|
|
2345
|
+
finalSections.push(singleSec);
|
|
2346
|
+
for (let i = 0; i < children.length; i++) {
|
|
2347
|
+
const child = children[i];
|
|
2348
|
+
const chH = childHeights[i];
|
|
2349
|
+
curContent.appendChild(child);
|
|
2350
|
+
curH += chH;
|
|
2351
|
+
if (curH >= maxH && i < children.length - 1) {
|
|
2352
|
+
const nextSec = document.createElement("section");
|
|
2353
|
+
nextSec.className = singleSec.className;
|
|
2354
|
+
nextSec.style.cssText = singleSec.style.cssText;
|
|
2355
|
+
nextSec.style.minHeight = `${pageH}px`;
|
|
2356
|
+
nextSec.style.boxSizing = "border-box";
|
|
2357
|
+
nextSec.style.backgroundColor = "#ffffff";
|
|
2358
|
+
nextSec.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
2359
|
+
nextSec.style.borderRadius = "4px";
|
|
2360
|
+
nextSec.style.marginBottom = "24px";
|
|
2361
|
+
if (headerEl) {
|
|
2362
|
+
nextSec.appendChild(headerEl.cloneNode(true));
|
|
2363
|
+
}
|
|
2364
|
+
const nextArticle = document.createElement("article");
|
|
2365
|
+
if (contentContainer.tagName.toLowerCase() === "article") {
|
|
2366
|
+
nextArticle.style.cssText = contentContainer.style.cssText;
|
|
2367
|
+
}
|
|
2368
|
+
nextSec.appendChild(nextArticle);
|
|
2369
|
+
if (footerEl) {
|
|
2370
|
+
nextSec.appendChild(footerEl.cloneNode(true));
|
|
2371
|
+
}
|
|
2372
|
+
if (curSec.nextSibling) {
|
|
2373
|
+
parent.insertBefore(nextSec, curSec.nextSibling);
|
|
2374
|
+
} else {
|
|
2375
|
+
parent.appendChild(nextSec);
|
|
2376
|
+
}
|
|
2377
|
+
finalSections.push(nextSec);
|
|
2378
|
+
curSec = nextSec;
|
|
2379
|
+
curContent = nextArticle;
|
|
2380
|
+
curH = 0;
|
|
2150
2381
|
}
|
|
2151
|
-
parent.appendChild(nextSec);
|
|
2152
|
-
newSections.push(nextSec);
|
|
2153
|
-
curContent = nextArticle;
|
|
2154
|
-
curH = 0;
|
|
2155
2382
|
}
|
|
2383
|
+
} else {
|
|
2384
|
+
finalSections.push(singleSec);
|
|
2156
2385
|
}
|
|
2157
|
-
sections = newSections;
|
|
2158
2386
|
}
|
|
2387
|
+
sections = finalSections;
|
|
2159
2388
|
}
|
|
2160
2389
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2161
2390
|
const totalPages = Math.max(1, pageElements.length);
|
|
@@ -2547,6 +2776,88 @@ var DocxPlugin = class {
|
|
|
2547
2776
|
}
|
|
2548
2777
|
return result;
|
|
2549
2778
|
}
|
|
2779
|
+
parseAndRenderChartSvg(xmlStr, width = 500, height = 260) {
|
|
2780
|
+
const catMatches = [...xmlStr.matchAll(/<c:cat>[\s\S]*?<c:strCache>([\s\S]*?)<\/c:strCache>/g)];
|
|
2781
|
+
let categories = [];
|
|
2782
|
+
if (catMatches.length > 0) {
|
|
2783
|
+
categories = [...catMatches[0][1].matchAll(/<c:v>([^<]+)<\/c:v>/g)].map((m) => m[1]);
|
|
2784
|
+
}
|
|
2785
|
+
if (categories.length === 0) {
|
|
2786
|
+
categories = ["Category 1", "Category 2", "Category 3", "Category 4"];
|
|
2787
|
+
}
|
|
2788
|
+
const defaultColors = ["#004586", "#ff420e", "#ffd320", "#579d1c", "#7e0021", "#83caff"];
|
|
2789
|
+
const sers = [...xmlStr.matchAll(/<c:ser>([\s\S]*?)<\/c:ser>/g)];
|
|
2790
|
+
const series = [];
|
|
2791
|
+
sers.forEach((s, sIdx) => {
|
|
2792
|
+
const titleMatch = s[1].match(/<c:tx>[\s\S]*?<c:v>([^<]+)<\/c:v>/);
|
|
2793
|
+
const title = titleMatch ? titleMatch[1] : `Series ${sIdx + 1}`;
|
|
2794
|
+
const clrMatch = s[1].match(/<a:srgbClr\s+val="([^"]+)"/);
|
|
2795
|
+
const color = clrMatch ? "#" + clrMatch[1] : defaultColors[sIdx % defaultColors.length];
|
|
2796
|
+
const valMatch = s[1].match(/<c:val>[\s\S]*?<c:numCache>([\s\S]*?)<\/c:numCache>/);
|
|
2797
|
+
let values = [];
|
|
2798
|
+
if (valMatch) {
|
|
2799
|
+
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);
|
|
2800
|
+
}
|
|
2801
|
+
series.push({ title, color, values });
|
|
2802
|
+
});
|
|
2803
|
+
if (series.length === 0) return "";
|
|
2804
|
+
let maxVal = 10;
|
|
2805
|
+
series.forEach((s) => s.values.forEach((v) => {
|
|
2806
|
+
if (v > maxVal) maxVal = v;
|
|
2807
|
+
}));
|
|
2808
|
+
maxVal = Math.ceil(maxVal * 1.15);
|
|
2809
|
+
if (maxVal % 2 !== 0) maxVal++;
|
|
2810
|
+
const padLeft = 45;
|
|
2811
|
+
const padBottom = 55;
|
|
2812
|
+
const padTop = 20;
|
|
2813
|
+
const padRight = 20;
|
|
2814
|
+
const plotW = width - padLeft - padRight;
|
|
2815
|
+
const plotH = height - padTop - padBottom;
|
|
2816
|
+
const yTicks = 5;
|
|
2817
|
+
let gridLines = "";
|
|
2818
|
+
for (let i = 0; i <= yTicks; i++) {
|
|
2819
|
+
const val = maxVal / yTicks * i;
|
|
2820
|
+
const y = padTop + plotH - val / maxVal * plotH;
|
|
2821
|
+
gridLines += `<line x1="${padLeft}" y1="${y}" x2="${padLeft + plotW}" y2="${y}" stroke="#e2e8f0" stroke-width="1" />`;
|
|
2822
|
+
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>`;
|
|
2823
|
+
}
|
|
2824
|
+
const numCats = categories.length;
|
|
2825
|
+
const numSers = series.length;
|
|
2826
|
+
const groupW = plotW / numCats;
|
|
2827
|
+
const barW = Math.max(8, Math.min(28, groupW * 0.7 / numSers));
|
|
2828
|
+
const groupPad = (groupW - barW * numSers) / 2;
|
|
2829
|
+
let bars = "";
|
|
2830
|
+
let catLabels = "";
|
|
2831
|
+
for (let c = 0; c < numCats; c++) {
|
|
2832
|
+
const catX = padLeft + c * groupW;
|
|
2833
|
+
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>`;
|
|
2834
|
+
for (let s = 0; s < numSers; s++) {
|
|
2835
|
+
const val = series[s].values[c] ?? 0;
|
|
2836
|
+
const bH = Math.max(0, val / maxVal * plotH);
|
|
2837
|
+
const bX = catX + groupPad + s * barW;
|
|
2838
|
+
const bY = padTop + plotH - bH;
|
|
2839
|
+
bars += `<rect x="${bX}" y="${bY}" width="${barW - 2}" height="${bH}" fill="${series[s].color}" rx="1" />`;
|
|
2840
|
+
}
|
|
2841
|
+
}
|
|
2842
|
+
let legend = "";
|
|
2843
|
+
const legY = height - 12;
|
|
2844
|
+
let legX = padLeft + (plotW - numSers * 100) / 2;
|
|
2845
|
+
series.forEach((s) => {
|
|
2846
|
+
legend += `<rect x="${legX}" y="${legY - 9}" width="10" height="10" fill="${s.color}" rx="2" />`;
|
|
2847
|
+
legend += `<text x="${legX + 15}" y="${legY}" font-size="11" fill="#475569" font-family="Calibri, sans-serif">${s.title}</text>`;
|
|
2848
|
+
legX += 95;
|
|
2849
|
+
});
|
|
2850
|
+
return `
|
|
2851
|
+
<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">
|
|
2852
|
+
${gridLines}
|
|
2853
|
+
<line x1="${padLeft}" y1="${padTop + plotH}" x2="${padLeft + plotW}" y2="${padTop + plotH}" stroke="#94a3b8" stroke-width="1.5" />
|
|
2854
|
+
<line x1="${padLeft}" y1="${padTop}" x2="${padLeft}" y2="${padTop + plotH}" stroke="#94a3b8" stroke-width="1.5" />
|
|
2855
|
+
${bars}
|
|
2856
|
+
${catLabels}
|
|
2857
|
+
${legend}
|
|
2858
|
+
</svg>
|
|
2859
|
+
`.trim();
|
|
2860
|
+
}
|
|
2550
2861
|
};
|
|
2551
2862
|
function docxPlugin() {
|
|
2552
2863
|
return new DocxPlugin();
|
|
@@ -3113,6 +3424,16 @@ var CodePlugin = class {
|
|
|
3113
3424
|
execute: () => {
|
|
3114
3425
|
instance.print?.();
|
|
3115
3426
|
}
|
|
3427
|
+
},
|
|
3428
|
+
{
|
|
3429
|
+
id: "open-window",
|
|
3430
|
+
icon: "open-window",
|
|
3431
|
+
label: "Open in Separate Full Window",
|
|
3432
|
+
type: "button",
|
|
3433
|
+
group: "actions",
|
|
3434
|
+
execute: () => {
|
|
3435
|
+
instance.openInSeparateWindow?.();
|
|
3436
|
+
}
|
|
3116
3437
|
}
|
|
3117
3438
|
);
|
|
3118
3439
|
return actions;
|
|
@@ -4281,6 +4602,14 @@ var RtfPlugin = class {
|
|
|
4281
4602
|
type: "button",
|
|
4282
4603
|
group: "actions",
|
|
4283
4604
|
execute: () => instance.print?.()
|
|
4605
|
+
},
|
|
4606
|
+
{
|
|
4607
|
+
id: "open-window",
|
|
4608
|
+
icon: "open-window",
|
|
4609
|
+
label: "Open in Separate Full Window",
|
|
4610
|
+
type: "button",
|
|
4611
|
+
group: "actions",
|
|
4612
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
4284
4613
|
}
|
|
4285
4614
|
);
|
|
4286
4615
|
return actions;
|
|
@@ -4333,59 +4662,54 @@ var RtfPlugin = class {
|
|
|
4333
4662
|
}
|
|
4334
4663
|
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
4335
4664
|
const htmlElements = await doc.render();
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
const secH = singleEl.offsetHeight || singleEl.scrollHeight;
|
|
4341
|
-
if (secH > 1300 && children.length > 1) {
|
|
4342
|
-
const childHeights = children.map((c) => {
|
|
4343
|
-
const rectH = c.getBoundingClientRect().height;
|
|
4344
|
-
const offH = c.offsetHeight;
|
|
4345
|
-
const textLen = c.textContent?.trim().length || 0;
|
|
4346
|
-
const estH = Math.max(24, Math.ceil(textLen / 80) * 22 + 16);
|
|
4347
|
-
return Math.max(rectH, offH, estH);
|
|
4348
|
-
});
|
|
4349
|
-
wrapper.innerHTML = "";
|
|
4350
|
-
const createRtfCard = () => {
|
|
4351
|
-
const card = document.createElement("div");
|
|
4352
|
-
card.className = "fp-rtf-page-card";
|
|
4353
|
-
card.style.backgroundColor = "#ffffff";
|
|
4354
|
-
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
4355
|
-
card.style.borderRadius = "4px";
|
|
4356
|
-
card.style.padding = "72px 56px";
|
|
4357
|
-
card.style.width = "816px";
|
|
4358
|
-
card.style.minHeight = "1056px";
|
|
4359
|
-
card.style.boxSizing = "border-box";
|
|
4360
|
-
card.style.marginBottom = "24px";
|
|
4361
|
-
return card;
|
|
4362
|
-
};
|
|
4363
|
-
let curCard = createRtfCard();
|
|
4364
|
-
wrapper.appendChild(curCard);
|
|
4365
|
-
pageElements = [curCard];
|
|
4366
|
-
let curH = 0;
|
|
4367
|
-
const maxH = 920;
|
|
4368
|
-
for (let i = 0; i < children.length; i++) {
|
|
4369
|
-
const child = children[i];
|
|
4370
|
-
const chH = childHeights[i];
|
|
4371
|
-
curCard.appendChild(child);
|
|
4372
|
-
curH += chH;
|
|
4373
|
-
if (curH >= maxH && i < children.length - 1) {
|
|
4374
|
-
curCard = createRtfCard();
|
|
4375
|
-
wrapper.appendChild(curCard);
|
|
4376
|
-
pageElements.push(curCard);
|
|
4377
|
-
curH = 0;
|
|
4378
|
-
}
|
|
4379
|
-
}
|
|
4665
|
+
const contentNodes = [];
|
|
4666
|
+
for (const item of htmlElements) {
|
|
4667
|
+
if (item.children && item.children.length > 0 && !item.tagName.toLowerCase().startsWith("table")) {
|
|
4668
|
+
contentNodes.push(...Array.from(item.children));
|
|
4380
4669
|
} else {
|
|
4381
|
-
|
|
4670
|
+
contentNodes.push(item);
|
|
4382
4671
|
}
|
|
4383
|
-
}
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4672
|
+
}
|
|
4673
|
+
wrapper.innerHTML = "";
|
|
4674
|
+
contentNodes.forEach((node) => wrapper.appendChild(node));
|
|
4675
|
+
const childHeights = contentNodes.map((c) => {
|
|
4676
|
+
const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
|
|
4677
|
+
const offH = c.offsetHeight || 0;
|
|
4678
|
+
const textLen = c.textContent?.trim().length || 0;
|
|
4679
|
+
const estH = Math.max(24, Math.ceil(textLen / 75) * 22 + 14);
|
|
4680
|
+
return Math.max(rectH, offH, estH);
|
|
4681
|
+
});
|
|
4682
|
+
wrapper.innerHTML = "";
|
|
4683
|
+
const createRtfCard = () => {
|
|
4684
|
+
const card = document.createElement("div");
|
|
4685
|
+
card.className = "fp-rtf-page-card";
|
|
4686
|
+
card.style.backgroundColor = "#ffffff";
|
|
4687
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
4688
|
+
card.style.borderRadius = "4px";
|
|
4689
|
+
card.style.padding = "72px 56px";
|
|
4690
|
+
card.style.width = "816px";
|
|
4691
|
+
card.style.minHeight = "1056px";
|
|
4692
|
+
card.style.boxSizing = "border-box";
|
|
4693
|
+
card.style.marginBottom = "24px";
|
|
4694
|
+
card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4695
|
+
card.style.lineHeight = "1.6";
|
|
4696
|
+
return card;
|
|
4697
|
+
};
|
|
4698
|
+
let curCard = createRtfCard();
|
|
4699
|
+
wrapper.appendChild(curCard);
|
|
4700
|
+
pageElements = [curCard];
|
|
4701
|
+
let curH = 0;
|
|
4702
|
+
const maxH = 912;
|
|
4703
|
+
for (let i = 0; i < contentNodes.length; i++) {
|
|
4704
|
+
const child = contentNodes[i];
|
|
4705
|
+
const chH = childHeights[i];
|
|
4706
|
+
curCard.appendChild(child);
|
|
4707
|
+
curH += chH;
|
|
4708
|
+
if (curH >= maxH && i < contentNodes.length - 1) {
|
|
4709
|
+
curCard = createRtfCard();
|
|
4710
|
+
wrapper.appendChild(curCard);
|
|
4711
|
+
pageElements.push(curCard);
|
|
4712
|
+
curH = 0;
|
|
4389
4713
|
}
|
|
4390
4714
|
}
|
|
4391
4715
|
} catch (err) {
|
|
@@ -4754,6 +5078,14 @@ var OpenDocumentPlugin = class {
|
|
|
4754
5078
|
type: "button",
|
|
4755
5079
|
group: "actions",
|
|
4756
5080
|
execute: () => instance.print?.()
|
|
5081
|
+
},
|
|
5082
|
+
{
|
|
5083
|
+
id: "open-window",
|
|
5084
|
+
icon: "open-window",
|
|
5085
|
+
label: "Open in Separate Full Window",
|
|
5086
|
+
type: "button",
|
|
5087
|
+
group: "actions",
|
|
5088
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
4757
5089
|
}
|
|
4758
5090
|
);
|
|
4759
5091
|
return actions;
|
|
@@ -5342,6 +5674,14 @@ var DocPlugin = class {
|
|
|
5342
5674
|
type: "button",
|
|
5343
5675
|
group: "actions",
|
|
5344
5676
|
execute: () => instance.print?.()
|
|
5677
|
+
},
|
|
5678
|
+
{
|
|
5679
|
+
id: "open-window",
|
|
5680
|
+
icon: "open-window",
|
|
5681
|
+
label: "Open in Separate Full Window",
|
|
5682
|
+
type: "button",
|
|
5683
|
+
group: "actions",
|
|
5684
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
5345
5685
|
}
|
|
5346
5686
|
);
|
|
5347
5687
|
return actions;
|
|
@@ -5633,9 +5973,25 @@ var DocPlugin = class {
|
|
|
5633
5973
|
heuristicTextExtraction(buffer) {
|
|
5634
5974
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
5635
5975
|
}
|
|
5976
|
+
cleanWordDocFields(text) {
|
|
5977
|
+
if (!text) return "";
|
|
5978
|
+
let cleaned = text.replace(
|
|
5979
|
+
/\x13\s*HYPERLINK\s*"?([^"\x14]+)"?\s*\x14([\s\S]*?)\x15/gi,
|
|
5980
|
+
(_match, url, label) => {
|
|
5981
|
+
const cleanUrl = url.trim();
|
|
5982
|
+
const cleanLabel = label.trim() || cleanUrl;
|
|
5983
|
+
return `<a href="${cleanUrl}" target="_blank" rel="noopener noreferrer" style="color: #2563eb; text-decoration: underline;">${cleanLabel}</a>`;
|
|
5984
|
+
}
|
|
5985
|
+
);
|
|
5986
|
+
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g, "$1");
|
|
5987
|
+
cleaned = cleaned.replace(/\x13[^\x15]*\x15/g, "");
|
|
5988
|
+
cleaned = cleaned.replace(/[\x13\x14\x15]/g, "");
|
|
5989
|
+
return cleaned;
|
|
5990
|
+
}
|
|
5636
5991
|
splitIntoPages(text) {
|
|
5637
5992
|
if (!text) return [""];
|
|
5638
|
-
const
|
|
5993
|
+
const cleanedText = this.cleanWordDocFields(text);
|
|
5994
|
+
const normalized = cleanedText.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ");
|
|
5639
5995
|
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);
|
|
5640
5996
|
if (explicitParts.length === 0) explicitParts.push(normalized);
|
|
5641
5997
|
const maxLinesPerPage = 32;
|
|
@@ -5646,7 +6002,8 @@ var DocPlugin = class {
|
|
|
5646
6002
|
let currentLines = [];
|
|
5647
6003
|
let count = 0;
|
|
5648
6004
|
for (const line of lines) {
|
|
5649
|
-
const
|
|
6005
|
+
const plainLine = line.replace(/<[^>]+>/g, "");
|
|
6006
|
+
const vLines = Math.max(1, Math.ceil((plainLine.length || 1) / charsPerLine));
|
|
5650
6007
|
if (count + vLines > maxLinesPerPage && currentLines.length > 0) {
|
|
5651
6008
|
finalPages.push(currentLines.join("\n"));
|
|
5652
6009
|
currentLines = [];
|
|
@@ -5722,25 +6079,26 @@ var DocPlugin = class {
|
|
|
5722
6079
|
i++;
|
|
5723
6080
|
continue;
|
|
5724
6081
|
}
|
|
6082
|
+
const sanitizeOptions = { ADD_TAGS: ["a"], ADD_ATTR: ["href", "target", "rel", "style"] };
|
|
5725
6083
|
if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
|
|
5726
6084
|
if (inList) {
|
|
5727
6085
|
html += "</ul>";
|
|
5728
6086
|
inList = false;
|
|
5729
6087
|
}
|
|
5730
|
-
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>`;
|
|
6088
|
+
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>`;
|
|
5731
6089
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
5732
6090
|
if (!inList) {
|
|
5733
6091
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
5734
6092
|
inList = true;
|
|
5735
6093
|
}
|
|
5736
6094
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
5737
|
-
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6__default.default.sanitize(bulletText)}</li>`;
|
|
6095
|
+
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6__default.default.sanitize(bulletText, sanitizeOptions)}</li>`;
|
|
5738
6096
|
} else {
|
|
5739
6097
|
if (inList) {
|
|
5740
6098
|
html += "</ul>";
|
|
5741
6099
|
inList = false;
|
|
5742
6100
|
}
|
|
5743
|
-
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6__default.default.sanitize(line)}</p>`;
|
|
6101
|
+
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6__default.default.sanitize(line, sanitizeOptions)}</p>`;
|
|
5744
6102
|
}
|
|
5745
6103
|
i++;
|
|
5746
6104
|
}
|