@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/react.js
CHANGED
|
@@ -338,16 +338,21 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
338
338
|
metadata.mimeType = source.type || void 0;
|
|
339
339
|
metadata.extension = extractExtension(source.name);
|
|
340
340
|
buffer = await source.arrayBuffer();
|
|
341
|
-
} else if (source instanceof Blob) {
|
|
341
|
+
} else if (source instanceof Blob || source && typeof source.arrayBuffer === "function" && typeof source.size === "number") {
|
|
342
342
|
metadata.size = source.size;
|
|
343
343
|
metadata.mimeType = source.type || void 0;
|
|
344
|
+
if (source.name) {
|
|
345
|
+
metadata.name = source.name;
|
|
346
|
+
metadata.extension = extractExtension(source.name);
|
|
347
|
+
}
|
|
344
348
|
buffer = await source.arrayBuffer();
|
|
345
|
-
} else if (source instanceof ArrayBuffer) {
|
|
349
|
+
} else if (source instanceof ArrayBuffer || Object.prototype.toString.call(source) === "[object ArrayBuffer]" || source && typeof source.byteLength === "number" && typeof source.slice === "function") {
|
|
346
350
|
buffer = source;
|
|
347
|
-
} else if (source instanceof Uint8Array) {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
+
} else if (source instanceof Uint8Array || ArrayBuffer.isView(source)) {
|
|
352
|
+
const view = source;
|
|
353
|
+
buffer = view.buffer.slice(
|
|
354
|
+
view.byteOffset,
|
|
355
|
+
view.byteOffset + view.byteLength
|
|
351
356
|
);
|
|
352
357
|
} else {
|
|
353
358
|
throw new Error("Unsupported file source type");
|
|
@@ -432,6 +437,45 @@ function createElement(tag, attrs, ...children) {
|
|
|
432
437
|
}
|
|
433
438
|
return el;
|
|
434
439
|
}
|
|
440
|
+
var DB_NAME = "PreviewFileTransferDB";
|
|
441
|
+
var DB_STORE = "transfers";
|
|
442
|
+
function openDB() {
|
|
443
|
+
return new Promise((resolve, reject) => {
|
|
444
|
+
if (typeof indexedDB === "undefined") {
|
|
445
|
+
return reject(new Error("IndexedDB is not available"));
|
|
446
|
+
}
|
|
447
|
+
const req = indexedDB.open(DB_NAME, 1);
|
|
448
|
+
req.onupgradeneeded = () => {
|
|
449
|
+
const db = req.result;
|
|
450
|
+
if (!db.objectStoreNames.contains(DB_STORE)) {
|
|
451
|
+
db.createObjectStore(DB_STORE, { keyPath: "id" });
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
req.onsuccess = () => resolve(req.result);
|
|
455
|
+
req.onerror = () => reject(req.error);
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
async function saveTransferPayload(id, payload) {
|
|
459
|
+
if (typeof window !== "undefined") {
|
|
460
|
+
try {
|
|
461
|
+
window[id] = payload;
|
|
462
|
+
window.__lastTransfer = payload;
|
|
463
|
+
} catch {
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
try {
|
|
467
|
+
const db = await openDB();
|
|
468
|
+
return new Promise((resolve, reject) => {
|
|
469
|
+
const tx = db.transaction(DB_STORE, "readwrite");
|
|
470
|
+
const store = tx.objectStore(DB_STORE);
|
|
471
|
+
store.put({ id, ...payload, timestamp: Date.now() });
|
|
472
|
+
tx.oncomplete = () => resolve();
|
|
473
|
+
tx.onerror = () => reject(tx.error);
|
|
474
|
+
});
|
|
475
|
+
} catch (e) {
|
|
476
|
+
console.warn("[saveTransferPayload] IndexedDB store warning:", e);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
435
479
|
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>`;
|
|
436
480
|
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>`;
|
|
437
481
|
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>`;
|
|
@@ -451,6 +495,7 @@ var ICON_COPY = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" str
|
|
|
451
495
|
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>`;
|
|
452
496
|
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>`;
|
|
453
497
|
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>`;
|
|
498
|
+
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>`;
|
|
454
499
|
var ICON_MAP = {
|
|
455
500
|
"zoom-in": ICON_ZOOM_IN,
|
|
456
501
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -477,7 +522,9 @@ var ICON_MAP = {
|
|
|
477
522
|
"forward-10": ICON_FAST_FORWARD,
|
|
478
523
|
"rewind": ICON_REWIND,
|
|
479
524
|
"replay-10": ICON_REWIND,
|
|
480
|
-
"speed": ICON_SPEED
|
|
525
|
+
"speed": ICON_SPEED,
|
|
526
|
+
"open-window": ICON_EXTERNAL_WINDOW,
|
|
527
|
+
"external-window": ICON_EXTERNAL_WINDOW
|
|
481
528
|
};
|
|
482
529
|
var ToolbarController = class {
|
|
483
530
|
el;
|
|
@@ -694,7 +741,7 @@ var ThumbnailPanel = class {
|
|
|
694
741
|
}
|
|
695
742
|
}
|
|
696
743
|
};
|
|
697
|
-
var FilePreviewViewer = class {
|
|
744
|
+
var FilePreviewViewer = class _FilePreviewViewer {
|
|
698
745
|
plugins = [];
|
|
699
746
|
activeInstance = null;
|
|
700
747
|
abortController = null;
|
|
@@ -731,6 +778,7 @@ var FilePreviewViewer = class {
|
|
|
731
778
|
* Preview a file in the given container element.
|
|
732
779
|
*/
|
|
733
780
|
async preview(container, source, options = {}) {
|
|
781
|
+
this.currentOptions = options;
|
|
734
782
|
this.abort();
|
|
735
783
|
this.abortController = new AbortController();
|
|
736
784
|
const { signal } = this.abortController;
|
|
@@ -740,7 +788,10 @@ var FilePreviewViewer = class {
|
|
|
740
788
|
this.showLoading();
|
|
741
789
|
try {
|
|
742
790
|
const { buffer, metadata } = await sourceToArrayBuffer(source, signal);
|
|
743
|
-
|
|
791
|
+
if (options.metadata) {
|
|
792
|
+
Object.assign(metadata, options.metadata);
|
|
793
|
+
}
|
|
794
|
+
this.currentBuffer = buffer.slice(0);
|
|
744
795
|
this.currentMetadata = metadata;
|
|
745
796
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
746
797
|
const fileInfo = { metadata, buffer };
|
|
@@ -770,6 +821,7 @@ var FilePreviewViewer = class {
|
|
|
770
821
|
}
|
|
771
822
|
});
|
|
772
823
|
this.activeInstance = instance;
|
|
824
|
+
instance.openInSeparateWindow = () => this.openInSeparateWindow();
|
|
773
825
|
this.hideLoading();
|
|
774
826
|
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
775
827
|
if (options.showToolbar !== false && this.toolbar) {
|
|
@@ -779,26 +831,16 @@ var FilePreviewViewer = class {
|
|
|
779
831
|
actions.push({
|
|
780
832
|
id: "fullscreen",
|
|
781
833
|
icon: "fullscreen",
|
|
782
|
-
label: "
|
|
834
|
+
label: "Fullscreen",
|
|
783
835
|
type: "button",
|
|
784
836
|
group: "view",
|
|
785
|
-
execute:
|
|
837
|
+
execute: () => {
|
|
786
838
|
try {
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
if (this.wrapperEl?.requestFullscreen) {
|
|
791
|
-
await this.wrapperEl.requestFullscreen().catch(() => {
|
|
792
|
-
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
793
|
-
});
|
|
794
|
-
} else {
|
|
795
|
-
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
796
|
-
}
|
|
839
|
+
if (!document.fullscreenElement) {
|
|
840
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
841
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
797
842
|
} else {
|
|
798
|
-
|
|
799
|
-
await document.exitFullscreen().catch(() => {
|
|
800
|
-
});
|
|
801
|
-
}
|
|
843
|
+
document.exitFullscreen?.();
|
|
802
844
|
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
803
845
|
}
|
|
804
846
|
} catch {
|
|
@@ -810,6 +852,28 @@ var FilePreviewViewer = class {
|
|
|
810
852
|
}
|
|
811
853
|
});
|
|
812
854
|
}
|
|
855
|
+
const openWinAction = actions.find((a) => a.id === "open-window");
|
|
856
|
+
if (openWinAction) {
|
|
857
|
+
if (options?._isSeparateWindow) {
|
|
858
|
+
const idx = actions.indexOf(openWinAction);
|
|
859
|
+
if (idx !== -1) actions.splice(idx, 1);
|
|
860
|
+
} else {
|
|
861
|
+
openWinAction.execute = () => {
|
|
862
|
+
this.openInSeparateWindow();
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
} else if (!options?._isSeparateWindow) {
|
|
866
|
+
actions.push({
|
|
867
|
+
id: "open-window",
|
|
868
|
+
icon: "open-window",
|
|
869
|
+
label: "Open in Separate Full Window",
|
|
870
|
+
type: "button",
|
|
871
|
+
group: "actions",
|
|
872
|
+
execute: () => {
|
|
873
|
+
this.openInSeparateWindow();
|
|
874
|
+
}
|
|
875
|
+
});
|
|
876
|
+
}
|
|
813
877
|
this.toolbar.update(actions);
|
|
814
878
|
this.toolbar.show();
|
|
815
879
|
}
|
|
@@ -842,6 +906,104 @@ var FilePreviewViewer = class {
|
|
|
842
906
|
throw error;
|
|
843
907
|
}
|
|
844
908
|
}
|
|
909
|
+
/**
|
|
910
|
+
* Opens the current file preview in a separate full browser window.
|
|
911
|
+
*/
|
|
912
|
+
openInSeparateWindow() {
|
|
913
|
+
if (!this.currentBuffer) {
|
|
914
|
+
console.warn("[FilePreviewViewer] No active file buffer to open in separate window");
|
|
915
|
+
return null;
|
|
916
|
+
}
|
|
917
|
+
if (this.currentOptions.onOpenSeparateWindow) {
|
|
918
|
+
return this.currentOptions.onOpenSeparateWindow({
|
|
919
|
+
buffer: this.currentBuffer,
|
|
920
|
+
metadata: this.currentMetadata || { name: "Document" },
|
|
921
|
+
options: this.currentOptions
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
const transferId = "fp_win_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8);
|
|
925
|
+
let clonedBuffer;
|
|
926
|
+
try {
|
|
927
|
+
clonedBuffer = this.currentBuffer.slice(0);
|
|
928
|
+
} catch {
|
|
929
|
+
clonedBuffer = this.currentBuffer;
|
|
930
|
+
}
|
|
931
|
+
const payload = {
|
|
932
|
+
buffer: clonedBuffer,
|
|
933
|
+
metadata: this.currentMetadata ? { ...this.currentMetadata } : void 0,
|
|
934
|
+
options: { ...this.currentOptions, _isSeparateWindow: true }
|
|
935
|
+
};
|
|
936
|
+
if (typeof window !== "undefined") {
|
|
937
|
+
try {
|
|
938
|
+
window[transferId] = payload;
|
|
939
|
+
window.__lastTransfer = payload;
|
|
940
|
+
} catch {
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
saveTransferPayload(transferId, payload).catch((err) => {
|
|
944
|
+
console.warn("[FilePreviewViewer] Transfer payload save warning:", err);
|
|
945
|
+
});
|
|
946
|
+
let targetUrl = null;
|
|
947
|
+
if (this.currentOptions.standaloneViewerUrl) {
|
|
948
|
+
const u = new URL(this.currentOptions.standaloneViewerUrl, window.location.href);
|
|
949
|
+
u.searchParams.set("mode", "fullscreen");
|
|
950
|
+
u.searchParams.set("transferId", transferId);
|
|
951
|
+
targetUrl = u.toString();
|
|
952
|
+
} else if (typeof window !== "undefined" && window.location?.href && !window.location.href.startsWith("about:")) {
|
|
953
|
+
const u = new URL(window.location.href);
|
|
954
|
+
u.searchParams.set("mode", "fullscreen");
|
|
955
|
+
u.searchParams.set("transferId", transferId);
|
|
956
|
+
targetUrl = u.toString();
|
|
957
|
+
}
|
|
958
|
+
if (targetUrl) {
|
|
959
|
+
const newWin2 = window.open(targetUrl, "_blank");
|
|
960
|
+
if (!newWin2) {
|
|
961
|
+
alert("Popup blocker prevented opening the preview in a separate window. Please allow popups for this site.");
|
|
962
|
+
return null;
|
|
963
|
+
}
|
|
964
|
+
return newWin2;
|
|
965
|
+
}
|
|
966
|
+
const title = (this.currentMetadata?.name || "Document Preview") + " - Full Preview";
|
|
967
|
+
const newWin = window.open("", "_blank");
|
|
968
|
+
if (!newWin) {
|
|
969
|
+
alert("Popup blocker prevented opening the preview in a separate window. Please allow popups for this site.");
|
|
970
|
+
return null;
|
|
971
|
+
}
|
|
972
|
+
newWin.document.title = title;
|
|
973
|
+
newWin.document.body.style.margin = "0";
|
|
974
|
+
newWin.document.body.style.padding = "0";
|
|
975
|
+
newWin.document.body.style.width = "100vw";
|
|
976
|
+
newWin.document.body.style.height = "100vh";
|
|
977
|
+
newWin.document.body.style.overflow = "hidden";
|
|
978
|
+
newWin.document.body.style.backgroundColor = "#f8fafc";
|
|
979
|
+
const headNodes = document.querySelectorAll('link[rel="stylesheet"], style');
|
|
980
|
+
headNodes.forEach((node) => {
|
|
981
|
+
newWin.document.head.appendChild(node.cloneNode(true));
|
|
982
|
+
});
|
|
983
|
+
const root = newWin.document.createElement("div");
|
|
984
|
+
root.id = "full-window-preview-root";
|
|
985
|
+
root.style.width = "100%";
|
|
986
|
+
root.style.height = "100%";
|
|
987
|
+
root.style.overflow = "hidden";
|
|
988
|
+
newWin.document.body.appendChild(root);
|
|
989
|
+
const separateViewer = new _FilePreviewViewer();
|
|
990
|
+
for (const plugin of this.plugins) {
|
|
991
|
+
separateViewer.registerPlugin(plugin);
|
|
992
|
+
}
|
|
993
|
+
separateViewer.preview(root, this.currentBuffer.slice(0), {
|
|
994
|
+
...this.currentOptions,
|
|
995
|
+
showToolbar: true,
|
|
996
|
+
toolbarPosition: "top",
|
|
997
|
+
metadata: this.currentMetadata || void 0,
|
|
998
|
+
_isSeparateWindow: true
|
|
999
|
+
}).catch((err) => {
|
|
1000
|
+
console.error("[FilePreviewViewer] Error rendering in separate window:", err);
|
|
1001
|
+
});
|
|
1002
|
+
newWin.addEventListener("beforeunload", () => {
|
|
1003
|
+
separateViewer.destroy();
|
|
1004
|
+
});
|
|
1005
|
+
return newWin;
|
|
1006
|
+
}
|
|
845
1007
|
/**
|
|
846
1008
|
* Subscribe to viewer events.
|
|
847
1009
|
*/
|
|
@@ -1247,8 +1409,20 @@ var CfbfReader = class {
|
|
|
1247
1409
|
}
|
|
1248
1410
|
};
|
|
1249
1411
|
if (typeof window !== "undefined" && pdfjsLib.GlobalWorkerOptions) {
|
|
1250
|
-
if (!pdfjsLib.GlobalWorkerOptions.workerSrc) {
|
|
1251
|
-
|
|
1412
|
+
if (!pdfjsLib.GlobalWorkerOptions.workerPort && !pdfjsLib.GlobalWorkerOptions.workerSrc) {
|
|
1413
|
+
const customWorker = window.__PDF_WORKER_SRC__;
|
|
1414
|
+
if (customWorker) {
|
|
1415
|
+
pdfjsLib.GlobalWorkerOptions.workerSrc = customWorker;
|
|
1416
|
+
} else {
|
|
1417
|
+
try {
|
|
1418
|
+
pdfjsLib.GlobalWorkerOptions.workerPort = new Worker(
|
|
1419
|
+
new URL("pdfjs-dist/build/pdf.worker.min.mjs", import.meta.url),
|
|
1420
|
+
{ type: "module" }
|
|
1421
|
+
);
|
|
1422
|
+
} catch {
|
|
1423
|
+
pdfjsLib.GlobalWorkerOptions.workerSrc = "./pdf.worker.min.mjs";
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1252
1426
|
}
|
|
1253
1427
|
}
|
|
1254
1428
|
var PdfPlugin = class {
|
|
@@ -1342,6 +1516,14 @@ var PdfPlugin = class {
|
|
|
1342
1516
|
type: "button",
|
|
1343
1517
|
group: "actions",
|
|
1344
1518
|
execute: () => instance.print?.()
|
|
1519
|
+
},
|
|
1520
|
+
{
|
|
1521
|
+
id: "open-window",
|
|
1522
|
+
icon: "open-window",
|
|
1523
|
+
label: "Open in Separate Full Window",
|
|
1524
|
+
type: "button",
|
|
1525
|
+
group: "actions",
|
|
1526
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
1345
1527
|
}
|
|
1346
1528
|
];
|
|
1347
1529
|
}
|
|
@@ -1391,18 +1573,21 @@ var PdfPlugin = class {
|
|
|
1391
1573
|
indicator.style.pointerEvents = "none";
|
|
1392
1574
|
container.appendChild(indicator);
|
|
1393
1575
|
ctx.container.appendChild(container);
|
|
1576
|
+
const standardFontsUrl = typeof window !== "undefined" && window.__PDF_STANDARD_FONTS_URL__ || "./standard_fonts/";
|
|
1577
|
+
const cmapsUrl = typeof window !== "undefined" && window.__PDF_CMAPS_URL__ || "./cmaps/";
|
|
1394
1578
|
const loadingTask = pdfjsLib.getDocument({
|
|
1395
|
-
data: new Uint8Array(ctx.buffer),
|
|
1396
|
-
cMapUrl:
|
|
1579
|
+
data: new Uint8Array(ctx.buffer.slice(0)),
|
|
1580
|
+
cMapUrl: cmapsUrl,
|
|
1397
1581
|
cMapPacked: true,
|
|
1398
|
-
standardFontDataUrl:
|
|
1582
|
+
standardFontDataUrl: standardFontsUrl,
|
|
1583
|
+
verbosity: 0
|
|
1399
1584
|
});
|
|
1400
1585
|
const pdfDoc = await loadingTask.promise;
|
|
1401
1586
|
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1402
1587
|
let currentPage = 1;
|
|
1403
1588
|
let zoomScale = 1;
|
|
1404
1589
|
let rotation = 0;
|
|
1405
|
-
let fitMode = "
|
|
1590
|
+
let fitMode = "page";
|
|
1406
1591
|
let currentRenderTask = null;
|
|
1407
1592
|
const renderPage = async (pageNum) => {
|
|
1408
1593
|
if (currentRenderTask) {
|
|
@@ -1422,15 +1607,15 @@ var PdfPlugin = class {
|
|
|
1422
1607
|
const containerWidth = container.clientWidth || 900;
|
|
1423
1608
|
const containerHeight = container.clientHeight || 700;
|
|
1424
1609
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1425
|
-
const availWidth = Math.max(
|
|
1426
|
-
const availHeight = Math.max(
|
|
1610
|
+
const availWidth = Math.max(320, containerWidth - 48);
|
|
1611
|
+
const availHeight = Math.max(550, containerHeight - 88);
|
|
1427
1612
|
const scaleW = availWidth / unscaledVp.width;
|
|
1428
1613
|
const scaleH = availHeight / unscaledVp.height;
|
|
1429
1614
|
let fitScale;
|
|
1430
1615
|
if (fitMode === "page") {
|
|
1431
|
-
fitScale = Math.max(0.
|
|
1616
|
+
fitScale = Math.max(0.4, Math.min(scaleW, scaleH));
|
|
1432
1617
|
} else {
|
|
1433
|
-
fitScale = Math.max(0.65, Math.min(1.
|
|
1618
|
+
fitScale = Math.max(0.65, Math.min(1.25, scaleW));
|
|
1434
1619
|
}
|
|
1435
1620
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1436
1621
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
@@ -1456,7 +1641,7 @@ var PdfPlugin = class {
|
|
|
1456
1641
|
currentRenderTask = null;
|
|
1457
1642
|
}
|
|
1458
1643
|
};
|
|
1459
|
-
|
|
1644
|
+
renderPage(1);
|
|
1460
1645
|
let resizeTimer = null;
|
|
1461
1646
|
const resizeObserver = new ResizeObserver(() => {
|
|
1462
1647
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
@@ -1500,7 +1685,7 @@ var PdfPlugin = class {
|
|
|
1500
1685
|
renderPage(currentPage);
|
|
1501
1686
|
},
|
|
1502
1687
|
fitToPage: () => {
|
|
1503
|
-
fitMode = fitMode === "
|
|
1688
|
+
fitMode = fitMode === "page" ? "width" : "page";
|
|
1504
1689
|
zoomScale = 1;
|
|
1505
1690
|
rotation = 0;
|
|
1506
1691
|
renderPage(currentPage);
|
|
@@ -1977,6 +2162,14 @@ var DocxPlugin = class {
|
|
|
1977
2162
|
type: "button",
|
|
1978
2163
|
group: "actions",
|
|
1979
2164
|
execute: () => instance.print?.()
|
|
2165
|
+
},
|
|
2166
|
+
{
|
|
2167
|
+
id: "open-window",
|
|
2168
|
+
icon: "open-window",
|
|
2169
|
+
label: "Open in Separate Full Window",
|
|
2170
|
+
type: "button",
|
|
2171
|
+
group: "actions",
|
|
2172
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
1980
2173
|
}
|
|
1981
2174
|
);
|
|
1982
2175
|
return actions;
|
|
@@ -2036,6 +2229,31 @@ var DocxPlugin = class {
|
|
|
2036
2229
|
}
|
|
2037
2230
|
if (wrapper.children.length > 0 && (wrapper.textContent?.trim().length ?? 0) > 0) {
|
|
2038
2231
|
renderedSuccessfully = true;
|
|
2232
|
+
try {
|
|
2233
|
+
const unzipped = unzipSync(new Uint8Array(ctx.buffer));
|
|
2234
|
+
const chartKeys = Object.keys(unzipped).filter((k) => k.replace(/^[./\\]+/, "").toLowerCase().startsWith("word/charts/chart") && k.endsWith(".xml")).sort();
|
|
2235
|
+
if (chartKeys.length > 0) {
|
|
2236
|
+
const allDivs = Array.from(wrapper.querySelectorAll("div"));
|
|
2237
|
+
const emptyContainers = allDivs.filter((div) => {
|
|
2238
|
+
const st = div.getAttribute("style") || "";
|
|
2239
|
+
return st.includes("width:") && st.includes("height:") && div.children.length === 0 && (div.textContent?.trim().length ?? 0) === 0;
|
|
2240
|
+
});
|
|
2241
|
+
chartKeys.forEach((cKey, idx) => {
|
|
2242
|
+
const target = emptyContainers[idx];
|
|
2243
|
+
if (target) {
|
|
2244
|
+
const xmlStr = strFromU8(unzipped[cKey]);
|
|
2245
|
+
const svg = this.parseAndRenderChartSvg(xmlStr);
|
|
2246
|
+
if (svg) {
|
|
2247
|
+
target.innerHTML = svg;
|
|
2248
|
+
target.style.display = "block";
|
|
2249
|
+
target.style.margin = "12px auto";
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
});
|
|
2253
|
+
}
|
|
2254
|
+
} catch (chartErr) {
|
|
2255
|
+
console.warn("[DocxPlugin] Non-critical error rendering DrawingML charts:", chartErr);
|
|
2256
|
+
}
|
|
2039
2257
|
}
|
|
2040
2258
|
} catch (err) {
|
|
2041
2259
|
console.warn("[DocxPlugin] docx-preview failed, triggering native fallback:", err);
|
|
@@ -2067,64 +2285,74 @@ var DocxPlugin = class {
|
|
|
2067
2285
|
}
|
|
2068
2286
|
let sections = Array.from(wrapper.querySelectorAll("section.docx"));
|
|
2069
2287
|
const cards = Array.from(wrapper.querySelectorAll(".fp-docx-page-card"));
|
|
2070
|
-
if (sections.length
|
|
2071
|
-
const
|
|
2072
|
-
const
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
const
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
nextSec.
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
nextArticle
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
nextSec.appendChild(
|
|
2288
|
+
if (sections.length > 0 && cards.length === 0) {
|
|
2289
|
+
const finalSections = [];
|
|
2290
|
+
for (const singleSec of sections) {
|
|
2291
|
+
const contentContainer = singleSec.querySelector("article") || singleSec;
|
|
2292
|
+
const children = Array.from(contentContainer.children);
|
|
2293
|
+
const pageH = singleSec.offsetHeight > 1300 ? 1122 : Math.max(1056, singleSec.offsetHeight);
|
|
2294
|
+
const secH = singleSec.scrollHeight || singleSec.offsetHeight;
|
|
2295
|
+
if (secH > pageH * 1.25 && children.length > 1) {
|
|
2296
|
+
const childHeights = children.map((c) => {
|
|
2297
|
+
const rectH = c.getBoundingClientRect().height;
|
|
2298
|
+
const offH = c.offsetHeight;
|
|
2299
|
+
const textLen = c.textContent?.trim().length || 0;
|
|
2300
|
+
const estH = Math.max(24, Math.ceil(textLen / 80) * 22 + 16);
|
|
2301
|
+
return Math.max(rectH, offH, estH);
|
|
2302
|
+
});
|
|
2303
|
+
const parent = singleSec.parentElement || wrapper;
|
|
2304
|
+
const headerEl = singleSec.querySelector("header");
|
|
2305
|
+
const footerEl = singleSec.querySelector("footer");
|
|
2306
|
+
contentContainer.innerHTML = "";
|
|
2307
|
+
singleSec.style.minHeight = `${pageH}px`;
|
|
2308
|
+
singleSec.style.boxSizing = "border-box";
|
|
2309
|
+
let curContent = contentContainer;
|
|
2310
|
+
let curSec = singleSec;
|
|
2311
|
+
let curH = 0;
|
|
2312
|
+
const maxH = pageH - 140;
|
|
2313
|
+
finalSections.push(singleSec);
|
|
2314
|
+
for (let i = 0; i < children.length; i++) {
|
|
2315
|
+
const child = children[i];
|
|
2316
|
+
const chH = childHeights[i];
|
|
2317
|
+
curContent.appendChild(child);
|
|
2318
|
+
curH += chH;
|
|
2319
|
+
if (curH >= maxH && i < children.length - 1) {
|
|
2320
|
+
const nextSec = document.createElement("section");
|
|
2321
|
+
nextSec.className = singleSec.className;
|
|
2322
|
+
nextSec.style.cssText = singleSec.style.cssText;
|
|
2323
|
+
nextSec.style.minHeight = `${pageH}px`;
|
|
2324
|
+
nextSec.style.boxSizing = "border-box";
|
|
2325
|
+
nextSec.style.backgroundColor = "#ffffff";
|
|
2326
|
+
nextSec.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
2327
|
+
nextSec.style.borderRadius = "4px";
|
|
2328
|
+
nextSec.style.marginBottom = "24px";
|
|
2329
|
+
if (headerEl) {
|
|
2330
|
+
nextSec.appendChild(headerEl.cloneNode(true));
|
|
2331
|
+
}
|
|
2332
|
+
const nextArticle = document.createElement("article");
|
|
2333
|
+
if (contentContainer.tagName.toLowerCase() === "article") {
|
|
2334
|
+
nextArticle.style.cssText = contentContainer.style.cssText;
|
|
2335
|
+
}
|
|
2336
|
+
nextSec.appendChild(nextArticle);
|
|
2337
|
+
if (footerEl) {
|
|
2338
|
+
nextSec.appendChild(footerEl.cloneNode(true));
|
|
2339
|
+
}
|
|
2340
|
+
if (curSec.nextSibling) {
|
|
2341
|
+
parent.insertBefore(nextSec, curSec.nextSibling);
|
|
2342
|
+
} else {
|
|
2343
|
+
parent.appendChild(nextSec);
|
|
2344
|
+
}
|
|
2345
|
+
finalSections.push(nextSec);
|
|
2346
|
+
curSec = nextSec;
|
|
2347
|
+
curContent = nextArticle;
|
|
2348
|
+
curH = 0;
|
|
2119
2349
|
}
|
|
2120
|
-
parent.appendChild(nextSec);
|
|
2121
|
-
newSections.push(nextSec);
|
|
2122
|
-
curContent = nextArticle;
|
|
2123
|
-
curH = 0;
|
|
2124
2350
|
}
|
|
2351
|
+
} else {
|
|
2352
|
+
finalSections.push(singleSec);
|
|
2125
2353
|
}
|
|
2126
|
-
sections = newSections;
|
|
2127
2354
|
}
|
|
2355
|
+
sections = finalSections;
|
|
2128
2356
|
}
|
|
2129
2357
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2130
2358
|
const totalPages = Math.max(1, pageElements.length);
|
|
@@ -2516,6 +2744,88 @@ var DocxPlugin = class {
|
|
|
2516
2744
|
}
|
|
2517
2745
|
return result;
|
|
2518
2746
|
}
|
|
2747
|
+
parseAndRenderChartSvg(xmlStr, width = 500, height = 260) {
|
|
2748
|
+
const catMatches = [...xmlStr.matchAll(/<c:cat>[\s\S]*?<c:strCache>([\s\S]*?)<\/c:strCache>/g)];
|
|
2749
|
+
let categories = [];
|
|
2750
|
+
if (catMatches.length > 0) {
|
|
2751
|
+
categories = [...catMatches[0][1].matchAll(/<c:v>([^<]+)<\/c:v>/g)].map((m) => m[1]);
|
|
2752
|
+
}
|
|
2753
|
+
if (categories.length === 0) {
|
|
2754
|
+
categories = ["Category 1", "Category 2", "Category 3", "Category 4"];
|
|
2755
|
+
}
|
|
2756
|
+
const defaultColors = ["#004586", "#ff420e", "#ffd320", "#579d1c", "#7e0021", "#83caff"];
|
|
2757
|
+
const sers = [...xmlStr.matchAll(/<c:ser>([\s\S]*?)<\/c:ser>/g)];
|
|
2758
|
+
const series = [];
|
|
2759
|
+
sers.forEach((s, sIdx) => {
|
|
2760
|
+
const titleMatch = s[1].match(/<c:tx>[\s\S]*?<c:v>([^<]+)<\/c:v>/);
|
|
2761
|
+
const title = titleMatch ? titleMatch[1] : `Series ${sIdx + 1}`;
|
|
2762
|
+
const clrMatch = s[1].match(/<a:srgbClr\s+val="([^"]+)"/);
|
|
2763
|
+
const color = clrMatch ? "#" + clrMatch[1] : defaultColors[sIdx % defaultColors.length];
|
|
2764
|
+
const valMatch = s[1].match(/<c:val>[\s\S]*?<c:numCache>([\s\S]*?)<\/c:numCache>/);
|
|
2765
|
+
let values = [];
|
|
2766
|
+
if (valMatch) {
|
|
2767
|
+
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);
|
|
2768
|
+
}
|
|
2769
|
+
series.push({ title, color, values });
|
|
2770
|
+
});
|
|
2771
|
+
if (series.length === 0) return "";
|
|
2772
|
+
let maxVal = 10;
|
|
2773
|
+
series.forEach((s) => s.values.forEach((v) => {
|
|
2774
|
+
if (v > maxVal) maxVal = v;
|
|
2775
|
+
}));
|
|
2776
|
+
maxVal = Math.ceil(maxVal * 1.15);
|
|
2777
|
+
if (maxVal % 2 !== 0) maxVal++;
|
|
2778
|
+
const padLeft = 45;
|
|
2779
|
+
const padBottom = 55;
|
|
2780
|
+
const padTop = 20;
|
|
2781
|
+
const padRight = 20;
|
|
2782
|
+
const plotW = width - padLeft - padRight;
|
|
2783
|
+
const plotH = height - padTop - padBottom;
|
|
2784
|
+
const yTicks = 5;
|
|
2785
|
+
let gridLines = "";
|
|
2786
|
+
for (let i = 0; i <= yTicks; i++) {
|
|
2787
|
+
const val = maxVal / yTicks * i;
|
|
2788
|
+
const y = padTop + plotH - val / maxVal * plotH;
|
|
2789
|
+
gridLines += `<line x1="${padLeft}" y1="${y}" x2="${padLeft + plotW}" y2="${y}" stroke="#e2e8f0" stroke-width="1" />`;
|
|
2790
|
+
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>`;
|
|
2791
|
+
}
|
|
2792
|
+
const numCats = categories.length;
|
|
2793
|
+
const numSers = series.length;
|
|
2794
|
+
const groupW = plotW / numCats;
|
|
2795
|
+
const barW = Math.max(8, Math.min(28, groupW * 0.7 / numSers));
|
|
2796
|
+
const groupPad = (groupW - barW * numSers) / 2;
|
|
2797
|
+
let bars = "";
|
|
2798
|
+
let catLabels = "";
|
|
2799
|
+
for (let c = 0; c < numCats; c++) {
|
|
2800
|
+
const catX = padLeft + c * groupW;
|
|
2801
|
+
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>`;
|
|
2802
|
+
for (let s = 0; s < numSers; s++) {
|
|
2803
|
+
const val = series[s].values[c] ?? 0;
|
|
2804
|
+
const bH = Math.max(0, val / maxVal * plotH);
|
|
2805
|
+
const bX = catX + groupPad + s * barW;
|
|
2806
|
+
const bY = padTop + plotH - bH;
|
|
2807
|
+
bars += `<rect x="${bX}" y="${bY}" width="${barW - 2}" height="${bH}" fill="${series[s].color}" rx="1" />`;
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
let legend = "";
|
|
2811
|
+
const legY = height - 12;
|
|
2812
|
+
let legX = padLeft + (plotW - numSers * 100) / 2;
|
|
2813
|
+
series.forEach((s) => {
|
|
2814
|
+
legend += `<rect x="${legX}" y="${legY - 9}" width="10" height="10" fill="${s.color}" rx="2" />`;
|
|
2815
|
+
legend += `<text x="${legX + 15}" y="${legY}" font-size="11" fill="#475569" font-family="Calibri, sans-serif">${s.title}</text>`;
|
|
2816
|
+
legX += 95;
|
|
2817
|
+
});
|
|
2818
|
+
return `
|
|
2819
|
+
<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">
|
|
2820
|
+
${gridLines}
|
|
2821
|
+
<line x1="${padLeft}" y1="${padTop + plotH}" x2="${padLeft + plotW}" y2="${padTop + plotH}" stroke="#94a3b8" stroke-width="1.5" />
|
|
2822
|
+
<line x1="${padLeft}" y1="${padTop}" x2="${padLeft}" y2="${padTop + plotH}" stroke="#94a3b8" stroke-width="1.5" />
|
|
2823
|
+
${bars}
|
|
2824
|
+
${catLabels}
|
|
2825
|
+
${legend}
|
|
2826
|
+
</svg>
|
|
2827
|
+
`.trim();
|
|
2828
|
+
}
|
|
2519
2829
|
};
|
|
2520
2830
|
function docxPlugin() {
|
|
2521
2831
|
return new DocxPlugin();
|
|
@@ -3082,6 +3392,16 @@ var CodePlugin = class {
|
|
|
3082
3392
|
execute: () => {
|
|
3083
3393
|
instance.print?.();
|
|
3084
3394
|
}
|
|
3395
|
+
},
|
|
3396
|
+
{
|
|
3397
|
+
id: "open-window",
|
|
3398
|
+
icon: "open-window",
|
|
3399
|
+
label: "Open in Separate Full Window",
|
|
3400
|
+
type: "button",
|
|
3401
|
+
group: "actions",
|
|
3402
|
+
execute: () => {
|
|
3403
|
+
instance.openInSeparateWindow?.();
|
|
3404
|
+
}
|
|
3085
3405
|
}
|
|
3086
3406
|
);
|
|
3087
3407
|
return actions;
|
|
@@ -4250,6 +4570,14 @@ var RtfPlugin = class {
|
|
|
4250
4570
|
type: "button",
|
|
4251
4571
|
group: "actions",
|
|
4252
4572
|
execute: () => instance.print?.()
|
|
4573
|
+
},
|
|
4574
|
+
{
|
|
4575
|
+
id: "open-window",
|
|
4576
|
+
icon: "open-window",
|
|
4577
|
+
label: "Open in Separate Full Window",
|
|
4578
|
+
type: "button",
|
|
4579
|
+
group: "actions",
|
|
4580
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
4253
4581
|
}
|
|
4254
4582
|
);
|
|
4255
4583
|
return actions;
|
|
@@ -4302,59 +4630,54 @@ var RtfPlugin = class {
|
|
|
4302
4630
|
}
|
|
4303
4631
|
const doc = new RTFJS.Document(ctx.buffer, {});
|
|
4304
4632
|
const htmlElements = await doc.render();
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
const secH = singleEl.offsetHeight || singleEl.scrollHeight;
|
|
4310
|
-
if (secH > 1300 && children.length > 1) {
|
|
4311
|
-
const childHeights = children.map((c) => {
|
|
4312
|
-
const rectH = c.getBoundingClientRect().height;
|
|
4313
|
-
const offH = c.offsetHeight;
|
|
4314
|
-
const textLen = c.textContent?.trim().length || 0;
|
|
4315
|
-
const estH = Math.max(24, Math.ceil(textLen / 80) * 22 + 16);
|
|
4316
|
-
return Math.max(rectH, offH, estH);
|
|
4317
|
-
});
|
|
4318
|
-
wrapper.innerHTML = "";
|
|
4319
|
-
const createRtfCard = () => {
|
|
4320
|
-
const card = document.createElement("div");
|
|
4321
|
-
card.className = "fp-rtf-page-card";
|
|
4322
|
-
card.style.backgroundColor = "#ffffff";
|
|
4323
|
-
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
4324
|
-
card.style.borderRadius = "4px";
|
|
4325
|
-
card.style.padding = "72px 56px";
|
|
4326
|
-
card.style.width = "816px";
|
|
4327
|
-
card.style.minHeight = "1056px";
|
|
4328
|
-
card.style.boxSizing = "border-box";
|
|
4329
|
-
card.style.marginBottom = "24px";
|
|
4330
|
-
return card;
|
|
4331
|
-
};
|
|
4332
|
-
let curCard = createRtfCard();
|
|
4333
|
-
wrapper.appendChild(curCard);
|
|
4334
|
-
pageElements = [curCard];
|
|
4335
|
-
let curH = 0;
|
|
4336
|
-
const maxH = 920;
|
|
4337
|
-
for (let i = 0; i < children.length; i++) {
|
|
4338
|
-
const child = children[i];
|
|
4339
|
-
const chH = childHeights[i];
|
|
4340
|
-
curCard.appendChild(child);
|
|
4341
|
-
curH += chH;
|
|
4342
|
-
if (curH >= maxH && i < children.length - 1) {
|
|
4343
|
-
curCard = createRtfCard();
|
|
4344
|
-
wrapper.appendChild(curCard);
|
|
4345
|
-
pageElements.push(curCard);
|
|
4346
|
-
curH = 0;
|
|
4347
|
-
}
|
|
4348
|
-
}
|
|
4633
|
+
const contentNodes = [];
|
|
4634
|
+
for (const item of htmlElements) {
|
|
4635
|
+
if (item.children && item.children.length > 0 && !item.tagName.toLowerCase().startsWith("table")) {
|
|
4636
|
+
contentNodes.push(...Array.from(item.children));
|
|
4349
4637
|
} else {
|
|
4350
|
-
|
|
4638
|
+
contentNodes.push(item);
|
|
4351
4639
|
}
|
|
4352
|
-
}
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4640
|
+
}
|
|
4641
|
+
wrapper.innerHTML = "";
|
|
4642
|
+
contentNodes.forEach((node) => wrapper.appendChild(node));
|
|
4643
|
+
const childHeights = contentNodes.map((c) => {
|
|
4644
|
+
const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
|
|
4645
|
+
const offH = c.offsetHeight || 0;
|
|
4646
|
+
const textLen = c.textContent?.trim().length || 0;
|
|
4647
|
+
const estH = Math.max(24, Math.ceil(textLen / 75) * 22 + 14);
|
|
4648
|
+
return Math.max(rectH, offH, estH);
|
|
4649
|
+
});
|
|
4650
|
+
wrapper.innerHTML = "";
|
|
4651
|
+
const createRtfCard = () => {
|
|
4652
|
+
const card = document.createElement("div");
|
|
4653
|
+
card.className = "fp-rtf-page-card";
|
|
4654
|
+
card.style.backgroundColor = "#ffffff";
|
|
4655
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
4656
|
+
card.style.borderRadius = "4px";
|
|
4657
|
+
card.style.padding = "72px 56px";
|
|
4658
|
+
card.style.width = "816px";
|
|
4659
|
+
card.style.minHeight = "1056px";
|
|
4660
|
+
card.style.boxSizing = "border-box";
|
|
4661
|
+
card.style.marginBottom = "24px";
|
|
4662
|
+
card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4663
|
+
card.style.lineHeight = "1.6";
|
|
4664
|
+
return card;
|
|
4665
|
+
};
|
|
4666
|
+
let curCard = createRtfCard();
|
|
4667
|
+
wrapper.appendChild(curCard);
|
|
4668
|
+
pageElements = [curCard];
|
|
4669
|
+
let curH = 0;
|
|
4670
|
+
const maxH = 912;
|
|
4671
|
+
for (let i = 0; i < contentNodes.length; i++) {
|
|
4672
|
+
const child = contentNodes[i];
|
|
4673
|
+
const chH = childHeights[i];
|
|
4674
|
+
curCard.appendChild(child);
|
|
4675
|
+
curH += chH;
|
|
4676
|
+
if (curH >= maxH && i < contentNodes.length - 1) {
|
|
4677
|
+
curCard = createRtfCard();
|
|
4678
|
+
wrapper.appendChild(curCard);
|
|
4679
|
+
pageElements.push(curCard);
|
|
4680
|
+
curH = 0;
|
|
4358
4681
|
}
|
|
4359
4682
|
}
|
|
4360
4683
|
} catch (err) {
|
|
@@ -4723,6 +5046,14 @@ var OpenDocumentPlugin = class {
|
|
|
4723
5046
|
type: "button",
|
|
4724
5047
|
group: "actions",
|
|
4725
5048
|
execute: () => instance.print?.()
|
|
5049
|
+
},
|
|
5050
|
+
{
|
|
5051
|
+
id: "open-window",
|
|
5052
|
+
icon: "open-window",
|
|
5053
|
+
label: "Open in Separate Full Window",
|
|
5054
|
+
type: "button",
|
|
5055
|
+
group: "actions",
|
|
5056
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
4726
5057
|
}
|
|
4727
5058
|
);
|
|
4728
5059
|
return actions;
|
|
@@ -5311,6 +5642,14 @@ var DocPlugin = class {
|
|
|
5311
5642
|
type: "button",
|
|
5312
5643
|
group: "actions",
|
|
5313
5644
|
execute: () => instance.print?.()
|
|
5645
|
+
},
|
|
5646
|
+
{
|
|
5647
|
+
id: "open-window",
|
|
5648
|
+
icon: "open-window",
|
|
5649
|
+
label: "Open in Separate Full Window",
|
|
5650
|
+
type: "button",
|
|
5651
|
+
group: "actions",
|
|
5652
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
5314
5653
|
}
|
|
5315
5654
|
);
|
|
5316
5655
|
return actions;
|
|
@@ -5602,9 +5941,25 @@ var DocPlugin = class {
|
|
|
5602
5941
|
heuristicTextExtraction(buffer) {
|
|
5603
5942
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
5604
5943
|
}
|
|
5944
|
+
cleanWordDocFields(text) {
|
|
5945
|
+
if (!text) return "";
|
|
5946
|
+
let cleaned = text.replace(
|
|
5947
|
+
/\x13\s*HYPERLINK\s*"?([^"\x14]+)"?\s*\x14([\s\S]*?)\x15/gi,
|
|
5948
|
+
(_match, url, label) => {
|
|
5949
|
+
const cleanUrl = url.trim();
|
|
5950
|
+
const cleanLabel = label.trim() || cleanUrl;
|
|
5951
|
+
return `<a href="${cleanUrl}" target="_blank" rel="noopener noreferrer" style="color: #2563eb; text-decoration: underline;">${cleanLabel}</a>`;
|
|
5952
|
+
}
|
|
5953
|
+
);
|
|
5954
|
+
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g, "$1");
|
|
5955
|
+
cleaned = cleaned.replace(/\x13[^\x15]*\x15/g, "");
|
|
5956
|
+
cleaned = cleaned.replace(/[\x13\x14\x15]/g, "");
|
|
5957
|
+
return cleaned;
|
|
5958
|
+
}
|
|
5605
5959
|
splitIntoPages(text) {
|
|
5606
5960
|
if (!text) return [""];
|
|
5607
|
-
const
|
|
5961
|
+
const cleanedText = this.cleanWordDocFields(text);
|
|
5962
|
+
const normalized = cleanedText.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ");
|
|
5608
5963
|
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);
|
|
5609
5964
|
if (explicitParts.length === 0) explicitParts.push(normalized);
|
|
5610
5965
|
const maxLinesPerPage = 32;
|
|
@@ -5615,7 +5970,8 @@ var DocPlugin = class {
|
|
|
5615
5970
|
let currentLines = [];
|
|
5616
5971
|
let count = 0;
|
|
5617
5972
|
for (const line of lines) {
|
|
5618
|
-
const
|
|
5973
|
+
const plainLine = line.replace(/<[^>]+>/g, "");
|
|
5974
|
+
const vLines = Math.max(1, Math.ceil((plainLine.length || 1) / charsPerLine));
|
|
5619
5975
|
if (count + vLines > maxLinesPerPage && currentLines.length > 0) {
|
|
5620
5976
|
finalPages.push(currentLines.join("\n"));
|
|
5621
5977
|
currentLines = [];
|
|
@@ -5691,25 +6047,26 @@ var DocPlugin = class {
|
|
|
5691
6047
|
i++;
|
|
5692
6048
|
continue;
|
|
5693
6049
|
}
|
|
6050
|
+
const sanitizeOptions = { ADD_TAGS: ["a"], ADD_ATTR: ["href", "target", "rel", "style"] };
|
|
5694
6051
|
if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
|
|
5695
6052
|
if (inList) {
|
|
5696
6053
|
html += "</ul>";
|
|
5697
6054
|
inList = false;
|
|
5698
6055
|
}
|
|
5699
|
-
html += `<h2 style="font-size: 16px; font-weight: 700; color: #1e3a8a; margin: 16px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6.sanitize(line)}</h2>`;
|
|
6056
|
+
html += `<h2 style="font-size: 16px; font-weight: 700; color: #1e3a8a; margin: 16px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6.sanitize(line, sanitizeOptions)}</h2>`;
|
|
5700
6057
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
5701
6058
|
if (!inList) {
|
|
5702
6059
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
5703
6060
|
inList = true;
|
|
5704
6061
|
}
|
|
5705
6062
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
5706
|
-
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6.sanitize(bulletText)}</li>`;
|
|
6063
|
+
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6.sanitize(bulletText, sanitizeOptions)}</li>`;
|
|
5707
6064
|
} else {
|
|
5708
6065
|
if (inList) {
|
|
5709
6066
|
html += "</ul>";
|
|
5710
6067
|
inList = false;
|
|
5711
6068
|
}
|
|
5712
|
-
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6.sanitize(line)}</p>`;
|
|
6069
|
+
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6.sanitize(line, sanitizeOptions)}</p>`;
|
|
5713
6070
|
}
|
|
5714
6071
|
i++;
|
|
5715
6072
|
}
|