@files-preview-app/preview-file 1.2.8 → 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 +563 -111
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +562 -111
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +606 -111
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +604 -112
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +563 -111
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +562 -111
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +563 -111
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +562 -111
- package/dist/vue.js.map +1 -1
- package/package.json +169 -179
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) {
|
|
@@ -417,16 +418,21 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
417
418
|
metadata.mimeType = source.type || void 0;
|
|
418
419
|
metadata.extension = extractExtension(source.name);
|
|
419
420
|
buffer = await source.arrayBuffer();
|
|
420
|
-
} else if (source instanceof Blob) {
|
|
421
|
+
} else if (source instanceof Blob || source && typeof source.arrayBuffer === "function" && typeof source.size === "number") {
|
|
421
422
|
metadata.size = source.size;
|
|
422
423
|
metadata.mimeType = source.type || void 0;
|
|
424
|
+
if (source.name) {
|
|
425
|
+
metadata.name = source.name;
|
|
426
|
+
metadata.extension = extractExtension(source.name);
|
|
427
|
+
}
|
|
423
428
|
buffer = await source.arrayBuffer();
|
|
424
|
-
} else if (source instanceof ArrayBuffer) {
|
|
429
|
+
} else if (source instanceof ArrayBuffer || Object.prototype.toString.call(source) === "[object ArrayBuffer]" || source && typeof source.byteLength === "number" && typeof source.slice === "function") {
|
|
425
430
|
buffer = source;
|
|
426
|
-
} else if (source instanceof Uint8Array) {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
431
|
+
} else if (source instanceof Uint8Array || ArrayBuffer.isView(source)) {
|
|
432
|
+
const view = source;
|
|
433
|
+
buffer = view.buffer.slice(
|
|
434
|
+
view.byteOffset,
|
|
435
|
+
view.byteOffset + view.byteLength
|
|
430
436
|
);
|
|
431
437
|
} else {
|
|
432
438
|
throw new Error("Unsupported file source type");
|
|
@@ -511,6 +517,45 @@ function createElement(tag, attrs, ...children) {
|
|
|
511
517
|
}
|
|
512
518
|
return el;
|
|
513
519
|
}
|
|
520
|
+
var DB_NAME = "PreviewFileTransferDB";
|
|
521
|
+
var DB_STORE = "transfers";
|
|
522
|
+
function openDB() {
|
|
523
|
+
return new Promise((resolve, reject) => {
|
|
524
|
+
if (typeof indexedDB === "undefined") {
|
|
525
|
+
return reject(new Error("IndexedDB is not available"));
|
|
526
|
+
}
|
|
527
|
+
const req = indexedDB.open(DB_NAME, 1);
|
|
528
|
+
req.onupgradeneeded = () => {
|
|
529
|
+
const db = req.result;
|
|
530
|
+
if (!db.objectStoreNames.contains(DB_STORE)) {
|
|
531
|
+
db.createObjectStore(DB_STORE, { keyPath: "id" });
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
req.onsuccess = () => resolve(req.result);
|
|
535
|
+
req.onerror = () => reject(req.error);
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
async function saveTransferPayload(id, payload) {
|
|
539
|
+
if (typeof window !== "undefined") {
|
|
540
|
+
try {
|
|
541
|
+
window[id] = payload;
|
|
542
|
+
window.__lastTransfer = payload;
|
|
543
|
+
} catch {
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
try {
|
|
547
|
+
const db = await openDB();
|
|
548
|
+
return new Promise((resolve, reject) => {
|
|
549
|
+
const tx = db.transaction(DB_STORE, "readwrite");
|
|
550
|
+
const store = tx.objectStore(DB_STORE);
|
|
551
|
+
store.put({ id, ...payload, timestamp: Date.now() });
|
|
552
|
+
tx.oncomplete = () => resolve();
|
|
553
|
+
tx.onerror = () => reject(tx.error);
|
|
554
|
+
});
|
|
555
|
+
} catch (e) {
|
|
556
|
+
console.warn("[saveTransferPayload] IndexedDB store warning:", e);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
514
559
|
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
560
|
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
561
|
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 +575,7 @@ var ICON_COPY = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" str
|
|
|
530
575
|
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
576
|
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
577
|
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>`;
|
|
578
|
+
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
579
|
var ICON_MAP = {
|
|
534
580
|
"zoom-in": ICON_ZOOM_IN,
|
|
535
581
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -556,7 +602,9 @@ var ICON_MAP = {
|
|
|
556
602
|
"forward-10": ICON_FAST_FORWARD,
|
|
557
603
|
"rewind": ICON_REWIND,
|
|
558
604
|
"replay-10": ICON_REWIND,
|
|
559
|
-
"speed": ICON_SPEED
|
|
605
|
+
"speed": ICON_SPEED,
|
|
606
|
+
"open-window": ICON_EXTERNAL_WINDOW,
|
|
607
|
+
"external-window": ICON_EXTERNAL_WINDOW
|
|
560
608
|
};
|
|
561
609
|
var ToolbarController = class {
|
|
562
610
|
el;
|
|
@@ -773,7 +821,7 @@ var ThumbnailPanel = class {
|
|
|
773
821
|
}
|
|
774
822
|
}
|
|
775
823
|
};
|
|
776
|
-
var FilePreviewViewer = class {
|
|
824
|
+
var FilePreviewViewer = class _FilePreviewViewer {
|
|
777
825
|
plugins = [];
|
|
778
826
|
activeInstance = null;
|
|
779
827
|
abortController = null;
|
|
@@ -810,6 +858,7 @@ var FilePreviewViewer = class {
|
|
|
810
858
|
* Preview a file in the given container element.
|
|
811
859
|
*/
|
|
812
860
|
async preview(container, source, options = {}) {
|
|
861
|
+
this.currentOptions = options;
|
|
813
862
|
this.abort();
|
|
814
863
|
this.abortController = new AbortController();
|
|
815
864
|
const { signal } = this.abortController;
|
|
@@ -819,7 +868,10 @@ var FilePreviewViewer = class {
|
|
|
819
868
|
this.showLoading();
|
|
820
869
|
try {
|
|
821
870
|
const { buffer, metadata } = await sourceToArrayBuffer(source, signal);
|
|
822
|
-
|
|
871
|
+
if (options.metadata) {
|
|
872
|
+
Object.assign(metadata, options.metadata);
|
|
873
|
+
}
|
|
874
|
+
this.currentBuffer = buffer.slice(0);
|
|
823
875
|
this.currentMetadata = metadata;
|
|
824
876
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
825
877
|
const fileInfo = { metadata, buffer };
|
|
@@ -849,6 +901,7 @@ var FilePreviewViewer = class {
|
|
|
849
901
|
}
|
|
850
902
|
});
|
|
851
903
|
this.activeInstance = instance;
|
|
904
|
+
instance.openInSeparateWindow = () => this.openInSeparateWindow();
|
|
852
905
|
this.hideLoading();
|
|
853
906
|
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
854
907
|
if (options.showToolbar !== false && this.toolbar) {
|
|
@@ -858,26 +911,16 @@ var FilePreviewViewer = class {
|
|
|
858
911
|
actions.push({
|
|
859
912
|
id: "fullscreen",
|
|
860
913
|
icon: "fullscreen",
|
|
861
|
-
label: "
|
|
914
|
+
label: "Fullscreen",
|
|
862
915
|
type: "button",
|
|
863
916
|
group: "view",
|
|
864
|
-
execute:
|
|
917
|
+
execute: () => {
|
|
865
918
|
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
|
-
}
|
|
919
|
+
if (!document.fullscreenElement) {
|
|
920
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
921
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
876
922
|
} else {
|
|
877
|
-
|
|
878
|
-
await document.exitFullscreen().catch(() => {
|
|
879
|
-
});
|
|
880
|
-
}
|
|
923
|
+
document.exitFullscreen?.();
|
|
881
924
|
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
882
925
|
}
|
|
883
926
|
} catch {
|
|
@@ -889,6 +932,28 @@ var FilePreviewViewer = class {
|
|
|
889
932
|
}
|
|
890
933
|
});
|
|
891
934
|
}
|
|
935
|
+
const openWinAction = actions.find((a) => a.id === "open-window");
|
|
936
|
+
if (openWinAction) {
|
|
937
|
+
if (options?._isSeparateWindow) {
|
|
938
|
+
const idx = actions.indexOf(openWinAction);
|
|
939
|
+
if (idx !== -1) actions.splice(idx, 1);
|
|
940
|
+
} else {
|
|
941
|
+
openWinAction.execute = () => {
|
|
942
|
+
this.openInSeparateWindow();
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
} else if (!options?._isSeparateWindow) {
|
|
946
|
+
actions.push({
|
|
947
|
+
id: "open-window",
|
|
948
|
+
icon: "open-window",
|
|
949
|
+
label: "Open in Separate Full Window",
|
|
950
|
+
type: "button",
|
|
951
|
+
group: "actions",
|
|
952
|
+
execute: () => {
|
|
953
|
+
this.openInSeparateWindow();
|
|
954
|
+
}
|
|
955
|
+
});
|
|
956
|
+
}
|
|
892
957
|
this.toolbar.update(actions);
|
|
893
958
|
this.toolbar.show();
|
|
894
959
|
}
|
|
@@ -921,6 +986,104 @@ var FilePreviewViewer = class {
|
|
|
921
986
|
throw error;
|
|
922
987
|
}
|
|
923
988
|
}
|
|
989
|
+
/**
|
|
990
|
+
* Opens the current file preview in a separate full browser window.
|
|
991
|
+
*/
|
|
992
|
+
openInSeparateWindow() {
|
|
993
|
+
if (!this.currentBuffer) {
|
|
994
|
+
console.warn("[FilePreviewViewer] No active file buffer to open in separate window");
|
|
995
|
+
return null;
|
|
996
|
+
}
|
|
997
|
+
if (this.currentOptions.onOpenSeparateWindow) {
|
|
998
|
+
return this.currentOptions.onOpenSeparateWindow({
|
|
999
|
+
buffer: this.currentBuffer,
|
|
1000
|
+
metadata: this.currentMetadata || { name: "Document" },
|
|
1001
|
+
options: this.currentOptions
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
const transferId = "fp_win_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8);
|
|
1005
|
+
let clonedBuffer;
|
|
1006
|
+
try {
|
|
1007
|
+
clonedBuffer = this.currentBuffer.slice(0);
|
|
1008
|
+
} catch {
|
|
1009
|
+
clonedBuffer = this.currentBuffer;
|
|
1010
|
+
}
|
|
1011
|
+
const payload = {
|
|
1012
|
+
buffer: clonedBuffer,
|
|
1013
|
+
metadata: this.currentMetadata ? { ...this.currentMetadata } : void 0,
|
|
1014
|
+
options: { ...this.currentOptions, _isSeparateWindow: true }
|
|
1015
|
+
};
|
|
1016
|
+
if (typeof window !== "undefined") {
|
|
1017
|
+
try {
|
|
1018
|
+
window[transferId] = payload;
|
|
1019
|
+
window.__lastTransfer = payload;
|
|
1020
|
+
} catch {
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
saveTransferPayload(transferId, payload).catch((err) => {
|
|
1024
|
+
console.warn("[FilePreviewViewer] Transfer payload save warning:", err);
|
|
1025
|
+
});
|
|
1026
|
+
let targetUrl = null;
|
|
1027
|
+
if (this.currentOptions.standaloneViewerUrl) {
|
|
1028
|
+
const u = new URL(this.currentOptions.standaloneViewerUrl, window.location.href);
|
|
1029
|
+
u.searchParams.set("mode", "fullscreen");
|
|
1030
|
+
u.searchParams.set("transferId", transferId);
|
|
1031
|
+
targetUrl = u.toString();
|
|
1032
|
+
} else if (typeof window !== "undefined" && window.location?.href && !window.location.href.startsWith("about:")) {
|
|
1033
|
+
const u = new URL(window.location.href);
|
|
1034
|
+
u.searchParams.set("mode", "fullscreen");
|
|
1035
|
+
u.searchParams.set("transferId", transferId);
|
|
1036
|
+
targetUrl = u.toString();
|
|
1037
|
+
}
|
|
1038
|
+
if (targetUrl) {
|
|
1039
|
+
const newWin2 = window.open(targetUrl, "_blank");
|
|
1040
|
+
if (!newWin2) {
|
|
1041
|
+
alert("Popup blocker prevented opening the preview in a separate window. Please allow popups for this site.");
|
|
1042
|
+
return null;
|
|
1043
|
+
}
|
|
1044
|
+
return newWin2;
|
|
1045
|
+
}
|
|
1046
|
+
const title = (this.currentMetadata?.name || "Document Preview") + " - Full Preview";
|
|
1047
|
+
const newWin = window.open("", "_blank");
|
|
1048
|
+
if (!newWin) {
|
|
1049
|
+
alert("Popup blocker prevented opening the preview in a separate window. Please allow popups for this site.");
|
|
1050
|
+
return null;
|
|
1051
|
+
}
|
|
1052
|
+
newWin.document.title = title;
|
|
1053
|
+
newWin.document.body.style.margin = "0";
|
|
1054
|
+
newWin.document.body.style.padding = "0";
|
|
1055
|
+
newWin.document.body.style.width = "100vw";
|
|
1056
|
+
newWin.document.body.style.height = "100vh";
|
|
1057
|
+
newWin.document.body.style.overflow = "hidden";
|
|
1058
|
+
newWin.document.body.style.backgroundColor = "#f8fafc";
|
|
1059
|
+
const headNodes = document.querySelectorAll('link[rel="stylesheet"], style');
|
|
1060
|
+
headNodes.forEach((node) => {
|
|
1061
|
+
newWin.document.head.appendChild(node.cloneNode(true));
|
|
1062
|
+
});
|
|
1063
|
+
const root = newWin.document.createElement("div");
|
|
1064
|
+
root.id = "full-window-preview-root";
|
|
1065
|
+
root.style.width = "100%";
|
|
1066
|
+
root.style.height = "100%";
|
|
1067
|
+
root.style.overflow = "hidden";
|
|
1068
|
+
newWin.document.body.appendChild(root);
|
|
1069
|
+
const separateViewer = new _FilePreviewViewer();
|
|
1070
|
+
for (const plugin of this.plugins) {
|
|
1071
|
+
separateViewer.registerPlugin(plugin);
|
|
1072
|
+
}
|
|
1073
|
+
separateViewer.preview(root, this.currentBuffer.slice(0), {
|
|
1074
|
+
...this.currentOptions,
|
|
1075
|
+
showToolbar: true,
|
|
1076
|
+
toolbarPosition: "top",
|
|
1077
|
+
metadata: this.currentMetadata || void 0,
|
|
1078
|
+
_isSeparateWindow: true
|
|
1079
|
+
}).catch((err) => {
|
|
1080
|
+
console.error("[FilePreviewViewer] Error rendering in separate window:", err);
|
|
1081
|
+
});
|
|
1082
|
+
newWin.addEventListener("beforeunload", () => {
|
|
1083
|
+
separateViewer.destroy();
|
|
1084
|
+
});
|
|
1085
|
+
return newWin;
|
|
1086
|
+
}
|
|
924
1087
|
/**
|
|
925
1088
|
* Subscribe to viewer events.
|
|
926
1089
|
*/
|
|
@@ -1326,8 +1489,20 @@ var CfbfReader = class {
|
|
|
1326
1489
|
}
|
|
1327
1490
|
};
|
|
1328
1491
|
if (typeof window !== "undefined" && pdfjsLib__namespace.GlobalWorkerOptions) {
|
|
1329
|
-
if (!pdfjsLib__namespace.GlobalWorkerOptions.workerSrc) {
|
|
1330
|
-
|
|
1492
|
+
if (!pdfjsLib__namespace.GlobalWorkerOptions.workerPort && !pdfjsLib__namespace.GlobalWorkerOptions.workerSrc) {
|
|
1493
|
+
const customWorker = window.__PDF_WORKER_SRC__;
|
|
1494
|
+
if (customWorker) {
|
|
1495
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = customWorker;
|
|
1496
|
+
} else {
|
|
1497
|
+
try {
|
|
1498
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerPort = new Worker(
|
|
1499
|
+
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))),
|
|
1500
|
+
{ type: "module" }
|
|
1501
|
+
);
|
|
1502
|
+
} catch {
|
|
1503
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = "./pdf.worker.min.mjs";
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1331
1506
|
}
|
|
1332
1507
|
}
|
|
1333
1508
|
var PdfPlugin = class {
|
|
@@ -1421,6 +1596,14 @@ var PdfPlugin = class {
|
|
|
1421
1596
|
type: "button",
|
|
1422
1597
|
group: "actions",
|
|
1423
1598
|
execute: () => instance.print?.()
|
|
1599
|
+
},
|
|
1600
|
+
{
|
|
1601
|
+
id: "open-window",
|
|
1602
|
+
icon: "open-window",
|
|
1603
|
+
label: "Open in Separate Full Window",
|
|
1604
|
+
type: "button",
|
|
1605
|
+
group: "actions",
|
|
1606
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
1424
1607
|
}
|
|
1425
1608
|
];
|
|
1426
1609
|
}
|
|
@@ -1470,18 +1653,21 @@ var PdfPlugin = class {
|
|
|
1470
1653
|
indicator.style.pointerEvents = "none";
|
|
1471
1654
|
container.appendChild(indicator);
|
|
1472
1655
|
ctx.container.appendChild(container);
|
|
1656
|
+
const standardFontsUrl = typeof window !== "undefined" && window.__PDF_STANDARD_FONTS_URL__ || "./standard_fonts/";
|
|
1657
|
+
const cmapsUrl = typeof window !== "undefined" && window.__PDF_CMAPS_URL__ || "./cmaps/";
|
|
1473
1658
|
const loadingTask = pdfjsLib__namespace.getDocument({
|
|
1474
|
-
data: new Uint8Array(ctx.buffer),
|
|
1475
|
-
cMapUrl:
|
|
1659
|
+
data: new Uint8Array(ctx.buffer.slice(0)),
|
|
1660
|
+
cMapUrl: cmapsUrl,
|
|
1476
1661
|
cMapPacked: true,
|
|
1477
|
-
standardFontDataUrl:
|
|
1662
|
+
standardFontDataUrl: standardFontsUrl,
|
|
1663
|
+
verbosity: 0
|
|
1478
1664
|
});
|
|
1479
1665
|
const pdfDoc = await loadingTask.promise;
|
|
1480
1666
|
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1481
1667
|
let currentPage = 1;
|
|
1482
1668
|
let zoomScale = 1;
|
|
1483
1669
|
let rotation = 0;
|
|
1484
|
-
let fitMode = "
|
|
1670
|
+
let fitMode = "page";
|
|
1485
1671
|
let currentRenderTask = null;
|
|
1486
1672
|
const renderPage = async (pageNum) => {
|
|
1487
1673
|
if (currentRenderTask) {
|
|
@@ -1501,15 +1687,15 @@ var PdfPlugin = class {
|
|
|
1501
1687
|
const containerWidth = container.clientWidth || 900;
|
|
1502
1688
|
const containerHeight = container.clientHeight || 700;
|
|
1503
1689
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1504
|
-
const availWidth = Math.max(
|
|
1505
|
-
const availHeight = Math.max(
|
|
1690
|
+
const availWidth = Math.max(320, containerWidth - 48);
|
|
1691
|
+
const availHeight = Math.max(550, containerHeight - 88);
|
|
1506
1692
|
const scaleW = availWidth / unscaledVp.width;
|
|
1507
1693
|
const scaleH = availHeight / unscaledVp.height;
|
|
1508
1694
|
let fitScale;
|
|
1509
1695
|
if (fitMode === "page") {
|
|
1510
|
-
fitScale = Math.max(0.
|
|
1696
|
+
fitScale = Math.max(0.4, Math.min(scaleW, scaleH));
|
|
1511
1697
|
} else {
|
|
1512
|
-
fitScale = Math.max(0.65, Math.min(1.
|
|
1698
|
+
fitScale = Math.max(0.65, Math.min(1.25, scaleW));
|
|
1513
1699
|
}
|
|
1514
1700
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1515
1701
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
@@ -1535,7 +1721,7 @@ var PdfPlugin = class {
|
|
|
1535
1721
|
currentRenderTask = null;
|
|
1536
1722
|
}
|
|
1537
1723
|
};
|
|
1538
|
-
|
|
1724
|
+
renderPage(1);
|
|
1539
1725
|
let resizeTimer = null;
|
|
1540
1726
|
const resizeObserver = new ResizeObserver(() => {
|
|
1541
1727
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
@@ -1579,7 +1765,7 @@ var PdfPlugin = class {
|
|
|
1579
1765
|
renderPage(currentPage);
|
|
1580
1766
|
},
|
|
1581
1767
|
fitToPage: () => {
|
|
1582
|
-
fitMode = fitMode === "
|
|
1768
|
+
fitMode = fitMode === "page" ? "width" : "page";
|
|
1583
1769
|
zoomScale = 1;
|
|
1584
1770
|
rotation = 0;
|
|
1585
1771
|
renderPage(currentPage);
|
|
@@ -1596,6 +1782,7 @@ var PdfPlugin = class {
|
|
|
1596
1782
|
getPageCount: () => totalPages,
|
|
1597
1783
|
getCurrentPage: () => currentPage,
|
|
1598
1784
|
goToPage: (page) => {
|
|
1785
|
+
container.scrollTop = 0;
|
|
1599
1786
|
renderPage(page);
|
|
1600
1787
|
},
|
|
1601
1788
|
download: () => {
|
|
@@ -2055,6 +2242,14 @@ var DocxPlugin = class {
|
|
|
2055
2242
|
type: "button",
|
|
2056
2243
|
group: "actions",
|
|
2057
2244
|
execute: () => instance.print?.()
|
|
2245
|
+
},
|
|
2246
|
+
{
|
|
2247
|
+
id: "open-window",
|
|
2248
|
+
icon: "open-window",
|
|
2249
|
+
label: "Open in Separate Full Window",
|
|
2250
|
+
type: "button",
|
|
2251
|
+
group: "actions",
|
|
2252
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
2058
2253
|
}
|
|
2059
2254
|
);
|
|
2060
2255
|
return actions;
|
|
@@ -2100,13 +2295,45 @@ var DocxPlugin = class {
|
|
|
2100
2295
|
ignoreFonts: true,
|
|
2101
2296
|
// Avoid crashes on embedded obfuscated fonts
|
|
2102
2297
|
breakPages: true,
|
|
2103
|
-
experimental: true
|
|
2298
|
+
experimental: true,
|
|
2299
|
+
ignoreLastRenderedPageBreak: false,
|
|
2300
|
+
// Honor Word's exact page breaks!
|
|
2301
|
+
renderHeaders: true,
|
|
2302
|
+
renderFooters: true,
|
|
2303
|
+
renderFootnotes: true,
|
|
2304
|
+
renderEndnotes: true,
|
|
2305
|
+
useBase64URL: true
|
|
2104
2306
|
});
|
|
2105
2307
|
if (!ctx.container.contains(wrapper)) {
|
|
2106
2308
|
ctx.container.appendChild(wrapper);
|
|
2107
2309
|
}
|
|
2108
2310
|
if (wrapper.children.length > 0 && (wrapper.textContent?.trim().length ?? 0) > 0) {
|
|
2109
2311
|
renderedSuccessfully = true;
|
|
2312
|
+
try {
|
|
2313
|
+
const unzipped = fflate.unzipSync(new Uint8Array(ctx.buffer));
|
|
2314
|
+
const chartKeys = Object.keys(unzipped).filter((k) => k.replace(/^[./\\]+/, "").toLowerCase().startsWith("word/charts/chart") && k.endsWith(".xml")).sort();
|
|
2315
|
+
if (chartKeys.length > 0) {
|
|
2316
|
+
const allDivs = Array.from(wrapper.querySelectorAll("div"));
|
|
2317
|
+
const emptyContainers = allDivs.filter((div) => {
|
|
2318
|
+
const st = div.getAttribute("style") || "";
|
|
2319
|
+
return st.includes("width:") && st.includes("height:") && div.children.length === 0 && (div.textContent?.trim().length ?? 0) === 0;
|
|
2320
|
+
});
|
|
2321
|
+
chartKeys.forEach((cKey, idx) => {
|
|
2322
|
+
const target = emptyContainers[idx];
|
|
2323
|
+
if (target) {
|
|
2324
|
+
const xmlStr = fflate.strFromU8(unzipped[cKey]);
|
|
2325
|
+
const svg = this.parseAndRenderChartSvg(xmlStr);
|
|
2326
|
+
if (svg) {
|
|
2327
|
+
target.innerHTML = svg;
|
|
2328
|
+
target.style.display = "block";
|
|
2329
|
+
target.style.margin = "12px auto";
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
});
|
|
2333
|
+
}
|
|
2334
|
+
} catch (chartErr) {
|
|
2335
|
+
console.warn("[DocxPlugin] Non-critical error rendering DrawingML charts:", chartErr);
|
|
2336
|
+
}
|
|
2110
2337
|
}
|
|
2111
2338
|
} catch (err) {
|
|
2112
2339
|
console.warn("[DocxPlugin] docx-preview failed, triggering native fallback:", err);
|
|
@@ -2121,11 +2348,14 @@ var DocxPlugin = class {
|
|
|
2121
2348
|
renderedSuccessfully = true;
|
|
2122
2349
|
} catch (fallbackErr) {
|
|
2123
2350
|
console.error("[DocxPlugin] Native fallback failed:", fallbackErr);
|
|
2351
|
+
const isCorrupt = fallbackErr?.message?.includes("invalid zip") || fallbackErr?.message?.includes("corrupted");
|
|
2124
2352
|
wrapper.innerHTML = `
|
|
2125
|
-
<div style="text-align:center; padding: 48px; background: #fff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.06);">
|
|
2126
|
-
<div style="font-size:48px; margin-bottom: 16px;"
|
|
2127
|
-
<h3 style="margin: 0 0 8px; color: #1e293b;">${ctx.metadata.name || "Word Document"}</h3>
|
|
2128
|
-
<p style="color: #64748b; margin: 0;
|
|
2353
|
+
<div style="text-align:center; padding: 48px 32px; background: #fff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.06); max-width: 600px; margin: 40px auto;">
|
|
2354
|
+
<div style="font-size:48px; margin-bottom: 16px;">${isCorrupt ? "\u26A0\uFE0F" : "\u{1F4C4}"}</div>
|
|
2355
|
+
<h3 style="margin: 0 0 8px; color: #1e293b; font-size: 18px;">${ctx.metadata.name || "Word Document"}</h3>
|
|
2356
|
+
<p style="color: #64748b; margin: 0 0 16px; font-size: 14px; line-height: 1.5;">
|
|
2357
|
+
${isCorrupt ? "This document appears to be corrupted or contains invalid archive data and cannot be opened (matches Microsoft Word on Windows)." : "Could not render document content. The file structure may be damaged."}
|
|
2358
|
+
</p>
|
|
2129
2359
|
</div>
|
|
2130
2360
|
`;
|
|
2131
2361
|
if (!ctx.container.contains(wrapper)) {
|
|
@@ -2135,50 +2365,74 @@ var DocxPlugin = class {
|
|
|
2135
2365
|
}
|
|
2136
2366
|
let sections = Array.from(wrapper.querySelectorAll("section.docx"));
|
|
2137
2367
|
const cards = Array.from(wrapper.querySelectorAll(".fp-docx-page-card"));
|
|
2138
|
-
if (sections.length
|
|
2139
|
-
const
|
|
2140
|
-
const
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
const
|
|
2144
|
-
|
|
2368
|
+
if (sections.length > 0 && cards.length === 0) {
|
|
2369
|
+
const finalSections = [];
|
|
2370
|
+
for (const singleSec of sections) {
|
|
2371
|
+
const contentContainer = singleSec.querySelector("article") || singleSec;
|
|
2372
|
+
const children = Array.from(contentContainer.children);
|
|
2373
|
+
const pageH = singleSec.offsetHeight > 1300 ? 1122 : Math.max(1056, singleSec.offsetHeight);
|
|
2374
|
+
const secH = singleSec.scrollHeight || singleSec.offsetHeight;
|
|
2375
|
+
if (secH > pageH * 1.25 && children.length > 1) {
|
|
2376
|
+
const childHeights = children.map((c) => {
|
|
2377
|
+
const rectH = c.getBoundingClientRect().height;
|
|
2378
|
+
const offH = c.offsetHeight;
|
|
2379
|
+
const textLen = c.textContent?.trim().length || 0;
|
|
2380
|
+
const estH = Math.max(24, Math.ceil(textLen / 80) * 22 + 16);
|
|
2381
|
+
return Math.max(rectH, offH, estH);
|
|
2382
|
+
});
|
|
2145
2383
|
const parent = singleSec.parentElement || wrapper;
|
|
2146
|
-
const
|
|
2147
|
-
|
|
2384
|
+
const headerEl = singleSec.querySelector("header");
|
|
2385
|
+
const footerEl = singleSec.querySelector("footer");
|
|
2386
|
+
contentContainer.innerHTML = "";
|
|
2148
2387
|
singleSec.style.minHeight = `${pageH}px`;
|
|
2149
|
-
singleSec.style.maxHeight = `${pageH}px`;
|
|
2150
|
-
singleSec.style.overflow = "hidden";
|
|
2151
2388
|
singleSec.style.boxSizing = "border-box";
|
|
2389
|
+
let curContent = contentContainer;
|
|
2152
2390
|
let curSec = singleSec;
|
|
2153
2391
|
let curH = 0;
|
|
2154
|
-
const maxH = pageH -
|
|
2392
|
+
const maxH = pageH - 140;
|
|
2393
|
+
finalSections.push(singleSec);
|
|
2155
2394
|
for (let i = 0; i < children.length; i++) {
|
|
2156
2395
|
const child = children[i];
|
|
2157
|
-
|
|
2158
|
-
|
|
2396
|
+
const chH = childHeights[i];
|
|
2397
|
+
curContent.appendChild(child);
|
|
2159
2398
|
curH += chH;
|
|
2160
2399
|
if (curH >= maxH && i < children.length - 1) {
|
|
2161
2400
|
const nextSec = document.createElement("section");
|
|
2162
2401
|
nextSec.className = singleSec.className;
|
|
2163
2402
|
nextSec.style.cssText = singleSec.style.cssText;
|
|
2164
|
-
nextSec.style.width = singleSec.style.width || "816px";
|
|
2165
2403
|
nextSec.style.minHeight = `${pageH}px`;
|
|
2166
|
-
nextSec.style.maxHeight = `${pageH}px`;
|
|
2167
|
-
nextSec.style.overflow = "hidden";
|
|
2168
2404
|
nextSec.style.boxSizing = "border-box";
|
|
2169
2405
|
nextSec.style.backgroundColor = "#ffffff";
|
|
2170
2406
|
nextSec.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
2171
2407
|
nextSec.style.borderRadius = "4px";
|
|
2172
2408
|
nextSec.style.marginBottom = "24px";
|
|
2173
|
-
|
|
2174
|
-
|
|
2409
|
+
if (headerEl) {
|
|
2410
|
+
nextSec.appendChild(headerEl.cloneNode(true));
|
|
2411
|
+
}
|
|
2412
|
+
const nextArticle = document.createElement("article");
|
|
2413
|
+
if (contentContainer.tagName.toLowerCase() === "article") {
|
|
2414
|
+
nextArticle.style.cssText = contentContainer.style.cssText;
|
|
2415
|
+
}
|
|
2416
|
+
nextSec.appendChild(nextArticle);
|
|
2417
|
+
if (footerEl) {
|
|
2418
|
+
nextSec.appendChild(footerEl.cloneNode(true));
|
|
2419
|
+
}
|
|
2420
|
+
if (curSec.nextSibling) {
|
|
2421
|
+
parent.insertBefore(nextSec, curSec.nextSibling);
|
|
2422
|
+
} else {
|
|
2423
|
+
parent.appendChild(nextSec);
|
|
2424
|
+
}
|
|
2425
|
+
finalSections.push(nextSec);
|
|
2175
2426
|
curSec = nextSec;
|
|
2427
|
+
curContent = nextArticle;
|
|
2176
2428
|
curH = 0;
|
|
2177
2429
|
}
|
|
2178
2430
|
}
|
|
2179
|
-
|
|
2431
|
+
} else {
|
|
2432
|
+
finalSections.push(singleSec);
|
|
2180
2433
|
}
|
|
2181
2434
|
}
|
|
2435
|
+
sections = finalSections;
|
|
2182
2436
|
}
|
|
2183
2437
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2184
2438
|
const totalPages = Math.max(1, pageElements.length);
|
|
@@ -2216,6 +2470,7 @@ var DocxPlugin = class {
|
|
|
2216
2470
|
if (indicator) {
|
|
2217
2471
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2218
2472
|
}
|
|
2473
|
+
ctx.container.scrollTop = 0;
|
|
2219
2474
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2220
2475
|
};
|
|
2221
2476
|
if (totalPages > 1) {
|
|
@@ -2569,6 +2824,88 @@ var DocxPlugin = class {
|
|
|
2569
2824
|
}
|
|
2570
2825
|
return result;
|
|
2571
2826
|
}
|
|
2827
|
+
parseAndRenderChartSvg(xmlStr, width = 500, height = 260) {
|
|
2828
|
+
const catMatches = [...xmlStr.matchAll(/<c:cat>[\s\S]*?<c:strCache>([\s\S]*?)<\/c:strCache>/g)];
|
|
2829
|
+
let categories = [];
|
|
2830
|
+
if (catMatches.length > 0) {
|
|
2831
|
+
categories = [...catMatches[0][1].matchAll(/<c:v>([^<]+)<\/c:v>/g)].map((m) => m[1]);
|
|
2832
|
+
}
|
|
2833
|
+
if (categories.length === 0) {
|
|
2834
|
+
categories = ["Category 1", "Category 2", "Category 3", "Category 4"];
|
|
2835
|
+
}
|
|
2836
|
+
const defaultColors = ["#004586", "#ff420e", "#ffd320", "#579d1c", "#7e0021", "#83caff"];
|
|
2837
|
+
const sers = [...xmlStr.matchAll(/<c:ser>([\s\S]*?)<\/c:ser>/g)];
|
|
2838
|
+
const series = [];
|
|
2839
|
+
sers.forEach((s, sIdx) => {
|
|
2840
|
+
const titleMatch = s[1].match(/<c:tx>[\s\S]*?<c:v>([^<]+)<\/c:v>/);
|
|
2841
|
+
const title = titleMatch ? titleMatch[1] : `Series ${sIdx + 1}`;
|
|
2842
|
+
const clrMatch = s[1].match(/<a:srgbClr\s+val="([^"]+)"/);
|
|
2843
|
+
const color = clrMatch ? "#" + clrMatch[1] : defaultColors[sIdx % defaultColors.length];
|
|
2844
|
+
const valMatch = s[1].match(/<c:val>[\s\S]*?<c:numCache>([\s\S]*?)<\/c:numCache>/);
|
|
2845
|
+
let values = [];
|
|
2846
|
+
if (valMatch) {
|
|
2847
|
+
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);
|
|
2848
|
+
}
|
|
2849
|
+
series.push({ title, color, values });
|
|
2850
|
+
});
|
|
2851
|
+
if (series.length === 0) return "";
|
|
2852
|
+
let maxVal = 10;
|
|
2853
|
+
series.forEach((s) => s.values.forEach((v) => {
|
|
2854
|
+
if (v > maxVal) maxVal = v;
|
|
2855
|
+
}));
|
|
2856
|
+
maxVal = Math.ceil(maxVal * 1.15);
|
|
2857
|
+
if (maxVal % 2 !== 0) maxVal++;
|
|
2858
|
+
const padLeft = 45;
|
|
2859
|
+
const padBottom = 55;
|
|
2860
|
+
const padTop = 20;
|
|
2861
|
+
const padRight = 20;
|
|
2862
|
+
const plotW = width - padLeft - padRight;
|
|
2863
|
+
const plotH = height - padTop - padBottom;
|
|
2864
|
+
const yTicks = 5;
|
|
2865
|
+
let gridLines = "";
|
|
2866
|
+
for (let i = 0; i <= yTicks; i++) {
|
|
2867
|
+
const val = maxVal / yTicks * i;
|
|
2868
|
+
const y = padTop + plotH - val / maxVal * plotH;
|
|
2869
|
+
gridLines += `<line x1="${padLeft}" y1="${y}" x2="${padLeft + plotW}" y2="${y}" stroke="#e2e8f0" stroke-width="1" />`;
|
|
2870
|
+
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>`;
|
|
2871
|
+
}
|
|
2872
|
+
const numCats = categories.length;
|
|
2873
|
+
const numSers = series.length;
|
|
2874
|
+
const groupW = plotW / numCats;
|
|
2875
|
+
const barW = Math.max(8, Math.min(28, groupW * 0.7 / numSers));
|
|
2876
|
+
const groupPad = (groupW - barW * numSers) / 2;
|
|
2877
|
+
let bars = "";
|
|
2878
|
+
let catLabels = "";
|
|
2879
|
+
for (let c = 0; c < numCats; c++) {
|
|
2880
|
+
const catX = padLeft + c * groupW;
|
|
2881
|
+
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>`;
|
|
2882
|
+
for (let s = 0; s < numSers; s++) {
|
|
2883
|
+
const val = series[s].values[c] ?? 0;
|
|
2884
|
+
const bH = Math.max(0, val / maxVal * plotH);
|
|
2885
|
+
const bX = catX + groupPad + s * barW;
|
|
2886
|
+
const bY = padTop + plotH - bH;
|
|
2887
|
+
bars += `<rect x="${bX}" y="${bY}" width="${barW - 2}" height="${bH}" fill="${series[s].color}" rx="1" />`;
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
let legend = "";
|
|
2891
|
+
const legY = height - 12;
|
|
2892
|
+
let legX = padLeft + (plotW - numSers * 100) / 2;
|
|
2893
|
+
series.forEach((s) => {
|
|
2894
|
+
legend += `<rect x="${legX}" y="${legY - 9}" width="10" height="10" fill="${s.color}" rx="2" />`;
|
|
2895
|
+
legend += `<text x="${legX + 15}" y="${legY}" font-size="11" fill="#475569" font-family="Calibri, sans-serif">${s.title}</text>`;
|
|
2896
|
+
legX += 95;
|
|
2897
|
+
});
|
|
2898
|
+
return `
|
|
2899
|
+
<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">
|
|
2900
|
+
${gridLines}
|
|
2901
|
+
<line x1="${padLeft}" y1="${padTop + plotH}" x2="${padLeft + plotW}" y2="${padTop + plotH}" stroke="#94a3b8" stroke-width="1.5" />
|
|
2902
|
+
<line x1="${padLeft}" y1="${padTop}" x2="${padLeft}" y2="${padTop + plotH}" stroke="#94a3b8" stroke-width="1.5" />
|
|
2903
|
+
${bars}
|
|
2904
|
+
${catLabels}
|
|
2905
|
+
${legend}
|
|
2906
|
+
</svg>
|
|
2907
|
+
`.trim();
|
|
2908
|
+
}
|
|
2572
2909
|
};
|
|
2573
2910
|
function docxPlugin() {
|
|
2574
2911
|
return new DocxPlugin();
|
|
@@ -3135,6 +3472,16 @@ var CodePlugin = class {
|
|
|
3135
3472
|
execute: () => {
|
|
3136
3473
|
instance.print?.();
|
|
3137
3474
|
}
|
|
3475
|
+
},
|
|
3476
|
+
{
|
|
3477
|
+
id: "open-window",
|
|
3478
|
+
icon: "open-window",
|
|
3479
|
+
label: "Open in Separate Full Window",
|
|
3480
|
+
type: "button",
|
|
3481
|
+
group: "actions",
|
|
3482
|
+
execute: () => {
|
|
3483
|
+
instance.openInSeparateWindow?.();
|
|
3484
|
+
}
|
|
3138
3485
|
}
|
|
3139
3486
|
);
|
|
3140
3487
|
return actions;
|
|
@@ -3148,17 +3495,39 @@ var CodePlugin = class {
|
|
|
3148
3495
|
let rawPages = [];
|
|
3149
3496
|
if (isTxt) {
|
|
3150
3497
|
const explicitPages = fullText.split(/(?:\f|\x0C)/);
|
|
3498
|
+
const charsPerLine = 85;
|
|
3499
|
+
const maxVisualLines = 45;
|
|
3500
|
+
const charsPerPage = charsPerLine * maxVisualLines;
|
|
3151
3501
|
for (const ep of explicitPages) {
|
|
3152
3502
|
const lines = ep.split(/\r?\n/);
|
|
3153
3503
|
let currentChunk = [];
|
|
3504
|
+
let currentLines = 0;
|
|
3154
3505
|
for (let i = 0; i < lines.length; i++) {
|
|
3155
|
-
|
|
3156
|
-
|
|
3506
|
+
const line = lines[i];
|
|
3507
|
+
const vLines = Math.max(1, Math.ceil((line.length || 1) / charsPerLine));
|
|
3508
|
+
if (currentLines + vLines > maxVisualLines && currentChunk.length > 0) {
|
|
3157
3509
|
rawPages.push(currentChunk.join("\n"));
|
|
3158
3510
|
currentChunk = [];
|
|
3511
|
+
currentLines = 0;
|
|
3512
|
+
}
|
|
3513
|
+
if (vLines > maxVisualLines) {
|
|
3514
|
+
let remaining = line;
|
|
3515
|
+
while (remaining.length > charsPerPage) {
|
|
3516
|
+
let splitIdx = remaining.lastIndexOf(" ", charsPerPage);
|
|
3517
|
+
if (splitIdx < charsPerPage * 0.75) splitIdx = charsPerPage;
|
|
3518
|
+
rawPages.push(remaining.slice(0, splitIdx));
|
|
3519
|
+
remaining = remaining.slice(splitIdx).trimStart();
|
|
3520
|
+
}
|
|
3521
|
+
if (remaining.length > 0) {
|
|
3522
|
+
currentChunk.push(remaining);
|
|
3523
|
+
currentLines = Math.ceil(remaining.length / charsPerLine);
|
|
3524
|
+
}
|
|
3525
|
+
} else {
|
|
3526
|
+
currentChunk.push(line);
|
|
3527
|
+
currentLines += vLines;
|
|
3159
3528
|
}
|
|
3160
3529
|
}
|
|
3161
|
-
if (currentChunk.length > 0
|
|
3530
|
+
if (currentChunk.length > 0) {
|
|
3162
3531
|
rawPages.push(currentChunk.join("\n"));
|
|
3163
3532
|
}
|
|
3164
3533
|
}
|
|
@@ -3268,6 +3637,7 @@ var CodePlugin = class {
|
|
|
3268
3637
|
if (indicator) {
|
|
3269
3638
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3270
3639
|
}
|
|
3640
|
+
container.scrollTop = 0;
|
|
3271
3641
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3272
3642
|
};
|
|
3273
3643
|
if (totalPages > 1) {
|
|
@@ -4280,6 +4650,14 @@ var RtfPlugin = class {
|
|
|
4280
4650
|
type: "button",
|
|
4281
4651
|
group: "actions",
|
|
4282
4652
|
execute: () => instance.print?.()
|
|
4653
|
+
},
|
|
4654
|
+
{
|
|
4655
|
+
id: "open-window",
|
|
4656
|
+
icon: "open-window",
|
|
4657
|
+
label: "Open in Separate Full Window",
|
|
4658
|
+
type: "button",
|
|
4659
|
+
group: "actions",
|
|
4660
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
4283
4661
|
}
|
|
4284
4662
|
);
|
|
4285
4663
|
return actions;
|
|
@@ -4332,11 +4710,55 @@ var RtfPlugin = class {
|
|
|
4332
4710
|
}
|
|
4333
4711
|
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
4334
4712
|
const htmlElements = await doc.render();
|
|
4335
|
-
|
|
4336
|
-
for (
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4713
|
+
const contentNodes = [];
|
|
4714
|
+
for (const item of htmlElements) {
|
|
4715
|
+
if (item.children && item.children.length > 0 && !item.tagName.toLowerCase().startsWith("table")) {
|
|
4716
|
+
contentNodes.push(...Array.from(item.children));
|
|
4717
|
+
} else {
|
|
4718
|
+
contentNodes.push(item);
|
|
4719
|
+
}
|
|
4720
|
+
}
|
|
4721
|
+
wrapper.innerHTML = "";
|
|
4722
|
+
contentNodes.forEach((node) => wrapper.appendChild(node));
|
|
4723
|
+
const childHeights = contentNodes.map((c) => {
|
|
4724
|
+
const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
|
|
4725
|
+
const offH = c.offsetHeight || 0;
|
|
4726
|
+
const textLen = c.textContent?.trim().length || 0;
|
|
4727
|
+
const estH = Math.max(24, Math.ceil(textLen / 75) * 22 + 14);
|
|
4728
|
+
return Math.max(rectH, offH, estH);
|
|
4729
|
+
});
|
|
4730
|
+
wrapper.innerHTML = "";
|
|
4731
|
+
const createRtfCard = () => {
|
|
4732
|
+
const card = document.createElement("div");
|
|
4733
|
+
card.className = "fp-rtf-page-card";
|
|
4734
|
+
card.style.backgroundColor = "#ffffff";
|
|
4735
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
4736
|
+
card.style.borderRadius = "4px";
|
|
4737
|
+
card.style.padding = "72px 56px";
|
|
4738
|
+
card.style.width = "816px";
|
|
4739
|
+
card.style.minHeight = "1056px";
|
|
4740
|
+
card.style.boxSizing = "border-box";
|
|
4741
|
+
card.style.marginBottom = "24px";
|
|
4742
|
+
card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4743
|
+
card.style.lineHeight = "1.6";
|
|
4744
|
+
return card;
|
|
4745
|
+
};
|
|
4746
|
+
let curCard = createRtfCard();
|
|
4747
|
+
wrapper.appendChild(curCard);
|
|
4748
|
+
pageElements = [curCard];
|
|
4749
|
+
let curH = 0;
|
|
4750
|
+
const maxH = 912;
|
|
4751
|
+
for (let i = 0; i < contentNodes.length; i++) {
|
|
4752
|
+
const child = contentNodes[i];
|
|
4753
|
+
const chH = childHeights[i];
|
|
4754
|
+
curCard.appendChild(child);
|
|
4755
|
+
curH += chH;
|
|
4756
|
+
if (curH >= maxH && i < contentNodes.length - 1) {
|
|
4757
|
+
curCard = createRtfCard();
|
|
4758
|
+
wrapper.appendChild(curCard);
|
|
4759
|
+
pageElements.push(curCard);
|
|
4760
|
+
curH = 0;
|
|
4761
|
+
}
|
|
4340
4762
|
}
|
|
4341
4763
|
} catch (err) {
|
|
4342
4764
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
@@ -4402,6 +4824,7 @@ var RtfPlugin = class {
|
|
|
4402
4824
|
if (indicator) {
|
|
4403
4825
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4404
4826
|
}
|
|
4827
|
+
ctx.container.scrollTop = 0;
|
|
4405
4828
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4406
4829
|
};
|
|
4407
4830
|
if (totalPages > 1) {
|
|
@@ -4703,6 +5126,14 @@ var OpenDocumentPlugin = class {
|
|
|
4703
5126
|
type: "button",
|
|
4704
5127
|
group: "actions",
|
|
4705
5128
|
execute: () => instance.print?.()
|
|
5129
|
+
},
|
|
5130
|
+
{
|
|
5131
|
+
id: "open-window",
|
|
5132
|
+
icon: "open-window",
|
|
5133
|
+
label: "Open in Separate Full Window",
|
|
5134
|
+
type: "button",
|
|
5135
|
+
group: "actions",
|
|
5136
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
4706
5137
|
}
|
|
4707
5138
|
);
|
|
4708
5139
|
return actions;
|
|
@@ -4873,12 +5304,9 @@ var OpenDocumentPlugin = class {
|
|
|
4873
5304
|
page.style.backgroundColor = "#ffffff";
|
|
4874
5305
|
page.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
4875
5306
|
page.style.borderRadius = "4px";
|
|
4876
|
-
page.style.boxSizing = "border-box";
|
|
4877
5307
|
page.style.display = idx === 0 ? "block" : "none";
|
|
4878
|
-
page.style.
|
|
4879
|
-
page.style.
|
|
4880
|
-
page.style.left = "50%";
|
|
4881
|
-
page.style.transform = "translateX(-50%)";
|
|
5308
|
+
page.style.margin = "0 auto 24px";
|
|
5309
|
+
page.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
4882
5310
|
elements.forEach((el) => page.appendChild(el));
|
|
4883
5311
|
wrapper.appendChild(page);
|
|
4884
5312
|
slides.push(page);
|
|
@@ -4916,6 +5344,7 @@ var OpenDocumentPlugin = class {
|
|
|
4916
5344
|
if (indicator) {
|
|
4917
5345
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4918
5346
|
}
|
|
5347
|
+
container.scrollTop = 0;
|
|
4919
5348
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4920
5349
|
};
|
|
4921
5350
|
return {
|
|
@@ -5293,6 +5722,14 @@ var DocPlugin = class {
|
|
|
5293
5722
|
type: "button",
|
|
5294
5723
|
group: "actions",
|
|
5295
5724
|
execute: () => instance.print?.()
|
|
5725
|
+
},
|
|
5726
|
+
{
|
|
5727
|
+
id: "open-window",
|
|
5728
|
+
icon: "open-window",
|
|
5729
|
+
label: "Open in Separate Full Window",
|
|
5730
|
+
type: "button",
|
|
5731
|
+
group: "actions",
|
|
5732
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
5296
5733
|
}
|
|
5297
5734
|
);
|
|
5298
5735
|
return actions;
|
|
@@ -5408,6 +5845,7 @@ var DocPlugin = class {
|
|
|
5408
5845
|
if (indicator) {
|
|
5409
5846
|
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5410
5847
|
}
|
|
5848
|
+
container.scrollTop = 0;
|
|
5411
5849
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5412
5850
|
};
|
|
5413
5851
|
if (totalPages > 1) {
|
|
@@ -5583,47 +6021,69 @@ var DocPlugin = class {
|
|
|
5583
6021
|
heuristicTextExtraction(buffer) {
|
|
5584
6022
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
5585
6023
|
}
|
|
6024
|
+
cleanWordDocFields(text) {
|
|
6025
|
+
if (!text) return "";
|
|
6026
|
+
let cleaned = text.replace(
|
|
6027
|
+
/\x13\s*HYPERLINK\s*"?([^"\x14]+)"?\s*\x14([\s\S]*?)\x15/gi,
|
|
6028
|
+
(_match, url, label) => {
|
|
6029
|
+
const cleanUrl = url.trim();
|
|
6030
|
+
const cleanLabel = label.trim() || cleanUrl;
|
|
6031
|
+
return `<a href="${cleanUrl}" target="_blank" rel="noopener noreferrer" style="color: #2563eb; text-decoration: underline;">${cleanLabel}</a>`;
|
|
6032
|
+
}
|
|
6033
|
+
);
|
|
6034
|
+
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g, "$1");
|
|
6035
|
+
cleaned = cleaned.replace(/\x13[^\x15]*\x15/g, "");
|
|
6036
|
+
cleaned = cleaned.replace(/[\x13\x14\x15]/g, "");
|
|
6037
|
+
return cleaned;
|
|
6038
|
+
}
|
|
5586
6039
|
splitIntoPages(text) {
|
|
5587
6040
|
if (!text) return [""];
|
|
5588
|
-
const
|
|
5589
|
-
|
|
5590
|
-
const
|
|
6041
|
+
const cleanedText = this.cleanWordDocFields(text);
|
|
6042
|
+
const normalized = cleanedText.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ");
|
|
6043
|
+
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);
|
|
6044
|
+
if (explicitParts.length === 0) explicitParts.push(normalized);
|
|
6045
|
+
const maxLinesPerPage = 32;
|
|
6046
|
+
const charsPerLine = 80;
|
|
5591
6047
|
const finalPages = [];
|
|
5592
6048
|
for (const part of explicitParts) {
|
|
5593
|
-
const lines = part.split(
|
|
6049
|
+
const lines = part.split("\n");
|
|
5594
6050
|
let currentLines = [];
|
|
5595
6051
|
let count = 0;
|
|
5596
6052
|
for (const line of lines) {
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
if (count
|
|
6053
|
+
const plainLine = line.replace(/<[^>]+>/g, "");
|
|
6054
|
+
const vLines = Math.max(1, Math.ceil((plainLine.length || 1) / charsPerLine));
|
|
6055
|
+
if (count + vLines > maxLinesPerPage && currentLines.length > 0) {
|
|
5600
6056
|
finalPages.push(currentLines.join("\n"));
|
|
5601
6057
|
currentLines = [];
|
|
5602
6058
|
count = 0;
|
|
5603
6059
|
}
|
|
6060
|
+
currentLines.push(line);
|
|
6061
|
+
count += vLines;
|
|
5604
6062
|
}
|
|
5605
6063
|
if (currentLines.length > 0) {
|
|
5606
6064
|
finalPages.push(currentLines.join("\n"));
|
|
5607
6065
|
}
|
|
5608
6066
|
}
|
|
5609
|
-
return finalPages.length > 0 ? finalPages : [
|
|
6067
|
+
return finalPages.length > 0 ? finalPages : [normalized];
|
|
5610
6068
|
}
|
|
5611
6069
|
/**
|
|
5612
6070
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
5613
6071
|
*/
|
|
5614
6072
|
formatDocToHtml(text, filename) {
|
|
5615
|
-
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
6073
|
+
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ").split("\n");
|
|
5616
6074
|
let html = "";
|
|
5617
6075
|
let inList = false;
|
|
5618
6076
|
let tableLines = [];
|
|
5619
6077
|
const flushTable = () => {
|
|
5620
6078
|
if (tableLines.length > 0) {
|
|
5621
|
-
html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size:
|
|
5622
|
-
for (
|
|
5623
|
-
|
|
5624
|
-
const
|
|
6079
|
+
html += '<table style="width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 13px; font-family: Calibri, sans-serif;">';
|
|
6080
|
+
for (let rIdx = 0; rIdx < tableLines.length; rIdx++) {
|
|
6081
|
+
const tLine = tableLines[rIdx];
|
|
6082
|
+
const isHeader = rIdx === 0;
|
|
6083
|
+
html += `<tr style="${isHeader ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
|
|
6084
|
+
const cols = tLine.split(" ").filter((c) => c.trim().length > 0);
|
|
5625
6085
|
for (const col of cols) {
|
|
5626
|
-
html += `<td style="border: 1px solid #cbd5e1; padding:
|
|
6086
|
+
html += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px;">${DOMPurify6__default.default.sanitize(col.trim())}</td>`;
|
|
5627
6087
|
}
|
|
5628
6088
|
html += "</tr>";
|
|
5629
6089
|
}
|
|
@@ -5636,27 +6096,18 @@ var DocPlugin = class {
|
|
|
5636
6096
|
let line = lines[i];
|
|
5637
6097
|
let tabCount = (line.match(/\t/g) || []).length;
|
|
5638
6098
|
if (tabCount > 0) {
|
|
5639
|
-
let
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
const nextTabCount = (lines[j].match(/\t/g) || []).length;
|
|
5643
|
-
if (nextTabCount === tabCount) {
|
|
5644
|
-
consecutiveTableLines++;
|
|
5645
|
-
j++;
|
|
5646
|
-
} else {
|
|
5647
|
-
break;
|
|
5648
|
-
}
|
|
6099
|
+
let j = i;
|
|
6100
|
+
while (j < lines.length && (lines[j].match(/\t/g) || []).length > 0) {
|
|
6101
|
+
j++;
|
|
5649
6102
|
}
|
|
5650
|
-
if (
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
inList = false;
|
|
5654
|
-
}
|
|
5655
|
-
tableLines = lines.slice(i, j);
|
|
5656
|
-
flushTable();
|
|
5657
|
-
i = j;
|
|
5658
|
-
continue;
|
|
6103
|
+
if (inList) {
|
|
6104
|
+
html += "</ul>";
|
|
6105
|
+
inList = false;
|
|
5659
6106
|
}
|
|
6107
|
+
tableLines = lines.slice(i, j);
|
|
6108
|
+
flushTable();
|
|
6109
|
+
i = j;
|
|
6110
|
+
continue;
|
|
5660
6111
|
}
|
|
5661
6112
|
line = line.trim();
|
|
5662
6113
|
if (!line) {
|
|
@@ -5676,25 +6127,26 @@ var DocPlugin = class {
|
|
|
5676
6127
|
i++;
|
|
5677
6128
|
continue;
|
|
5678
6129
|
}
|
|
6130
|
+
const sanitizeOptions = { ADD_TAGS: ["a"], ADD_ATTR: ["href", "target", "rel", "style"] };
|
|
5679
6131
|
if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
|
|
5680
6132
|
if (inList) {
|
|
5681
6133
|
html += "</ul>";
|
|
5682
6134
|
inList = false;
|
|
5683
6135
|
}
|
|
5684
|
-
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>`;
|
|
6136
|
+
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>`;
|
|
5685
6137
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
5686
6138
|
if (!inList) {
|
|
5687
6139
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
5688
6140
|
inList = true;
|
|
5689
6141
|
}
|
|
5690
6142
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
5691
|
-
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6__default.default.sanitize(bulletText)}</li>`;
|
|
6143
|
+
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6__default.default.sanitize(bulletText, sanitizeOptions)}</li>`;
|
|
5692
6144
|
} else {
|
|
5693
6145
|
if (inList) {
|
|
5694
6146
|
html += "</ul>";
|
|
5695
6147
|
inList = false;
|
|
5696
6148
|
}
|
|
5697
|
-
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6__default.default.sanitize(line)}</p>`;
|
|
6149
|
+
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6__default.default.sanitize(line, sanitizeOptions)}</p>`;
|
|
5698
6150
|
}
|
|
5699
6151
|
i++;
|
|
5700
6152
|
}
|