@files-preview-app/preview-file 1.2.9 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular.cjs +668 -154
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +667 -154
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +711 -154
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +709 -155
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +668 -154
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +667 -154
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +668 -154
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +667 -154
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
package/dist/vue.cjs
CHANGED
|
@@ -17,6 +17,7 @@ var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
|
|
|
17
17
|
var OrbitControls_js = require('three/examples/jsm/controls/OrbitControls.js');
|
|
18
18
|
var RTFJS = require('rtf.js/dist/RTFJS.bundle.js');
|
|
19
19
|
|
|
20
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
20
21
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
21
22
|
|
|
22
23
|
function _interopNamespace(e) {
|
|
@@ -40,6 +41,7 @@ function _interopNamespace(e) {
|
|
|
40
41
|
var DOMPurify6__default = /*#__PURE__*/_interopDefault(DOMPurify6);
|
|
41
42
|
var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
|
|
42
43
|
var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
44
|
+
var fflate__namespace = /*#__PURE__*/_interopNamespace(fflate);
|
|
43
45
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
44
46
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
45
47
|
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
@@ -369,16 +371,21 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
369
371
|
metadata.mimeType = source.type || void 0;
|
|
370
372
|
metadata.extension = extractExtension(source.name);
|
|
371
373
|
buffer = await source.arrayBuffer();
|
|
372
|
-
} else if (source instanceof Blob) {
|
|
374
|
+
} else if (source instanceof Blob || source && typeof source.arrayBuffer === "function" && typeof source.size === "number") {
|
|
373
375
|
metadata.size = source.size;
|
|
374
376
|
metadata.mimeType = source.type || void 0;
|
|
377
|
+
if (source.name) {
|
|
378
|
+
metadata.name = source.name;
|
|
379
|
+
metadata.extension = extractExtension(source.name);
|
|
380
|
+
}
|
|
375
381
|
buffer = await source.arrayBuffer();
|
|
376
|
-
} else if (source instanceof ArrayBuffer) {
|
|
382
|
+
} else if (source instanceof ArrayBuffer || Object.prototype.toString.call(source) === "[object ArrayBuffer]" || source && typeof source.byteLength === "number" && typeof source.slice === "function") {
|
|
377
383
|
buffer = source;
|
|
378
|
-
} else if (source instanceof Uint8Array) {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
384
|
+
} else if (source instanceof Uint8Array || ArrayBuffer.isView(source)) {
|
|
385
|
+
const view = source;
|
|
386
|
+
buffer = view.buffer.slice(
|
|
387
|
+
view.byteOffset,
|
|
388
|
+
view.byteOffset + view.byteLength
|
|
382
389
|
);
|
|
383
390
|
} else {
|
|
384
391
|
throw new Error("Unsupported file source type");
|
|
@@ -463,6 +470,45 @@ function createElement(tag, attrs, ...children) {
|
|
|
463
470
|
}
|
|
464
471
|
return el;
|
|
465
472
|
}
|
|
473
|
+
var DB_NAME = "PreviewFileTransferDB";
|
|
474
|
+
var DB_STORE = "transfers";
|
|
475
|
+
function openDB() {
|
|
476
|
+
return new Promise((resolve, reject) => {
|
|
477
|
+
if (typeof indexedDB === "undefined") {
|
|
478
|
+
return reject(new Error("IndexedDB is not available"));
|
|
479
|
+
}
|
|
480
|
+
const req = indexedDB.open(DB_NAME, 1);
|
|
481
|
+
req.onupgradeneeded = () => {
|
|
482
|
+
const db = req.result;
|
|
483
|
+
if (!db.objectStoreNames.contains(DB_STORE)) {
|
|
484
|
+
db.createObjectStore(DB_STORE, { keyPath: "id" });
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
req.onsuccess = () => resolve(req.result);
|
|
488
|
+
req.onerror = () => reject(req.error);
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
async function saveTransferPayload(id, payload) {
|
|
492
|
+
if (typeof window !== "undefined") {
|
|
493
|
+
try {
|
|
494
|
+
window[id] = payload;
|
|
495
|
+
window.__lastTransfer = payload;
|
|
496
|
+
} catch {
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
try {
|
|
500
|
+
const db = await openDB();
|
|
501
|
+
return new Promise((resolve, reject) => {
|
|
502
|
+
const tx = db.transaction(DB_STORE, "readwrite");
|
|
503
|
+
const store = tx.objectStore(DB_STORE);
|
|
504
|
+
store.put({ id, ...payload, timestamp: Date.now() });
|
|
505
|
+
tx.oncomplete = () => resolve();
|
|
506
|
+
tx.onerror = () => reject(tx.error);
|
|
507
|
+
});
|
|
508
|
+
} catch (e) {
|
|
509
|
+
console.warn("[saveTransferPayload] IndexedDB store warning:", e);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
466
512
|
var ICON_ZOOM_IN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="11" y1="8" x2="11" y2="14"></line><line x1="8" y1="11" x2="14" y2="11"></line></svg>`;
|
|
467
513
|
var ICON_ZOOM_OUT = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="8" y1="11" x2="14" y2="11"></line></svg>`;
|
|
468
514
|
var ICON_FIT_PAGE = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"></rect><line x1="8" y1="12" x2="16" y2="12"></line><polyline points="11 9 8 12 11 15"></polyline><polyline points="13 9 16 12 13 15"></polyline></svg>`;
|
|
@@ -482,6 +528,7 @@ var ICON_COPY = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" str
|
|
|
482
528
|
var ICON_FAST_FORWARD = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 19 22 12 13 5 13 19"></polygon><polygon points="2 19 11 12 2 5 2 19"></polygon></svg>`;
|
|
483
529
|
var ICON_REWIND = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="11 19 2 12 11 5 11 19"></polygon><polygon points="22 19 13 12 22 5 22 19"></polygon></svg>`;
|
|
484
530
|
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>`;
|
|
531
|
+
var ICON_EXTERNAL_WINDOW = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>`;
|
|
485
532
|
var ICON_MAP = {
|
|
486
533
|
"zoom-in": ICON_ZOOM_IN,
|
|
487
534
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -508,7 +555,9 @@ var ICON_MAP = {
|
|
|
508
555
|
"forward-10": ICON_FAST_FORWARD,
|
|
509
556
|
"rewind": ICON_REWIND,
|
|
510
557
|
"replay-10": ICON_REWIND,
|
|
511
|
-
"speed": ICON_SPEED
|
|
558
|
+
"speed": ICON_SPEED,
|
|
559
|
+
"open-window": ICON_EXTERNAL_WINDOW,
|
|
560
|
+
"external-window": ICON_EXTERNAL_WINDOW
|
|
512
561
|
};
|
|
513
562
|
var ToolbarController = class {
|
|
514
563
|
el;
|
|
@@ -651,9 +700,11 @@ var ToolbarController = class {
|
|
|
651
700
|
type: "button",
|
|
652
701
|
"data-action-id": id
|
|
653
702
|
});
|
|
654
|
-
const
|
|
655
|
-
if (
|
|
656
|
-
btn.innerHTML =
|
|
703
|
+
const internalSvg = ICON_MAP[iconHtml] || ICON_MAP[id];
|
|
704
|
+
if (internalSvg) {
|
|
705
|
+
btn.innerHTML = internalSvg;
|
|
706
|
+
} else if (iconHtml && iconHtml.startsWith("<svg")) {
|
|
707
|
+
btn.innerHTML = sanitizeSVG(iconHtml);
|
|
657
708
|
} else {
|
|
658
709
|
btn.textContent = title || id;
|
|
659
710
|
}
|
|
@@ -725,7 +776,7 @@ var ThumbnailPanel = class {
|
|
|
725
776
|
}
|
|
726
777
|
}
|
|
727
778
|
};
|
|
728
|
-
var FilePreviewViewer = class {
|
|
779
|
+
var FilePreviewViewer = class _FilePreviewViewer {
|
|
729
780
|
plugins = [];
|
|
730
781
|
activeInstance = null;
|
|
731
782
|
abortController = null;
|
|
@@ -762,6 +813,7 @@ var FilePreviewViewer = class {
|
|
|
762
813
|
* Preview a file in the given container element.
|
|
763
814
|
*/
|
|
764
815
|
async preview(container, source, options = {}) {
|
|
816
|
+
this.currentOptions = options;
|
|
765
817
|
this.abort();
|
|
766
818
|
this.abortController = new AbortController();
|
|
767
819
|
const { signal } = this.abortController;
|
|
@@ -771,7 +823,10 @@ var FilePreviewViewer = class {
|
|
|
771
823
|
this.showLoading();
|
|
772
824
|
try {
|
|
773
825
|
const { buffer, metadata } = await sourceToArrayBuffer(source, signal);
|
|
774
|
-
|
|
826
|
+
if (options.metadata) {
|
|
827
|
+
Object.assign(metadata, options.metadata);
|
|
828
|
+
}
|
|
829
|
+
this.currentBuffer = buffer.slice(0);
|
|
775
830
|
this.currentMetadata = metadata;
|
|
776
831
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
777
832
|
const fileInfo = { metadata, buffer };
|
|
@@ -801,6 +856,7 @@ var FilePreviewViewer = class {
|
|
|
801
856
|
}
|
|
802
857
|
});
|
|
803
858
|
this.activeInstance = instance;
|
|
859
|
+
instance.openInSeparateWindow = () => this.openInSeparateWindow();
|
|
804
860
|
this.hideLoading();
|
|
805
861
|
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
806
862
|
if (options.showToolbar !== false && this.toolbar) {
|
|
@@ -810,26 +866,16 @@ var FilePreviewViewer = class {
|
|
|
810
866
|
actions.push({
|
|
811
867
|
id: "fullscreen",
|
|
812
868
|
icon: "fullscreen",
|
|
813
|
-
label: "
|
|
869
|
+
label: "Fullscreen",
|
|
814
870
|
type: "button",
|
|
815
871
|
group: "view",
|
|
816
|
-
execute:
|
|
872
|
+
execute: () => {
|
|
817
873
|
try {
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
if (this.wrapperEl?.requestFullscreen) {
|
|
822
|
-
await this.wrapperEl.requestFullscreen().catch(() => {
|
|
823
|
-
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
824
|
-
});
|
|
825
|
-
} else {
|
|
826
|
-
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
827
|
-
}
|
|
874
|
+
if (!document.fullscreenElement) {
|
|
875
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
876
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
828
877
|
} else {
|
|
829
|
-
|
|
830
|
-
await document.exitFullscreen().catch(() => {
|
|
831
|
-
});
|
|
832
|
-
}
|
|
878
|
+
document.exitFullscreen?.();
|
|
833
879
|
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
834
880
|
}
|
|
835
881
|
} catch {
|
|
@@ -841,6 +887,28 @@ var FilePreviewViewer = class {
|
|
|
841
887
|
}
|
|
842
888
|
});
|
|
843
889
|
}
|
|
890
|
+
const openWinAction = actions.find((a) => a.id === "open-window");
|
|
891
|
+
if (openWinAction) {
|
|
892
|
+
if (options?._isSeparateWindow) {
|
|
893
|
+
const idx = actions.indexOf(openWinAction);
|
|
894
|
+
if (idx !== -1) actions.splice(idx, 1);
|
|
895
|
+
} else {
|
|
896
|
+
openWinAction.execute = () => {
|
|
897
|
+
this.openInSeparateWindow();
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
} else if (!options?._isSeparateWindow) {
|
|
901
|
+
actions.push({
|
|
902
|
+
id: "open-window",
|
|
903
|
+
icon: "open-window",
|
|
904
|
+
label: "Open in Separate Full Window",
|
|
905
|
+
type: "button",
|
|
906
|
+
group: "actions",
|
|
907
|
+
execute: () => {
|
|
908
|
+
this.openInSeparateWindow();
|
|
909
|
+
}
|
|
910
|
+
});
|
|
911
|
+
}
|
|
844
912
|
this.toolbar.update(actions);
|
|
845
913
|
this.toolbar.show();
|
|
846
914
|
}
|
|
@@ -873,6 +941,104 @@ var FilePreviewViewer = class {
|
|
|
873
941
|
throw error;
|
|
874
942
|
}
|
|
875
943
|
}
|
|
944
|
+
/**
|
|
945
|
+
* Opens the current file preview in a separate full browser window.
|
|
946
|
+
*/
|
|
947
|
+
openInSeparateWindow() {
|
|
948
|
+
if (!this.currentBuffer) {
|
|
949
|
+
console.warn("[FilePreviewViewer] No active file buffer to open in separate window");
|
|
950
|
+
return null;
|
|
951
|
+
}
|
|
952
|
+
if (this.currentOptions.onOpenSeparateWindow) {
|
|
953
|
+
return this.currentOptions.onOpenSeparateWindow({
|
|
954
|
+
buffer: this.currentBuffer,
|
|
955
|
+
metadata: this.currentMetadata || { name: "Document" },
|
|
956
|
+
options: this.currentOptions
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
const transferId = "fp_win_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8);
|
|
960
|
+
let clonedBuffer;
|
|
961
|
+
try {
|
|
962
|
+
clonedBuffer = this.currentBuffer.slice(0);
|
|
963
|
+
} catch {
|
|
964
|
+
clonedBuffer = this.currentBuffer;
|
|
965
|
+
}
|
|
966
|
+
const payload = {
|
|
967
|
+
buffer: clonedBuffer,
|
|
968
|
+
metadata: this.currentMetadata ? { ...this.currentMetadata } : void 0,
|
|
969
|
+
options: { ...this.currentOptions, _isSeparateWindow: true }
|
|
970
|
+
};
|
|
971
|
+
if (typeof window !== "undefined") {
|
|
972
|
+
try {
|
|
973
|
+
window[transferId] = payload;
|
|
974
|
+
window.__lastTransfer = payload;
|
|
975
|
+
} catch {
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
saveTransferPayload(transferId, payload).catch((err) => {
|
|
979
|
+
console.warn("[FilePreviewViewer] Transfer payload save warning:", err);
|
|
980
|
+
});
|
|
981
|
+
let targetUrl = null;
|
|
982
|
+
if (this.currentOptions.standaloneViewerUrl) {
|
|
983
|
+
const u = new URL(this.currentOptions.standaloneViewerUrl, window.location.href);
|
|
984
|
+
u.searchParams.set("mode", "fullscreen");
|
|
985
|
+
u.searchParams.set("transferId", transferId);
|
|
986
|
+
targetUrl = u.toString();
|
|
987
|
+
} else if (typeof window !== "undefined" && window.location?.href && !window.location.href.startsWith("about:")) {
|
|
988
|
+
const u = new URL(window.location.href);
|
|
989
|
+
u.searchParams.set("mode", "fullscreen");
|
|
990
|
+
u.searchParams.set("transferId", transferId);
|
|
991
|
+
targetUrl = u.toString();
|
|
992
|
+
}
|
|
993
|
+
if (targetUrl) {
|
|
994
|
+
const newWin2 = window.open(targetUrl, "_blank");
|
|
995
|
+
if (!newWin2) {
|
|
996
|
+
alert("Popup blocker prevented opening the preview in a separate window. Please allow popups for this site.");
|
|
997
|
+
return null;
|
|
998
|
+
}
|
|
999
|
+
return newWin2;
|
|
1000
|
+
}
|
|
1001
|
+
const title = (this.currentMetadata?.name || "Document Preview") + " - Full Preview";
|
|
1002
|
+
const newWin = window.open("", "_blank");
|
|
1003
|
+
if (!newWin) {
|
|
1004
|
+
alert("Popup blocker prevented opening the preview in a separate window. Please allow popups for this site.");
|
|
1005
|
+
return null;
|
|
1006
|
+
}
|
|
1007
|
+
newWin.document.title = title;
|
|
1008
|
+
newWin.document.body.style.margin = "0";
|
|
1009
|
+
newWin.document.body.style.padding = "0";
|
|
1010
|
+
newWin.document.body.style.width = "100vw";
|
|
1011
|
+
newWin.document.body.style.height = "100vh";
|
|
1012
|
+
newWin.document.body.style.overflow = "hidden";
|
|
1013
|
+
newWin.document.body.style.backgroundColor = "#f8fafc";
|
|
1014
|
+
const headNodes = document.querySelectorAll('link[rel="stylesheet"], style');
|
|
1015
|
+
headNodes.forEach((node) => {
|
|
1016
|
+
newWin.document.head.appendChild(node.cloneNode(true));
|
|
1017
|
+
});
|
|
1018
|
+
const root = newWin.document.createElement("div");
|
|
1019
|
+
root.id = "full-window-preview-root";
|
|
1020
|
+
root.style.width = "100%";
|
|
1021
|
+
root.style.height = "100%";
|
|
1022
|
+
root.style.overflow = "hidden";
|
|
1023
|
+
newWin.document.body.appendChild(root);
|
|
1024
|
+
const separateViewer = new _FilePreviewViewer();
|
|
1025
|
+
for (const plugin of this.plugins) {
|
|
1026
|
+
separateViewer.registerPlugin(plugin);
|
|
1027
|
+
}
|
|
1028
|
+
separateViewer.preview(root, this.currentBuffer.slice(0), {
|
|
1029
|
+
...this.currentOptions,
|
|
1030
|
+
showToolbar: true,
|
|
1031
|
+
toolbarPosition: "top",
|
|
1032
|
+
metadata: this.currentMetadata || void 0,
|
|
1033
|
+
_isSeparateWindow: true
|
|
1034
|
+
}).catch((err) => {
|
|
1035
|
+
console.error("[FilePreviewViewer] Error rendering in separate window:", err);
|
|
1036
|
+
});
|
|
1037
|
+
newWin.addEventListener("beforeunload", () => {
|
|
1038
|
+
separateViewer.destroy();
|
|
1039
|
+
});
|
|
1040
|
+
return newWin;
|
|
1041
|
+
}
|
|
876
1042
|
/**
|
|
877
1043
|
* Subscribe to viewer events.
|
|
878
1044
|
*/
|
|
@@ -1278,8 +1444,20 @@ var CfbfReader = class {
|
|
|
1278
1444
|
}
|
|
1279
1445
|
};
|
|
1280
1446
|
if (typeof window !== "undefined" && pdfjsLib__namespace.GlobalWorkerOptions) {
|
|
1281
|
-
if (!pdfjsLib__namespace.GlobalWorkerOptions.workerSrc) {
|
|
1282
|
-
|
|
1447
|
+
if (!pdfjsLib__namespace.GlobalWorkerOptions.workerPort && !pdfjsLib__namespace.GlobalWorkerOptions.workerSrc) {
|
|
1448
|
+
const customWorker = window.__PDF_WORKER_SRC__;
|
|
1449
|
+
if (customWorker) {
|
|
1450
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = customWorker;
|
|
1451
|
+
} else {
|
|
1452
|
+
try {
|
|
1453
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerPort = new Worker(
|
|
1454
|
+
new URL("pdfjs-dist/build/pdf.worker.min.mjs", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('vue.cjs', document.baseURI).href))),
|
|
1455
|
+
{ type: "module" }
|
|
1456
|
+
);
|
|
1457
|
+
} catch {
|
|
1458
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = "./pdf.worker.min.mjs";
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1283
1461
|
}
|
|
1284
1462
|
}
|
|
1285
1463
|
var PdfPlugin = class {
|
|
@@ -1373,6 +1551,14 @@ var PdfPlugin = class {
|
|
|
1373
1551
|
type: "button",
|
|
1374
1552
|
group: "actions",
|
|
1375
1553
|
execute: () => instance.print?.()
|
|
1554
|
+
},
|
|
1555
|
+
{
|
|
1556
|
+
id: "open-window",
|
|
1557
|
+
icon: "open-window",
|
|
1558
|
+
label: "Open in Separate Full Window",
|
|
1559
|
+
type: "button",
|
|
1560
|
+
group: "actions",
|
|
1561
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
1376
1562
|
}
|
|
1377
1563
|
];
|
|
1378
1564
|
}
|
|
@@ -1422,18 +1608,21 @@ var PdfPlugin = class {
|
|
|
1422
1608
|
indicator.style.pointerEvents = "none";
|
|
1423
1609
|
container.appendChild(indicator);
|
|
1424
1610
|
ctx.container.appendChild(container);
|
|
1611
|
+
const standardFontsUrl = typeof window !== "undefined" && window.__PDF_STANDARD_FONTS_URL__ || "./standard_fonts/";
|
|
1612
|
+
const cmapsUrl = typeof window !== "undefined" && window.__PDF_CMAPS_URL__ || "./cmaps/";
|
|
1425
1613
|
const loadingTask = pdfjsLib__namespace.getDocument({
|
|
1426
|
-
data: new Uint8Array(ctx.buffer),
|
|
1427
|
-
cMapUrl:
|
|
1614
|
+
data: new Uint8Array(ctx.buffer.slice(0)),
|
|
1615
|
+
cMapUrl: cmapsUrl,
|
|
1428
1616
|
cMapPacked: true,
|
|
1429
|
-
standardFontDataUrl:
|
|
1617
|
+
standardFontDataUrl: standardFontsUrl,
|
|
1618
|
+
verbosity: 0
|
|
1430
1619
|
});
|
|
1431
1620
|
const pdfDoc = await loadingTask.promise;
|
|
1432
1621
|
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1433
1622
|
let currentPage = 1;
|
|
1434
1623
|
let zoomScale = 1;
|
|
1435
1624
|
let rotation = 0;
|
|
1436
|
-
let fitMode = "
|
|
1625
|
+
let fitMode = "page";
|
|
1437
1626
|
let currentRenderTask = null;
|
|
1438
1627
|
const renderPage = async (pageNum) => {
|
|
1439
1628
|
if (currentRenderTask) {
|
|
@@ -1453,15 +1642,15 @@ var PdfPlugin = class {
|
|
|
1453
1642
|
const containerWidth = container.clientWidth || 900;
|
|
1454
1643
|
const containerHeight = container.clientHeight || 700;
|
|
1455
1644
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1456
|
-
const availWidth = Math.max(
|
|
1457
|
-
const availHeight = Math.max(
|
|
1645
|
+
const availWidth = Math.max(320, containerWidth - 48);
|
|
1646
|
+
const availHeight = Math.max(550, containerHeight - 88);
|
|
1458
1647
|
const scaleW = availWidth / unscaledVp.width;
|
|
1459
1648
|
const scaleH = availHeight / unscaledVp.height;
|
|
1460
1649
|
let fitScale;
|
|
1461
1650
|
if (fitMode === "page") {
|
|
1462
|
-
fitScale = Math.max(0.
|
|
1651
|
+
fitScale = Math.max(0.4, Math.min(scaleW, scaleH));
|
|
1463
1652
|
} else {
|
|
1464
|
-
fitScale = Math.max(0.65, Math.min(1.
|
|
1653
|
+
fitScale = Math.max(0.65, Math.min(1.25, scaleW));
|
|
1465
1654
|
}
|
|
1466
1655
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1467
1656
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
@@ -1487,7 +1676,7 @@ var PdfPlugin = class {
|
|
|
1487
1676
|
currentRenderTask = null;
|
|
1488
1677
|
}
|
|
1489
1678
|
};
|
|
1490
|
-
|
|
1679
|
+
renderPage(1);
|
|
1491
1680
|
let resizeTimer = null;
|
|
1492
1681
|
const resizeObserver = new ResizeObserver(() => {
|
|
1493
1682
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
@@ -1531,7 +1720,7 @@ var PdfPlugin = class {
|
|
|
1531
1720
|
renderPage(currentPage);
|
|
1532
1721
|
},
|
|
1533
1722
|
fitToPage: () => {
|
|
1534
|
-
fitMode = fitMode === "
|
|
1723
|
+
fitMode = fitMode === "page" ? "width" : "page";
|
|
1535
1724
|
zoomScale = 1;
|
|
1536
1725
|
rotation = 0;
|
|
1537
1726
|
renderPage(currentPage);
|
|
@@ -2008,6 +2197,14 @@ var DocxPlugin = class {
|
|
|
2008
2197
|
type: "button",
|
|
2009
2198
|
group: "actions",
|
|
2010
2199
|
execute: () => instance.print?.()
|
|
2200
|
+
},
|
|
2201
|
+
{
|
|
2202
|
+
id: "open-window",
|
|
2203
|
+
icon: "open-window",
|
|
2204
|
+
label: "Open in Separate Full Window",
|
|
2205
|
+
type: "button",
|
|
2206
|
+
group: "actions",
|
|
2207
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
2011
2208
|
}
|
|
2012
2209
|
);
|
|
2013
2210
|
return actions;
|
|
@@ -2067,6 +2264,31 @@ var DocxPlugin = class {
|
|
|
2067
2264
|
}
|
|
2068
2265
|
if (wrapper.children.length > 0 && (wrapper.textContent?.trim().length ?? 0) > 0) {
|
|
2069
2266
|
renderedSuccessfully = true;
|
|
2267
|
+
try {
|
|
2268
|
+
const unzipped = fflate.unzipSync(new Uint8Array(ctx.buffer));
|
|
2269
|
+
const chartKeys = Object.keys(unzipped).filter((k) => k.replace(/^[./\\]+/, "").toLowerCase().startsWith("word/charts/chart") && k.endsWith(".xml")).sort();
|
|
2270
|
+
if (chartKeys.length > 0) {
|
|
2271
|
+
const allDivs = Array.from(wrapper.querySelectorAll("div"));
|
|
2272
|
+
const emptyContainers = allDivs.filter((div) => {
|
|
2273
|
+
const st = div.getAttribute("style") || "";
|
|
2274
|
+
return st.includes("width:") && st.includes("height:") && div.children.length === 0 && (div.textContent?.trim().length ?? 0) === 0;
|
|
2275
|
+
});
|
|
2276
|
+
chartKeys.forEach((cKey, idx) => {
|
|
2277
|
+
const target = emptyContainers[idx];
|
|
2278
|
+
if (target) {
|
|
2279
|
+
const xmlStr = fflate.strFromU8(unzipped[cKey]);
|
|
2280
|
+
const svg = this.parseAndRenderChartSvg(xmlStr);
|
|
2281
|
+
if (svg) {
|
|
2282
|
+
target.innerHTML = svg;
|
|
2283
|
+
target.style.display = "block";
|
|
2284
|
+
target.style.margin = "12px auto";
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
});
|
|
2288
|
+
}
|
|
2289
|
+
} catch (chartErr) {
|
|
2290
|
+
console.warn("[DocxPlugin] Non-critical error rendering DrawingML charts:", chartErr);
|
|
2291
|
+
}
|
|
2070
2292
|
}
|
|
2071
2293
|
} catch (err) {
|
|
2072
2294
|
console.warn("[DocxPlugin] docx-preview failed, triggering native fallback:", err);
|
|
@@ -2098,64 +2320,74 @@ var DocxPlugin = class {
|
|
|
2098
2320
|
}
|
|
2099
2321
|
let sections = Array.from(wrapper.querySelectorAll("section.docx"));
|
|
2100
2322
|
const cards = Array.from(wrapper.querySelectorAll(".fp-docx-page-card"));
|
|
2101
|
-
if (sections.length
|
|
2102
|
-
const
|
|
2103
|
-
const
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
const
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
nextSec.
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
nextArticle
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
nextSec.appendChild(
|
|
2323
|
+
if (sections.length > 0 && cards.length === 0) {
|
|
2324
|
+
const finalSections = [];
|
|
2325
|
+
for (const singleSec of sections) {
|
|
2326
|
+
const contentContainer = singleSec.querySelector("article") || singleSec;
|
|
2327
|
+
const children = Array.from(contentContainer.children);
|
|
2328
|
+
const pageH = singleSec.offsetHeight > 1300 ? 1122 : Math.max(1056, singleSec.offsetHeight);
|
|
2329
|
+
const secH = singleSec.scrollHeight || singleSec.offsetHeight;
|
|
2330
|
+
if (secH > pageH * 1.25 && children.length > 1) {
|
|
2331
|
+
const childHeights = children.map((c) => {
|
|
2332
|
+
const rectH = c.getBoundingClientRect().height;
|
|
2333
|
+
const offH = c.offsetHeight;
|
|
2334
|
+
const textLen = c.textContent?.trim().length || 0;
|
|
2335
|
+
const estH = Math.max(24, Math.ceil(textLen / 80) * 22 + 16);
|
|
2336
|
+
return Math.max(rectH, offH, estH);
|
|
2337
|
+
});
|
|
2338
|
+
const parent = singleSec.parentElement || wrapper;
|
|
2339
|
+
const headerEl = singleSec.querySelector("header");
|
|
2340
|
+
const footerEl = singleSec.querySelector("footer");
|
|
2341
|
+
contentContainer.innerHTML = "";
|
|
2342
|
+
singleSec.style.minHeight = `${pageH}px`;
|
|
2343
|
+
singleSec.style.boxSizing = "border-box";
|
|
2344
|
+
let curContent = contentContainer;
|
|
2345
|
+
let curSec = singleSec;
|
|
2346
|
+
let curH = 0;
|
|
2347
|
+
const maxH = pageH - 140;
|
|
2348
|
+
finalSections.push(singleSec);
|
|
2349
|
+
for (let i = 0; i < children.length; i++) {
|
|
2350
|
+
const child = children[i];
|
|
2351
|
+
const chH = childHeights[i];
|
|
2352
|
+
curContent.appendChild(child);
|
|
2353
|
+
curH += chH;
|
|
2354
|
+
if (curH >= maxH && i < children.length - 1) {
|
|
2355
|
+
const nextSec = document.createElement("section");
|
|
2356
|
+
nextSec.className = singleSec.className;
|
|
2357
|
+
nextSec.style.cssText = singleSec.style.cssText;
|
|
2358
|
+
nextSec.style.minHeight = `${pageH}px`;
|
|
2359
|
+
nextSec.style.boxSizing = "border-box";
|
|
2360
|
+
nextSec.style.backgroundColor = "#ffffff";
|
|
2361
|
+
nextSec.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
2362
|
+
nextSec.style.borderRadius = "4px";
|
|
2363
|
+
nextSec.style.marginBottom = "24px";
|
|
2364
|
+
if (headerEl) {
|
|
2365
|
+
nextSec.appendChild(headerEl.cloneNode(true));
|
|
2366
|
+
}
|
|
2367
|
+
const nextArticle = document.createElement("article");
|
|
2368
|
+
if (contentContainer.tagName.toLowerCase() === "article") {
|
|
2369
|
+
nextArticle.style.cssText = contentContainer.style.cssText;
|
|
2370
|
+
}
|
|
2371
|
+
nextSec.appendChild(nextArticle);
|
|
2372
|
+
if (footerEl) {
|
|
2373
|
+
nextSec.appendChild(footerEl.cloneNode(true));
|
|
2374
|
+
}
|
|
2375
|
+
if (curSec.nextSibling) {
|
|
2376
|
+
parent.insertBefore(nextSec, curSec.nextSibling);
|
|
2377
|
+
} else {
|
|
2378
|
+
parent.appendChild(nextSec);
|
|
2379
|
+
}
|
|
2380
|
+
finalSections.push(nextSec);
|
|
2381
|
+
curSec = nextSec;
|
|
2382
|
+
curContent = nextArticle;
|
|
2383
|
+
curH = 0;
|
|
2150
2384
|
}
|
|
2151
|
-
parent.appendChild(nextSec);
|
|
2152
|
-
newSections.push(nextSec);
|
|
2153
|
-
curContent = nextArticle;
|
|
2154
|
-
curH = 0;
|
|
2155
2385
|
}
|
|
2386
|
+
} else {
|
|
2387
|
+
finalSections.push(singleSec);
|
|
2156
2388
|
}
|
|
2157
|
-
sections = newSections;
|
|
2158
2389
|
}
|
|
2390
|
+
sections = finalSections;
|
|
2159
2391
|
}
|
|
2160
2392
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2161
2393
|
const totalPages = Math.max(1, pageElements.length);
|
|
@@ -2547,6 +2779,88 @@ var DocxPlugin = class {
|
|
|
2547
2779
|
}
|
|
2548
2780
|
return result;
|
|
2549
2781
|
}
|
|
2782
|
+
parseAndRenderChartSvg(xmlStr, width = 500, height = 260) {
|
|
2783
|
+
const catMatches = [...xmlStr.matchAll(/<c:cat>[\s\S]*?<c:strCache>([\s\S]*?)<\/c:strCache>/g)];
|
|
2784
|
+
let categories = [];
|
|
2785
|
+
if (catMatches.length > 0) {
|
|
2786
|
+
categories = [...catMatches[0][1].matchAll(/<c:v>([^<]+)<\/c:v>/g)].map((m) => m[1]);
|
|
2787
|
+
}
|
|
2788
|
+
if (categories.length === 0) {
|
|
2789
|
+
categories = ["Category 1", "Category 2", "Category 3", "Category 4"];
|
|
2790
|
+
}
|
|
2791
|
+
const defaultColors = ["#004586", "#ff420e", "#ffd320", "#579d1c", "#7e0021", "#83caff"];
|
|
2792
|
+
const sers = [...xmlStr.matchAll(/<c:ser>([\s\S]*?)<\/c:ser>/g)];
|
|
2793
|
+
const series = [];
|
|
2794
|
+
sers.forEach((s, sIdx) => {
|
|
2795
|
+
const titleMatch = s[1].match(/<c:tx>[\s\S]*?<c:v>([^<]+)<\/c:v>/);
|
|
2796
|
+
const title = titleMatch ? titleMatch[1] : `Series ${sIdx + 1}`;
|
|
2797
|
+
const clrMatch = s[1].match(/<a:srgbClr\s+val="([^"]+)"/);
|
|
2798
|
+
const color = clrMatch ? "#" + clrMatch[1] : defaultColors[sIdx % defaultColors.length];
|
|
2799
|
+
const valMatch = s[1].match(/<c:val>[\s\S]*?<c:numCache>([\s\S]*?)<\/c:numCache>/);
|
|
2800
|
+
let values = [];
|
|
2801
|
+
if (valMatch) {
|
|
2802
|
+
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);
|
|
2803
|
+
}
|
|
2804
|
+
series.push({ title, color, values });
|
|
2805
|
+
});
|
|
2806
|
+
if (series.length === 0) return "";
|
|
2807
|
+
let maxVal = 10;
|
|
2808
|
+
series.forEach((s) => s.values.forEach((v) => {
|
|
2809
|
+
if (v > maxVal) maxVal = v;
|
|
2810
|
+
}));
|
|
2811
|
+
maxVal = Math.ceil(maxVal * 1.15);
|
|
2812
|
+
if (maxVal % 2 !== 0) maxVal++;
|
|
2813
|
+
const padLeft = 45;
|
|
2814
|
+
const padBottom = 55;
|
|
2815
|
+
const padTop = 20;
|
|
2816
|
+
const padRight = 20;
|
|
2817
|
+
const plotW = width - padLeft - padRight;
|
|
2818
|
+
const plotH = height - padTop - padBottom;
|
|
2819
|
+
const yTicks = 5;
|
|
2820
|
+
let gridLines = "";
|
|
2821
|
+
for (let i = 0; i <= yTicks; i++) {
|
|
2822
|
+
const val = maxVal / yTicks * i;
|
|
2823
|
+
const y = padTop + plotH - val / maxVal * plotH;
|
|
2824
|
+
gridLines += `<line x1="${padLeft}" y1="${y}" x2="${padLeft + plotW}" y2="${y}" stroke="#e2e8f0" stroke-width="1" />`;
|
|
2825
|
+
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>`;
|
|
2826
|
+
}
|
|
2827
|
+
const numCats = categories.length;
|
|
2828
|
+
const numSers = series.length;
|
|
2829
|
+
const groupW = plotW / numCats;
|
|
2830
|
+
const barW = Math.max(8, Math.min(28, groupW * 0.7 / numSers));
|
|
2831
|
+
const groupPad = (groupW - barW * numSers) / 2;
|
|
2832
|
+
let bars = "";
|
|
2833
|
+
let catLabels = "";
|
|
2834
|
+
for (let c = 0; c < numCats; c++) {
|
|
2835
|
+
const catX = padLeft + c * groupW;
|
|
2836
|
+
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>`;
|
|
2837
|
+
for (let s = 0; s < numSers; s++) {
|
|
2838
|
+
const val = series[s].values[c] ?? 0;
|
|
2839
|
+
const bH = Math.max(0, val / maxVal * plotH);
|
|
2840
|
+
const bX = catX + groupPad + s * barW;
|
|
2841
|
+
const bY = padTop + plotH - bH;
|
|
2842
|
+
bars += `<rect x="${bX}" y="${bY}" width="${barW - 2}" height="${bH}" fill="${series[s].color}" rx="1" />`;
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
let legend = "";
|
|
2846
|
+
const legY = height - 12;
|
|
2847
|
+
let legX = padLeft + (plotW - numSers * 100) / 2;
|
|
2848
|
+
series.forEach((s) => {
|
|
2849
|
+
legend += `<rect x="${legX}" y="${legY - 9}" width="10" height="10" fill="${s.color}" rx="2" />`;
|
|
2850
|
+
legend += `<text x="${legX + 15}" y="${legY}" font-size="11" fill="#475569" font-family="Calibri, sans-serif">${s.title}</text>`;
|
|
2851
|
+
legX += 95;
|
|
2852
|
+
});
|
|
2853
|
+
return `
|
|
2854
|
+
<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">
|
|
2855
|
+
${gridLines}
|
|
2856
|
+
<line x1="${padLeft}" y1="${padTop + plotH}" x2="${padLeft + plotW}" y2="${padTop + plotH}" stroke="#94a3b8" stroke-width="1.5" />
|
|
2857
|
+
<line x1="${padLeft}" y1="${padTop}" x2="${padLeft}" y2="${padTop + plotH}" stroke="#94a3b8" stroke-width="1.5" />
|
|
2858
|
+
${bars}
|
|
2859
|
+
${catLabels}
|
|
2860
|
+
${legend}
|
|
2861
|
+
</svg>
|
|
2862
|
+
`.trim();
|
|
2863
|
+
}
|
|
2550
2864
|
};
|
|
2551
2865
|
function docxPlugin() {
|
|
2552
2866
|
return new DocxPlugin();
|
|
@@ -3113,6 +3427,16 @@ var CodePlugin = class {
|
|
|
3113
3427
|
execute: () => {
|
|
3114
3428
|
instance.print?.();
|
|
3115
3429
|
}
|
|
3430
|
+
},
|
|
3431
|
+
{
|
|
3432
|
+
id: "open-window",
|
|
3433
|
+
icon: "open-window",
|
|
3434
|
+
label: "Open in Separate Full Window",
|
|
3435
|
+
type: "button",
|
|
3436
|
+
group: "actions",
|
|
3437
|
+
execute: () => {
|
|
3438
|
+
instance.openInSeparateWindow?.();
|
|
3439
|
+
}
|
|
3116
3440
|
}
|
|
3117
3441
|
);
|
|
3118
3442
|
return actions;
|
|
@@ -4281,6 +4605,14 @@ var RtfPlugin = class {
|
|
|
4281
4605
|
type: "button",
|
|
4282
4606
|
group: "actions",
|
|
4283
4607
|
execute: () => instance.print?.()
|
|
4608
|
+
},
|
|
4609
|
+
{
|
|
4610
|
+
id: "open-window",
|
|
4611
|
+
icon: "open-window",
|
|
4612
|
+
label: "Open in Separate Full Window",
|
|
4613
|
+
type: "button",
|
|
4614
|
+
group: "actions",
|
|
4615
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
4284
4616
|
}
|
|
4285
4617
|
);
|
|
4286
4618
|
return actions;
|
|
@@ -4333,59 +4665,54 @@ var RtfPlugin = class {
|
|
|
4333
4665
|
}
|
|
4334
4666
|
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
4335
4667
|
const htmlElements = await doc.render();
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
const secH = singleEl.offsetHeight || singleEl.scrollHeight;
|
|
4341
|
-
if (secH > 1300 && children.length > 1) {
|
|
4342
|
-
const childHeights = children.map((c) => {
|
|
4343
|
-
const rectH = c.getBoundingClientRect().height;
|
|
4344
|
-
const offH = c.offsetHeight;
|
|
4345
|
-
const textLen = c.textContent?.trim().length || 0;
|
|
4346
|
-
const estH = Math.max(24, Math.ceil(textLen / 80) * 22 + 16);
|
|
4347
|
-
return Math.max(rectH, offH, estH);
|
|
4348
|
-
});
|
|
4349
|
-
wrapper.innerHTML = "";
|
|
4350
|
-
const createRtfCard = () => {
|
|
4351
|
-
const card = document.createElement("div");
|
|
4352
|
-
card.className = "fp-rtf-page-card";
|
|
4353
|
-
card.style.backgroundColor = "#ffffff";
|
|
4354
|
-
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
4355
|
-
card.style.borderRadius = "4px";
|
|
4356
|
-
card.style.padding = "72px 56px";
|
|
4357
|
-
card.style.width = "816px";
|
|
4358
|
-
card.style.minHeight = "1056px";
|
|
4359
|
-
card.style.boxSizing = "border-box";
|
|
4360
|
-
card.style.marginBottom = "24px";
|
|
4361
|
-
return card;
|
|
4362
|
-
};
|
|
4363
|
-
let curCard = createRtfCard();
|
|
4364
|
-
wrapper.appendChild(curCard);
|
|
4365
|
-
pageElements = [curCard];
|
|
4366
|
-
let curH = 0;
|
|
4367
|
-
const maxH = 920;
|
|
4368
|
-
for (let i = 0; i < children.length; i++) {
|
|
4369
|
-
const child = children[i];
|
|
4370
|
-
const chH = childHeights[i];
|
|
4371
|
-
curCard.appendChild(child);
|
|
4372
|
-
curH += chH;
|
|
4373
|
-
if (curH >= maxH && i < children.length - 1) {
|
|
4374
|
-
curCard = createRtfCard();
|
|
4375
|
-
wrapper.appendChild(curCard);
|
|
4376
|
-
pageElements.push(curCard);
|
|
4377
|
-
curH = 0;
|
|
4378
|
-
}
|
|
4379
|
-
}
|
|
4668
|
+
const contentNodes = [];
|
|
4669
|
+
for (const item of htmlElements) {
|
|
4670
|
+
if (item.children && item.children.length > 0 && !item.tagName.toLowerCase().startsWith("table")) {
|
|
4671
|
+
contentNodes.push(...Array.from(item.children));
|
|
4380
4672
|
} else {
|
|
4381
|
-
|
|
4673
|
+
contentNodes.push(item);
|
|
4382
4674
|
}
|
|
4383
|
-
}
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4675
|
+
}
|
|
4676
|
+
wrapper.innerHTML = "";
|
|
4677
|
+
contentNodes.forEach((node) => wrapper.appendChild(node));
|
|
4678
|
+
const childHeights = contentNodes.map((c) => {
|
|
4679
|
+
const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
|
|
4680
|
+
const offH = c.offsetHeight || 0;
|
|
4681
|
+
const textLen = c.textContent?.trim().length || 0;
|
|
4682
|
+
const estH = Math.max(24, Math.ceil(textLen / 75) * 22 + 14);
|
|
4683
|
+
return Math.max(rectH, offH, estH);
|
|
4684
|
+
});
|
|
4685
|
+
wrapper.innerHTML = "";
|
|
4686
|
+
const createRtfCard = () => {
|
|
4687
|
+
const card = document.createElement("div");
|
|
4688
|
+
card.className = "fp-rtf-page-card";
|
|
4689
|
+
card.style.backgroundColor = "#ffffff";
|
|
4690
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
4691
|
+
card.style.borderRadius = "4px";
|
|
4692
|
+
card.style.padding = "72px 56px";
|
|
4693
|
+
card.style.width = "816px";
|
|
4694
|
+
card.style.minHeight = "1056px";
|
|
4695
|
+
card.style.boxSizing = "border-box";
|
|
4696
|
+
card.style.marginBottom = "24px";
|
|
4697
|
+
card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4698
|
+
card.style.lineHeight = "1.6";
|
|
4699
|
+
return card;
|
|
4700
|
+
};
|
|
4701
|
+
let curCard = createRtfCard();
|
|
4702
|
+
wrapper.appendChild(curCard);
|
|
4703
|
+
pageElements = [curCard];
|
|
4704
|
+
let curH = 0;
|
|
4705
|
+
const maxH = 912;
|
|
4706
|
+
for (let i = 0; i < contentNodes.length; i++) {
|
|
4707
|
+
const child = contentNodes[i];
|
|
4708
|
+
const chH = childHeights[i];
|
|
4709
|
+
curCard.appendChild(child);
|
|
4710
|
+
curH += chH;
|
|
4711
|
+
if (curH >= maxH && i < contentNodes.length - 1) {
|
|
4712
|
+
curCard = createRtfCard();
|
|
4713
|
+
wrapper.appendChild(curCard);
|
|
4714
|
+
pageElements.push(curCard);
|
|
4715
|
+
curH = 0;
|
|
4389
4716
|
}
|
|
4390
4717
|
}
|
|
4391
4718
|
} catch (err) {
|
|
@@ -4754,6 +5081,14 @@ var OpenDocumentPlugin = class {
|
|
|
4754
5081
|
type: "button",
|
|
4755
5082
|
group: "actions",
|
|
4756
5083
|
execute: () => instance.print?.()
|
|
5084
|
+
},
|
|
5085
|
+
{
|
|
5086
|
+
id: "open-window",
|
|
5087
|
+
icon: "open-window",
|
|
5088
|
+
label: "Open in Separate Full Window",
|
|
5089
|
+
type: "button",
|
|
5090
|
+
group: "actions",
|
|
5091
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
4757
5092
|
}
|
|
4758
5093
|
);
|
|
4759
5094
|
return actions;
|
|
@@ -5342,6 +5677,14 @@ var DocPlugin = class {
|
|
|
5342
5677
|
type: "button",
|
|
5343
5678
|
group: "actions",
|
|
5344
5679
|
execute: () => instance.print?.()
|
|
5680
|
+
},
|
|
5681
|
+
{
|
|
5682
|
+
id: "open-window",
|
|
5683
|
+
icon: "open-window",
|
|
5684
|
+
label: "Open in Separate Full Window",
|
|
5685
|
+
type: "button",
|
|
5686
|
+
group: "actions",
|
|
5687
|
+
execute: () => instance.openInSeparateWindow?.()
|
|
5345
5688
|
}
|
|
5346
5689
|
);
|
|
5347
5690
|
return actions;
|
|
@@ -5361,8 +5704,17 @@ var DocPlugin = class {
|
|
|
5361
5704
|
let scale = 1;
|
|
5362
5705
|
let extractedRawText = "";
|
|
5363
5706
|
let isFallback = false;
|
|
5707
|
+
let chartSvg = "";
|
|
5364
5708
|
try {
|
|
5365
5709
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
5710
|
+
try {
|
|
5711
|
+
const pkg = cfbf.readStream("package_stream");
|
|
5712
|
+
if (pkg && pkg.length > 100) {
|
|
5713
|
+
chartSvg = this.parseOdfChartToSvg(pkg);
|
|
5714
|
+
}
|
|
5715
|
+
} catch (chartErr) {
|
|
5716
|
+
console.warn("[DocPlugin] Chart stream parsing info:", chartErr);
|
|
5717
|
+
}
|
|
5366
5718
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
5367
5719
|
if (!wordDocStream || wordDocStream.length < 512) {
|
|
5368
5720
|
throw new Error("WordDocument stream not found or invalid in CFBF archive");
|
|
@@ -5380,7 +5732,7 @@ var DocPlugin = class {
|
|
|
5380
5732
|
extractedRawText = fallback;
|
|
5381
5733
|
isFallback = true;
|
|
5382
5734
|
}
|
|
5383
|
-
const rawPages = this.splitIntoPages(extractedRawText);
|
|
5735
|
+
const rawPages = this.splitIntoPages(extractedRawText, chartSvg);
|
|
5384
5736
|
const totalPages = Math.max(1, rawPages.length);
|
|
5385
5737
|
let currentPage = 1;
|
|
5386
5738
|
const pageCards = [];
|
|
@@ -5622,7 +5974,7 @@ var DocPlugin = class {
|
|
|
5622
5974
|
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
5623
5975
|
const trimmed = run.trim();
|
|
5624
5976
|
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
5625
|
-
if (!trimmed.includes("Normal.dot") && !trimmed.includes("Microsoft Word") && !trimmed.includes("Times New Roman") && !trimmed.startsWith("\xD0\xCF\xE0\xA1\xB1\xE1") && !/^[\W_0-9]+$/.test(trimmed)) {
|
|
5977
|
+
if (!trimmed.includes("Normal.dot") && !trimmed.includes("Microsoft Word") && !trimmed.includes("Times New Roman") && !trimmed.startsWith("\xD0\xCF\xE0\xA1\xB1\xE1") && !/^EMBED\b/i.test(trimmed) && !trimmed.includes("ChartDocument") && !/^[\W_0-9]+$/.test(trimmed)) {
|
|
5626
5978
|
seen.add(trimmed);
|
|
5627
5979
|
candidateLines.push(trimmed);
|
|
5628
5980
|
}
|
|
@@ -5633,12 +5985,138 @@ var DocPlugin = class {
|
|
|
5633
5985
|
heuristicTextExtraction(buffer) {
|
|
5634
5986
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
5635
5987
|
}
|
|
5636
|
-
|
|
5988
|
+
/**
|
|
5989
|
+
* Parses an embedded OpenDocument Chart package into a vector SVG bar/column chart
|
|
5990
|
+
*/
|
|
5991
|
+
parseOdfChartToSvg(zipBytes) {
|
|
5992
|
+
try {
|
|
5993
|
+
const unzipped = fflate__namespace.unzipSync(zipBytes);
|
|
5994
|
+
const contentXml = unzipped["content.xml"] ? new TextDecoder("utf-8").decode(unzipped["content.xml"]) : "";
|
|
5995
|
+
if (!contentXml) return "";
|
|
5996
|
+
const rowsMatch = contentXml.match(/<table:table-row[\s\S]*?<\/table:table-row>/g) || [];
|
|
5997
|
+
if (rowsMatch.length < 2) return "";
|
|
5998
|
+
const headers = [];
|
|
5999
|
+
const firstRow = rowsMatch[0];
|
|
6000
|
+
const headerCells = firstRow ? firstRow.match(/<text:p>([^<]+)<\/text:p>/g) || [] : [];
|
|
6001
|
+
for (const h2 of headerCells) {
|
|
6002
|
+
headers.push(h2.replace(/<\/?text:p>/g, "").trim());
|
|
6003
|
+
}
|
|
6004
|
+
const categories = [];
|
|
6005
|
+
const seriesValues = headers.map(() => []);
|
|
6006
|
+
for (let r = 1; r < rowsMatch.length; r++) {
|
|
6007
|
+
const rowStr = rowsMatch[r];
|
|
6008
|
+
if (!rowStr) continue;
|
|
6009
|
+
const cells = rowStr.match(/<table:table-cell[\s\S]*?<\/table:table-cell>/g) || [];
|
|
6010
|
+
if (cells.length > 0 && cells[0]) {
|
|
6011
|
+
const catMatch = cells[0].match(/<text:p>([^<]+)<\/text:p>/);
|
|
6012
|
+
categories.push(catMatch ? catMatch[1] : "Row " + r);
|
|
6013
|
+
for (let c = 1; c < cells.length && c - 1 < headers.length; c++) {
|
|
6014
|
+
const cellStr = cells[c];
|
|
6015
|
+
if (!cellStr) continue;
|
|
6016
|
+
const valMatch = cellStr.match(/office:value="([0-9.]+)"/) || cellStr.match(/<text:p>([0-9.]+)<\/text:p>/);
|
|
6017
|
+
const series = seriesValues[c - 1];
|
|
6018
|
+
if (series) {
|
|
6019
|
+
series.push(valMatch ? parseFloat(valMatch[1]) : 0);
|
|
6020
|
+
}
|
|
6021
|
+
}
|
|
6022
|
+
}
|
|
6023
|
+
}
|
|
6024
|
+
const colors = ["#004586", "#ff420e", "#ffd320", "#579d1c", "#7e0021"];
|
|
6025
|
+
const colorMatches = contentXml.matchAll(/draw:fill-color="(#[0-9a-fA-F]{6})"/g);
|
|
6026
|
+
let cIdx = 0;
|
|
6027
|
+
for (const cm of colorMatches) {
|
|
6028
|
+
if (cIdx < colors.length) colors[cIdx] = cm[1];
|
|
6029
|
+
cIdx++;
|
|
6030
|
+
}
|
|
6031
|
+
let maxVal = 10;
|
|
6032
|
+
for (const s of seriesValues) {
|
|
6033
|
+
for (const v of s) {
|
|
6034
|
+
if (v > maxVal) maxVal = v;
|
|
6035
|
+
}
|
|
6036
|
+
}
|
|
6037
|
+
maxVal = Math.ceil(maxVal * 1.15);
|
|
6038
|
+
const width = 560;
|
|
6039
|
+
const height = 280;
|
|
6040
|
+
const padLeft = 45;
|
|
6041
|
+
const padRight = 100;
|
|
6042
|
+
const padTop = 20;
|
|
6043
|
+
const padBottom = 40;
|
|
6044
|
+
const chartW = width - padLeft - padRight;
|
|
6045
|
+
const chartH = height - padTop - padBottom;
|
|
6046
|
+
let svg = `<svg viewBox="0 0 ${width} ${height}" width="100%" height="auto" style="max-width: 560px; height: 280px; margin: 16px auto; display: block; font-family: Calibri, sans-serif; background: #ffffff; border: 1px solid #e2e8f0; border-radius: 6px; box-shadow: 0 1px 4px rgba(0,0,0,0.05);">`;
|
|
6047
|
+
for (let step = 0; step <= 4; step++) {
|
|
6048
|
+
const yVal = (maxVal / 4 * step).toFixed(1);
|
|
6049
|
+
const yPos = padTop + chartH - step / 4 * chartH;
|
|
6050
|
+
svg += `<line x1="${padLeft}" y1="${yPos}" x2="${padLeft + chartW}" y2="${yPos}" stroke="#e2e8f0" stroke-dasharray="2,2" />`;
|
|
6051
|
+
svg += `<text x="${padLeft - 8}" y="${yPos + 4}" font-size="11" fill="#64748b" text-anchor="end">${yVal}</text>`;
|
|
6052
|
+
}
|
|
6053
|
+
const numCats = categories.length;
|
|
6054
|
+
const numSeries = headers.length;
|
|
6055
|
+
const groupW = chartW / numCats;
|
|
6056
|
+
const barW = Math.max(8, groupW * 0.7 / numSeries);
|
|
6057
|
+
const groupPad = (groupW - barW * numSeries) / 2;
|
|
6058
|
+
for (let catIdx = 0; catIdx < numCats; catIdx++) {
|
|
6059
|
+
const groupX = padLeft + catIdx * groupW + groupPad;
|
|
6060
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6061
|
+
const val = seriesValues[sIdx][catIdx] || 0;
|
|
6062
|
+
const barH = val / maxVal * chartH;
|
|
6063
|
+
const barX = groupX + sIdx * barW;
|
|
6064
|
+
const barY = padTop + chartH - barH;
|
|
6065
|
+
const col = colors[sIdx % colors.length];
|
|
6066
|
+
svg += `<rect x="${barX}" y="${barY}" width="${barW - 2}" height="${barH}" fill="${col}" rx="2"><title>${headers[sIdx]}: ${val}</title></rect>`;
|
|
6067
|
+
}
|
|
6068
|
+
const catX = padLeft + catIdx * groupW + groupW / 2;
|
|
6069
|
+
svg += `<text x="${catX}" y="${padTop + chartH + 18}" font-size="11" fill="#475569" text-anchor="middle">${categories[catIdx]}</text>`;
|
|
6070
|
+
}
|
|
6071
|
+
let legendY = padTop + 20;
|
|
6072
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6073
|
+
const col = colors[sIdx % colors.length];
|
|
6074
|
+
svg += `<rect x="${padLeft + chartW + 15}" y="${legendY}" width="12" height="12" fill="${col}" rx="2" />`;
|
|
6075
|
+
svg += `<text x="${padLeft + chartW + 32}" y="${legendY + 10}" font-size="11" fill="#334155">${headers[sIdx]}</text>`;
|
|
6076
|
+
legendY += 20;
|
|
6077
|
+
}
|
|
6078
|
+
svg += "</svg>";
|
|
6079
|
+
return svg;
|
|
6080
|
+
} catch (e) {
|
|
6081
|
+
console.warn("[DocPlugin] Error generating chart SVG:", e);
|
|
6082
|
+
return "";
|
|
6083
|
+
}
|
|
6084
|
+
}
|
|
6085
|
+
cleanWordDocFields(text, chartSvg = "") {
|
|
6086
|
+
if (!text) return "";
|
|
6087
|
+
let cleaned = text.replace(
|
|
6088
|
+
/\x13\s*EMBED\b[\s\S]*?\x15/gi,
|
|
6089
|
+
() => chartSvg ? `
|
|
6090
|
+
|
|
6091
|
+
${chartSvg}
|
|
6092
|
+
|
|
6093
|
+
` : ""
|
|
6094
|
+
);
|
|
6095
|
+
cleaned = cleaned.replace(
|
|
6096
|
+
/\x13\s*HYPERLINK\s*"?([^"\x14]+)"?\s*\x14([\s\S]*?)\x15/gi,
|
|
6097
|
+
(_match, url, label) => {
|
|
6098
|
+
const cleanUrl = url.trim();
|
|
6099
|
+
const cleanLabel = label.trim() || cleanUrl;
|
|
6100
|
+
return `<a href="${cleanUrl}" target="_blank" rel="noopener noreferrer" style="color: #2563eb; text-decoration: underline;">${cleanLabel}</a>`;
|
|
6101
|
+
}
|
|
6102
|
+
);
|
|
6103
|
+
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g, (_m, res) => {
|
|
6104
|
+
if (/[\x00-\x1F]/.test(res)) return "";
|
|
6105
|
+
return res.trim();
|
|
6106
|
+
});
|
|
6107
|
+
cleaned = cleaned.replace(/\x13[^\x15]*\x15/g, "");
|
|
6108
|
+
cleaned = cleaned.replace(/[\x13\x14\x15]/g, "");
|
|
6109
|
+
cleaned = cleaned.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/g, "");
|
|
6110
|
+
cleaned = cleaned.replace(/EMBED\s+LibreOffice\.ChartDocument\.[0-9]+/gi, chartSvg || "");
|
|
6111
|
+
return cleaned;
|
|
6112
|
+
}
|
|
6113
|
+
splitIntoPages(text, chartSvg = "") {
|
|
5637
6114
|
if (!text) return [""];
|
|
5638
|
-
const
|
|
6115
|
+
const cleanedText = this.cleanWordDocFields(text, chartSvg);
|
|
6116
|
+
const normalized = cleanedText.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ");
|
|
5639
6117
|
const explicitParts = normalized.split(/[\x0C\f]|\n\s*[-=_]{3,}\s*(?:PAGE|Page|page break)[\s\d\w-]*[-=_]{3,}\s*\n/i).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
5640
6118
|
if (explicitParts.length === 0) explicitParts.push(normalized);
|
|
5641
|
-
const maxLinesPerPage =
|
|
6119
|
+
const maxLinesPerPage = 34;
|
|
5642
6120
|
const charsPerLine = 80;
|
|
5643
6121
|
const finalPages = [];
|
|
5644
6122
|
for (const part of explicitParts) {
|
|
@@ -5646,7 +6124,8 @@ var DocPlugin = class {
|
|
|
5646
6124
|
let currentLines = [];
|
|
5647
6125
|
let count = 0;
|
|
5648
6126
|
for (const line of lines) {
|
|
5649
|
-
const
|
|
6127
|
+
const isSvg = line.includes("<svg");
|
|
6128
|
+
const vLines = isSvg ? 12 : Math.max(1, Math.ceil((line.replace(/<[^>]+>/g, "").length || 1) / charsPerLine));
|
|
5650
6129
|
if (count + vLines > maxLinesPerPage && currentLines.length > 0) {
|
|
5651
6130
|
finalPages.push(currentLines.join("\n"));
|
|
5652
6131
|
currentLines = [];
|
|
@@ -5686,9 +6165,44 @@ var DocPlugin = class {
|
|
|
5686
6165
|
tableLines = [];
|
|
5687
6166
|
}
|
|
5688
6167
|
};
|
|
6168
|
+
const sanitizeOptions = {
|
|
6169
|
+
ADD_TAGS: ["a", "svg", "g", "path", "line", "rect", "circle", "text", "title"],
|
|
6170
|
+
ADD_ATTR: [
|
|
6171
|
+
"href",
|
|
6172
|
+
"target",
|
|
6173
|
+
"rel",
|
|
6174
|
+
"style",
|
|
6175
|
+
"viewBox",
|
|
6176
|
+
"width",
|
|
6177
|
+
"height",
|
|
6178
|
+
"x",
|
|
6179
|
+
"y",
|
|
6180
|
+
"x1",
|
|
6181
|
+
"y1",
|
|
6182
|
+
"x2",
|
|
6183
|
+
"y2",
|
|
6184
|
+
"fill",
|
|
6185
|
+
"stroke",
|
|
6186
|
+
"stroke-width",
|
|
6187
|
+
"stroke-dasharray",
|
|
6188
|
+
"rx",
|
|
6189
|
+
"font-size",
|
|
6190
|
+
"text-anchor"
|
|
6191
|
+
]
|
|
6192
|
+
};
|
|
5689
6193
|
let i = 0;
|
|
5690
6194
|
while (i < lines.length) {
|
|
5691
6195
|
let line = lines[i];
|
|
6196
|
+
if (line.includes("<svg")) {
|
|
6197
|
+
if (inList) {
|
|
6198
|
+
html += "</ul>";
|
|
6199
|
+
inList = false;
|
|
6200
|
+
}
|
|
6201
|
+
flushTable();
|
|
6202
|
+
html += line;
|
|
6203
|
+
i++;
|
|
6204
|
+
continue;
|
|
6205
|
+
}
|
|
5692
6206
|
let tabCount = (line.match(/\t/g) || []).length;
|
|
5693
6207
|
if (tabCount > 0) {
|
|
5694
6208
|
let j = i;
|
|
@@ -5727,20 +6241,20 @@ var DocPlugin = class {
|
|
|
5727
6241
|
html += "</ul>";
|
|
5728
6242
|
inList = false;
|
|
5729
6243
|
}
|
|
5730
|
-
html += `<h2 style="font-size: 16px; font-weight: 700; color: #1e3a8a; margin: 16px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6__default.default.sanitize(line)}</h2>`;
|
|
6244
|
+
html += `<h2 style="font-size: 16px; font-weight: 700; color: #1e3a8a; margin: 16px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6__default.default.sanitize(line, sanitizeOptions)}</h2>`;
|
|
5731
6245
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
5732
6246
|
if (!inList) {
|
|
5733
6247
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
5734
6248
|
inList = true;
|
|
5735
6249
|
}
|
|
5736
6250
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
5737
|
-
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6__default.default.sanitize(bulletText)}</li>`;
|
|
6251
|
+
html += `<li style="margin: 4px 0; line-height: 1.15; font-size: 12pt;">${DOMPurify6__default.default.sanitize(bulletText, sanitizeOptions)}</li>`;
|
|
5738
6252
|
} else {
|
|
5739
6253
|
if (inList) {
|
|
5740
6254
|
html += "</ul>";
|
|
5741
6255
|
inList = false;
|
|
5742
6256
|
}
|
|
5743
|
-
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6__default.default.sanitize(line)}</p>`;
|
|
6257
|
+
html += `<p style="line-height: 1.15; margin: 0; font-size: 12pt; text-align: justify;">${DOMPurify6__default.default.sanitize(line, sanitizeOptions)}</p>`;
|
|
5744
6258
|
}
|
|
5745
6259
|
i++;
|
|
5746
6260
|
}
|