@files-preview-app/preview-file 1.3.0 → 1.3.2
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/README.md +69 -0
- package/dist/angular.cjs +1477 -482
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.d.cts +1 -1
- package/dist/angular.d.ts +1 -1
- package/dist/angular.js +1477 -482
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +1477 -482
- package/dist/index.cjs.map +1 -1
- package/dist/index.d-B79v0jxi.d.cts +570 -0
- package/dist/index.d-B79v0jxi.d.ts +570 -0
- package/dist/index.d.cts +3227 -19
- package/dist/index.d.ts +3227 -19
- package/dist/index.js +1477 -482
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +1477 -482
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -16
- package/dist/react.d.ts +1 -16
- package/dist/react.js +1477 -482
- package/dist/react.js.map +1 -1
- package/dist/styles.css +195 -14
- package/dist/vue.cjs +1477 -482
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.d.cts +1 -1
- package/dist/vue.d.ts +1 -1
- package/dist/vue.js +1477 -482
- package/dist/vue.js.map +1 -1
- package/package.json +2 -2
package/dist/angular.cjs
CHANGED
|
@@ -42,6 +42,7 @@ function _interopNamespace(e) {
|
|
|
42
42
|
var DOMPurify6__default = /*#__PURE__*/_interopDefault(DOMPurify6);
|
|
43
43
|
var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
|
|
44
44
|
var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
45
|
+
var fflate__namespace = /*#__PURE__*/_interopNamespace(fflate);
|
|
45
46
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
46
47
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
47
48
|
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
@@ -574,8 +575,7 @@ var ICON_FULLSCREEN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="non
|
|
|
574
575
|
var ICON_COPY = `<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="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`;
|
|
575
576
|
var ICON_FAST_FORWARD = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 19 22 12 13 5 13 19"></polygon><polygon points="2 19 11 12 2 5 2 19"></polygon></svg>`;
|
|
576
577
|
var ICON_REWIND = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="11 19 2 12 11 5 11 19"></polygon><polygon points="22 19 13 12 22 5 22 19"></polygon></svg>`;
|
|
577
|
-
var
|
|
578
|
-
var ICON_EXTERNAL_WINDOW = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>`;
|
|
578
|
+
var ICON_EXTERNAL_WINDOW = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"></rect><line x1="3" y1="8" x2="21" y2="8"></line><circle cx="6" cy="5.5" r="0.75" fill="currentColor"></circle><circle cx="8.5" cy="5.5" r="0.75" fill="currentColor"></circle><polyline points="14 13 18 13 18 17"></polyline><line x1="11" y1="20" x2="18" y2="13"></line></svg>`;
|
|
579
579
|
var ICON_MAP = {
|
|
580
580
|
"zoom-in": ICON_ZOOM_IN,
|
|
581
581
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -602,28 +602,177 @@ var ICON_MAP = {
|
|
|
602
602
|
"forward-10": ICON_FAST_FORWARD,
|
|
603
603
|
"rewind": ICON_REWIND,
|
|
604
604
|
"replay-10": ICON_REWIND,
|
|
605
|
-
"speed": ICON_SPEED,
|
|
606
605
|
"open-window": ICON_EXTERNAL_WINDOW,
|
|
607
|
-
"external-window": ICON_EXTERNAL_WINDOW
|
|
606
|
+
"external-window": ICON_EXTERNAL_WINDOW,
|
|
607
|
+
"openWindow": ICON_EXTERNAL_WINDOW,
|
|
608
|
+
"openSeparateWindow": ICON_EXTERNAL_WINDOW
|
|
608
609
|
};
|
|
609
610
|
var ToolbarController = class {
|
|
610
611
|
el;
|
|
611
612
|
toolbarEl;
|
|
612
613
|
actions = [];
|
|
614
|
+
config = {};
|
|
613
615
|
pageInputEl = null;
|
|
614
616
|
pageLabelEl = null;
|
|
615
|
-
|
|
617
|
+
prevPageBtn = null;
|
|
618
|
+
nextPageBtn = null;
|
|
619
|
+
constructor(container, config) {
|
|
616
620
|
this.el = container;
|
|
621
|
+
if (config) this.config = { ...config };
|
|
617
622
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
618
623
|
this.el.appendChild(this.toolbarEl);
|
|
619
624
|
}
|
|
625
|
+
setConfig(config) {
|
|
626
|
+
this.config = { ...config };
|
|
627
|
+
this.render();
|
|
628
|
+
}
|
|
629
|
+
getConfig() {
|
|
630
|
+
return { ...this.config };
|
|
631
|
+
}
|
|
632
|
+
hideAction(actionId) {
|
|
633
|
+
this.config[actionId] = false;
|
|
634
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = false;
|
|
635
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = false;
|
|
636
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
637
|
+
this.config.fitPage = false;
|
|
638
|
+
this.config.fitToPage = false;
|
|
639
|
+
this.config.fitWidth = false;
|
|
640
|
+
}
|
|
641
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = false;
|
|
642
|
+
if (actionId === "fullscreen") this.config.fullscreen = false;
|
|
643
|
+
if (actionId === "download") this.config.download = false;
|
|
644
|
+
if (actionId === "print") this.config.print = false;
|
|
645
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
646
|
+
this.config.openWindow = false;
|
|
647
|
+
this.config.openSeparateWindow = false;
|
|
648
|
+
}
|
|
649
|
+
if (actionId === "copy") this.config.copy = false;
|
|
650
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
651
|
+
this.config.pageNav = false;
|
|
652
|
+
this.config.pagination = false;
|
|
653
|
+
}
|
|
654
|
+
this.render();
|
|
655
|
+
}
|
|
656
|
+
showAction(actionId) {
|
|
657
|
+
this.config[actionId] = true;
|
|
658
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = true;
|
|
659
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = true;
|
|
660
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
661
|
+
this.config.fitPage = true;
|
|
662
|
+
this.config.fitToPage = true;
|
|
663
|
+
this.config.fitWidth = true;
|
|
664
|
+
}
|
|
665
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = true;
|
|
666
|
+
if (actionId === "fullscreen") this.config.fullscreen = true;
|
|
667
|
+
if (actionId === "download") this.config.download = true;
|
|
668
|
+
if (actionId === "print") this.config.print = true;
|
|
669
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
670
|
+
this.config.openWindow = true;
|
|
671
|
+
this.config.openSeparateWindow = true;
|
|
672
|
+
}
|
|
673
|
+
if (actionId === "copy") this.config.copy = true;
|
|
674
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
675
|
+
this.config.pageNav = true;
|
|
676
|
+
this.config.pagination = true;
|
|
677
|
+
}
|
|
678
|
+
this.render();
|
|
679
|
+
}
|
|
680
|
+
normalizeActionId(actionId) {
|
|
681
|
+
if (actionId === "zoomIn") return "zoom-in";
|
|
682
|
+
if (actionId === "zoomOut") return "zoom-out";
|
|
683
|
+
if (actionId === "fitPage" || actionId === "fitToPage" || actionId === "fitWidth") return "fit-page";
|
|
684
|
+
if (actionId === "rotateCW") return "rotate-cw";
|
|
685
|
+
if (actionId === "rotateCCW") return "rotate-ccw";
|
|
686
|
+
if (actionId === "openWindow" || actionId === "openSeparateWindow") return "open-window";
|
|
687
|
+
if (actionId === "pageNav") return "page-nav";
|
|
688
|
+
return actionId;
|
|
689
|
+
}
|
|
690
|
+
enableAction(actionId) {
|
|
691
|
+
const norm = this.normalizeActionId(actionId);
|
|
692
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
693
|
+
if (btn) {
|
|
694
|
+
btn.disabled = false;
|
|
695
|
+
btn.classList.remove("disabled");
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
disableAction(actionId) {
|
|
699
|
+
const norm = this.normalizeActionId(actionId);
|
|
700
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
701
|
+
if (btn) {
|
|
702
|
+
btn.disabled = true;
|
|
703
|
+
btn.classList.add("disabled");
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
setActionActive(actionId, active) {
|
|
707
|
+
const norm = this.normalizeActionId(actionId);
|
|
708
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
709
|
+
if (btn) {
|
|
710
|
+
if (active) {
|
|
711
|
+
btn.classList.add("active");
|
|
712
|
+
} else {
|
|
713
|
+
btn.classList.remove("active");
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
isActionEnabled(action) {
|
|
718
|
+
const c = this.config;
|
|
719
|
+
const id = action.id;
|
|
720
|
+
if (c[id] === false) return false;
|
|
721
|
+
if (id === "zoom-in" && (c.zoomIn === false || c["zoom-in"] === false)) return false;
|
|
722
|
+
if (id === "zoom-out" && (c.zoomOut === false || c["zoom-out"] === false)) return false;
|
|
723
|
+
if ((id === "fit-page" || id === "fit-width" || id === "fit-slide") && (c.fitPage === false || c.fitToPage === false || c.fitWidth === false || c["fit-page"] === false || c["fit-width"] === false)) {
|
|
724
|
+
return false;
|
|
725
|
+
}
|
|
726
|
+
if ((id === "rotate-cw" || id === "rotate-ccw" || id === "rotate") && (c.rotate === false || c.rotateCW === false || c.rotateCCW === false || c["rotate-cw"] === false)) {
|
|
727
|
+
return false;
|
|
728
|
+
}
|
|
729
|
+
if (id === "fullscreen" && c.fullscreen === false) return false;
|
|
730
|
+
if (id === "download" && c.download === false) return false;
|
|
731
|
+
if (id === "print" && c.print === false) return false;
|
|
732
|
+
if ((id === "open-window" || id === "external-window") && (c.openWindow === false || c.openSeparateWindow === false || c["open-window"] === false)) {
|
|
733
|
+
return false;
|
|
734
|
+
}
|
|
735
|
+
if (id === "copy" && c.copy === false) return false;
|
|
736
|
+
if (id === "thumbnails" && c.thumbnails === false) return false;
|
|
737
|
+
if (id === "page-nav" && (c.pageNav === false || c.pagination === false || c["page-nav"] === false)) {
|
|
738
|
+
return false;
|
|
739
|
+
}
|
|
740
|
+
if ((id === "prev" || id === "page-prev") && (c.prevPage === false || c.prev === false || c["prev"] === false || c.pageNav === false || c.pagination === false)) {
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
743
|
+
if ((id === "next" || id === "page-next") && (c.nextPage === false || c.next === false || c["next"] === false || c.pageNav === false || c.pagination === false)) {
|
|
744
|
+
return false;
|
|
745
|
+
}
|
|
746
|
+
if (id === "play" && c.play === false) return false;
|
|
747
|
+
if (id === "pause" && c.pause === false) return false;
|
|
748
|
+
if ((id === "fast-forward" || id === "forward-10") && (c.fastForward === false || c["fast-forward"] === false)) {
|
|
749
|
+
return false;
|
|
750
|
+
}
|
|
751
|
+
if ((id === "rewind" || id === "replay-10") && (c.rewind === false || c["rewind"] === false)) {
|
|
752
|
+
return false;
|
|
753
|
+
}
|
|
754
|
+
if (id === "speed" && c.speed === false) return false;
|
|
755
|
+
return true;
|
|
756
|
+
}
|
|
620
757
|
setPage(page, max) {
|
|
621
758
|
if (this.pageInputEl) {
|
|
622
759
|
this.pageInputEl.value = page.toString();
|
|
760
|
+
if (max !== void 0) {
|
|
761
|
+
this.pageInputEl.max = max.toString();
|
|
762
|
+
}
|
|
623
763
|
}
|
|
624
764
|
if (max !== void 0 && this.pageLabelEl) {
|
|
625
765
|
this.pageLabelEl.textContent = ` / ${max}`;
|
|
626
766
|
}
|
|
767
|
+
const currentMax = max !== void 0 ? max : parseInt(this.pageInputEl?.max || "1", 10) || 1;
|
|
768
|
+
if (this.prevPageBtn) {
|
|
769
|
+
this.prevPageBtn.disabled = page <= 1;
|
|
770
|
+
this.prevPageBtn.style.opacity = page <= 1 ? "0.4" : "1";
|
|
771
|
+
}
|
|
772
|
+
if (this.nextPageBtn) {
|
|
773
|
+
this.nextPageBtn.disabled = page >= currentMax;
|
|
774
|
+
this.nextPageBtn.style.opacity = page >= currentMax ? "0.4" : "1";
|
|
775
|
+
}
|
|
627
776
|
}
|
|
628
777
|
update(actions) {
|
|
629
778
|
this.actions = actions;
|
|
@@ -646,8 +795,9 @@ var ToolbarController = class {
|
|
|
646
795
|
view: [],
|
|
647
796
|
actions: []
|
|
648
797
|
};
|
|
649
|
-
const
|
|
650
|
-
const
|
|
798
|
+
const enabledActions = this.actions.filter((a) => this.isActionEnabled(a));
|
|
799
|
+
const hasPageNav = enabledActions.some((a) => a.type === "page-nav");
|
|
800
|
+
const effectiveActions = hasPageNav ? enabledActions.filter((a) => a.id !== "page-prev" && a.id !== "page-next" && a.id !== "prev" && a.id !== "next") : enabledActions;
|
|
651
801
|
for (const action of effectiveActions) {
|
|
652
802
|
if (groups[action.group]) {
|
|
653
803
|
groups[action.group].push(action);
|
|
@@ -707,6 +857,13 @@ var ToolbarController = class {
|
|
|
707
857
|
action.execute("go", val);
|
|
708
858
|
});
|
|
709
859
|
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
860
|
+
const curVal = action.value ?? 1;
|
|
861
|
+
prevBtn.disabled = curVal <= 1;
|
|
862
|
+
prevBtn.style.opacity = curVal <= 1 ? "0.4" : "1";
|
|
863
|
+
nextBtn.disabled = curVal >= max;
|
|
864
|
+
nextBtn.style.opacity = curVal >= max ? "0.4" : "1";
|
|
865
|
+
this.prevPageBtn = prevBtn;
|
|
866
|
+
this.nextPageBtn = nextBtn;
|
|
710
867
|
this.pageInputEl = input;
|
|
711
868
|
this.pageLabelEl = label;
|
|
712
869
|
groupEl.appendChild(prevBtn);
|
|
@@ -747,9 +904,11 @@ var ToolbarController = class {
|
|
|
747
904
|
type: "button",
|
|
748
905
|
"data-action-id": id
|
|
749
906
|
});
|
|
750
|
-
const
|
|
751
|
-
if (
|
|
752
|
-
btn.innerHTML =
|
|
907
|
+
const internalSvg = ICON_MAP[iconHtml] || ICON_MAP[id];
|
|
908
|
+
if (internalSvg) {
|
|
909
|
+
btn.innerHTML = internalSvg;
|
|
910
|
+
} else if (iconHtml && iconHtml.startsWith("<svg")) {
|
|
911
|
+
btn.innerHTML = sanitizeSVG(iconHtml);
|
|
753
912
|
} else {
|
|
754
913
|
btn.textContent = title || id;
|
|
755
914
|
}
|
|
@@ -760,25 +919,63 @@ var ToolbarController = class {
|
|
|
760
919
|
var ThumbnailPanel = class {
|
|
761
920
|
el;
|
|
762
921
|
panelEl;
|
|
922
|
+
listEl;
|
|
923
|
+
headerEl;
|
|
763
924
|
thumbnails = [];
|
|
764
925
|
onSelect;
|
|
926
|
+
onToggleCallback;
|
|
765
927
|
activeIndex = 0;
|
|
766
|
-
|
|
928
|
+
observer;
|
|
929
|
+
renderedIndices = /* @__PURE__ */ new Set();
|
|
930
|
+
constructor(container, onToggle) {
|
|
767
931
|
this.el = container;
|
|
932
|
+
this.onToggleCallback = onToggle;
|
|
768
933
|
this.panelEl = createElement("div", { className: "fp-thumbnail-panel hidden" });
|
|
934
|
+
this.panelEl.style.width = "0px";
|
|
935
|
+
this.panelEl.style.minWidth = "0px";
|
|
936
|
+
this.panelEl.style.opacity = "0";
|
|
937
|
+
this.headerEl = createElement("div", { className: "fp-thumbnail-header" });
|
|
938
|
+
const title = createElement("span", { className: "fp-thumbnail-title" }, "Pages");
|
|
939
|
+
const closeBtn = createElement("button", {
|
|
940
|
+
className: "fp-thumbnail-close-btn",
|
|
941
|
+
title: "Close Thumbnails",
|
|
942
|
+
type: "button"
|
|
943
|
+
});
|
|
944
|
+
closeBtn.innerHTML = ICON_CLOSE;
|
|
945
|
+
closeBtn.addEventListener("click", (e) => {
|
|
946
|
+
e.stopPropagation();
|
|
947
|
+
this.hide();
|
|
948
|
+
});
|
|
949
|
+
this.headerEl.appendChild(title);
|
|
950
|
+
this.headerEl.appendChild(closeBtn);
|
|
951
|
+
this.listEl = createElement("div", { className: "fp-thumbnail-list" });
|
|
952
|
+
this.panelEl.appendChild(this.headerEl);
|
|
953
|
+
this.panelEl.appendChild(this.listEl);
|
|
769
954
|
this.el.appendChild(this.panelEl);
|
|
770
955
|
}
|
|
956
|
+
isOpen() {
|
|
957
|
+
return !this.panelEl.classList.contains("hidden") && this.panelEl.style.width !== "0px";
|
|
958
|
+
}
|
|
771
959
|
update(thumbnails, onSelect) {
|
|
772
960
|
this.thumbnails = thumbnails;
|
|
773
961
|
this.onSelect = onSelect;
|
|
962
|
+
this.renderedIndices.clear();
|
|
963
|
+
const titleEl = this.headerEl.querySelector(".fp-thumbnail-title");
|
|
964
|
+
if (titleEl) {
|
|
965
|
+
titleEl.textContent = `Pages (${thumbnails.length})`;
|
|
966
|
+
}
|
|
774
967
|
this.render();
|
|
968
|
+
if (this.isOpen()) {
|
|
969
|
+
this.renderAllVisible();
|
|
970
|
+
}
|
|
775
971
|
}
|
|
776
972
|
setActive(index) {
|
|
777
973
|
this.activeIndex = index;
|
|
778
|
-
const items = this.
|
|
974
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
779
975
|
items.forEach((item, i) => {
|
|
780
976
|
if (i === index) {
|
|
781
977
|
item.classList.add("active");
|
|
978
|
+
item.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
782
979
|
} else {
|
|
783
980
|
item.classList.remove("active");
|
|
784
981
|
}
|
|
@@ -786,37 +983,102 @@ var ThumbnailPanel = class {
|
|
|
786
983
|
}
|
|
787
984
|
show() {
|
|
788
985
|
this.panelEl.classList.remove("hidden");
|
|
986
|
+
this.panelEl.style.width = "200px";
|
|
987
|
+
this.panelEl.style.minWidth = "200px";
|
|
988
|
+
this.panelEl.style.opacity = "1";
|
|
989
|
+
this.panelEl.style.display = "flex";
|
|
990
|
+
this.onToggleCallback?.(true);
|
|
991
|
+
this.renderAllVisible();
|
|
789
992
|
}
|
|
790
993
|
hide() {
|
|
791
994
|
this.panelEl.classList.add("hidden");
|
|
995
|
+
this.panelEl.style.width = "0px";
|
|
996
|
+
this.panelEl.style.minWidth = "0px";
|
|
997
|
+
this.panelEl.style.opacity = "0";
|
|
998
|
+
this.onToggleCallback?.(false);
|
|
792
999
|
}
|
|
793
1000
|
toggle() {
|
|
794
|
-
this.
|
|
1001
|
+
if (this.isOpen()) {
|
|
1002
|
+
this.hide();
|
|
1003
|
+
} else {
|
|
1004
|
+
this.show();
|
|
1005
|
+
}
|
|
795
1006
|
}
|
|
796
1007
|
destroy() {
|
|
1008
|
+
if (this.observer) {
|
|
1009
|
+
this.observer.disconnect();
|
|
1010
|
+
this.observer = void 0;
|
|
1011
|
+
}
|
|
1012
|
+
this.renderedIndices.clear();
|
|
797
1013
|
this.el.innerHTML = "";
|
|
798
1014
|
}
|
|
799
|
-
|
|
800
|
-
this.
|
|
1015
|
+
renderAllVisible() {
|
|
1016
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
1017
|
+
items.forEach((item) => {
|
|
1018
|
+
const idx = parseInt(item.dataset.thumbIndex || "-1", 10);
|
|
1019
|
+
if (idx >= 0 && !this.renderedIndices.has(idx)) {
|
|
1020
|
+
this.renderThumbnailItem(idx, item);
|
|
1021
|
+
}
|
|
1022
|
+
});
|
|
1023
|
+
}
|
|
1024
|
+
renderThumbnailItem(idx, itemEl) {
|
|
1025
|
+
if (this.renderedIndices.has(idx)) return;
|
|
1026
|
+
this.renderedIndices.add(idx);
|
|
1027
|
+
const canvas = itemEl.querySelector("canvas");
|
|
1028
|
+
const thumb = this.thumbnails[idx];
|
|
1029
|
+
if (canvas && thumb) {
|
|
1030
|
+
Promise.resolve(thumb.render(canvas)).catch((err) => {
|
|
1031
|
+
console.warn(`[FilePreview] Error rendering thumbnail ${idx}:`, err);
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
render() {
|
|
1036
|
+
if (this.observer) {
|
|
1037
|
+
this.observer.disconnect();
|
|
1038
|
+
}
|
|
1039
|
+
this.listEl.innerHTML = "";
|
|
1040
|
+
const useObserver = typeof IntersectionObserver !== "undefined";
|
|
1041
|
+
if (useObserver) {
|
|
1042
|
+
this.observer = new IntersectionObserver(
|
|
1043
|
+
(entries) => {
|
|
1044
|
+
for (const entry of entries) {
|
|
1045
|
+
if (entry.isIntersecting) {
|
|
1046
|
+
const target = entry.target;
|
|
1047
|
+
const idx = parseInt(target.dataset.thumbIndex || "-1", 10);
|
|
1048
|
+
if (idx >= 0) {
|
|
1049
|
+
this.renderThumbnailItem(idx, target);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
},
|
|
1054
|
+
{
|
|
1055
|
+
root: this.listEl,
|
|
1056
|
+
rootMargin: "120px 0px 120px 0px"
|
|
1057
|
+
}
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
801
1060
|
for (let i = 0; i < this.thumbnails.length; i++) {
|
|
802
1061
|
const thumb = this.thumbnails[i];
|
|
803
|
-
const itemEl = createElement("div", {
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
1062
|
+
const itemEl = createElement("div", {
|
|
1063
|
+
className: "fp-thumbnail-item" + (i === this.activeIndex ? " active" : "")
|
|
1064
|
+
});
|
|
1065
|
+
itemEl.dataset.thumbIndex = i.toString();
|
|
807
1066
|
itemEl.addEventListener("click", () => {
|
|
808
1067
|
this.setActive(i);
|
|
809
1068
|
this.onSelect?.(i);
|
|
810
1069
|
});
|
|
811
|
-
const
|
|
812
|
-
const
|
|
813
|
-
|
|
1070
|
+
const canvasWrapper = createElement("div", { className: "fp-thumbnail-canvas-wrapper" });
|
|
1071
|
+
const canvas = createElement("canvas", { width: "130", height: "170" });
|
|
1072
|
+
canvasWrapper.appendChild(canvas);
|
|
1073
|
+
const label = createElement("span", { className: "fp-thumbnail-label" }, thumb.label || `Page ${i + 1}`);
|
|
1074
|
+
itemEl.appendChild(canvasWrapper);
|
|
814
1075
|
itemEl.appendChild(label);
|
|
815
|
-
this.
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
}
|
|
819
|
-
|
|
1076
|
+
this.listEl.appendChild(itemEl);
|
|
1077
|
+
if (this.observer) {
|
|
1078
|
+
this.observer.observe(itemEl);
|
|
1079
|
+
}
|
|
1080
|
+
if (i < 4) {
|
|
1081
|
+
this.renderThumbnailItem(i, itemEl);
|
|
820
1082
|
}
|
|
821
1083
|
}
|
|
822
1084
|
}
|
|
@@ -837,6 +1099,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
837
1099
|
currentOptions = {};
|
|
838
1100
|
resizeObserver = null;
|
|
839
1101
|
fullscreenHandler = null;
|
|
1102
|
+
titleBarEl = null;
|
|
840
1103
|
/**
|
|
841
1104
|
* Register a preview plugin.
|
|
842
1105
|
*/
|
|
@@ -873,6 +1136,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
873
1136
|
}
|
|
874
1137
|
this.currentBuffer = buffer.slice(0);
|
|
875
1138
|
this.currentMetadata = metadata;
|
|
1139
|
+
this.updateTitleBar(options, metadata);
|
|
876
1140
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
877
1141
|
const fileInfo = { metadata, buffer };
|
|
878
1142
|
const matchedPlugin = await this.findPlugin(fileInfo);
|
|
@@ -896,15 +1160,21 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
896
1160
|
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
897
1161
|
const total = payload.total ?? payload.totalPages;
|
|
898
1162
|
this.toolbar?.setPage(payload.page, total);
|
|
1163
|
+
this.thumbnailPanel?.setActive(payload.page - 1);
|
|
899
1164
|
}
|
|
900
1165
|
this.eventEmitter.emit(event, payload);
|
|
901
|
-
}
|
|
1166
|
+
},
|
|
1167
|
+
toggleThumbnails: () => this.toggleThumbnails()
|
|
902
1168
|
});
|
|
903
1169
|
this.activeInstance = instance;
|
|
904
1170
|
instance.openInSeparateWindow = () => this.openInSeparateWindow();
|
|
1171
|
+
instance.toggleThumbnails = () => this.toggleThumbnails();
|
|
905
1172
|
this.hideLoading();
|
|
906
1173
|
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
907
|
-
|
|
1174
|
+
const isToolbarVisible = options.showToolbar !== false && options.toolbar !== false;
|
|
1175
|
+
if (isToolbarVisible && this.toolbar) {
|
|
1176
|
+
const toolbarConfig = this.extractToolbarConfig(options);
|
|
1177
|
+
this.toolbar.setConfig(toolbarConfig);
|
|
908
1178
|
const actions = matchedPlugin.getToolbarActions(instance);
|
|
909
1179
|
const hasFullscreen = actions.some((a) => a.id === "fullscreen");
|
|
910
1180
|
if (!hasFullscreen && this.wrapperEl) {
|
|
@@ -954,6 +1224,12 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
954
1224
|
}
|
|
955
1225
|
});
|
|
956
1226
|
}
|
|
1227
|
+
const thumbAction = actions.find((a) => a.id === "thumbnails");
|
|
1228
|
+
if (thumbAction) {
|
|
1229
|
+
thumbAction.execute = () => {
|
|
1230
|
+
this.toggleThumbnails();
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
957
1233
|
this.toolbar.update(actions);
|
|
958
1234
|
this.toolbar.show();
|
|
959
1235
|
}
|
|
@@ -1038,7 +1314,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1038
1314
|
if (targetUrl) {
|
|
1039
1315
|
const newWin2 = window.open(targetUrl, "_blank");
|
|
1040
1316
|
if (!newWin2) {
|
|
1041
|
-
|
|
1317
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
1042
1318
|
return null;
|
|
1043
1319
|
}
|
|
1044
1320
|
return newWin2;
|
|
@@ -1046,7 +1322,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1046
1322
|
const title = (this.currentMetadata?.name || "Document Preview") + " - Full Preview";
|
|
1047
1323
|
const newWin = window.open("", "_blank");
|
|
1048
1324
|
if (!newWin) {
|
|
1049
|
-
|
|
1325
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
1050
1326
|
return null;
|
|
1051
1327
|
}
|
|
1052
1328
|
newWin.document.title = title;
|
|
@@ -1123,6 +1399,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1123
1399
|
this.currentBuffer = null;
|
|
1124
1400
|
this.currentMetadata = null;
|
|
1125
1401
|
this.currentContainer = null;
|
|
1402
|
+
this.titleBarEl = null;
|
|
1126
1403
|
}
|
|
1127
1404
|
/**
|
|
1128
1405
|
* Get the currently active preview instance.
|
|
@@ -1130,7 +1407,218 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1130
1407
|
getInstance() {
|
|
1131
1408
|
return this.activeInstance;
|
|
1132
1409
|
}
|
|
1410
|
+
// --- Toolbar Configuration & Feature Toggles ---
|
|
1411
|
+
/**
|
|
1412
|
+
* Configure toolbar features dynamically through options or methods.
|
|
1413
|
+
* e.g. viewer.setToolbarConfig({ zoomIn: false, print: false })
|
|
1414
|
+
*/
|
|
1415
|
+
setToolbarConfig(config) {
|
|
1416
|
+
this.toolbar?.setConfig(config);
|
|
1417
|
+
}
|
|
1418
|
+
/**
|
|
1419
|
+
* Get current toolbar configuration.
|
|
1420
|
+
*/
|
|
1421
|
+
getToolbarConfig() {
|
|
1422
|
+
return this.toolbar?.getConfig() ?? {};
|
|
1423
|
+
}
|
|
1424
|
+
/**
|
|
1425
|
+
* Hide a specific toolbar action by ID or alias (e.g. 'zoom-in', 'print', 'download').
|
|
1426
|
+
*/
|
|
1427
|
+
hideToolbarAction(actionId) {
|
|
1428
|
+
this.toolbar?.hideAction(actionId);
|
|
1429
|
+
}
|
|
1430
|
+
/**
|
|
1431
|
+
* Show a specific toolbar action by ID or alias.
|
|
1432
|
+
*/
|
|
1433
|
+
showToolbarAction(actionId) {
|
|
1434
|
+
this.toolbar?.showAction(actionId);
|
|
1435
|
+
}
|
|
1436
|
+
/**
|
|
1437
|
+
* Enable a specific toolbar action button.
|
|
1438
|
+
*/
|
|
1439
|
+
enableToolbarAction(actionId) {
|
|
1440
|
+
this.toolbar?.enableAction(actionId);
|
|
1441
|
+
}
|
|
1442
|
+
/**
|
|
1443
|
+
* Disable a specific toolbar action button.
|
|
1444
|
+
*/
|
|
1445
|
+
disableToolbarAction(actionId) {
|
|
1446
|
+
this.toolbar?.disableAction(actionId);
|
|
1447
|
+
}
|
|
1448
|
+
// --- Programmatic Toolbar Action Methods ---
|
|
1449
|
+
/**
|
|
1450
|
+
* Fit document to page so it fills the frame width with minimal margins.
|
|
1451
|
+
*/
|
|
1452
|
+
fitToPage() {
|
|
1453
|
+
this.activeInstance?.fitToPage?.();
|
|
1454
|
+
}
|
|
1455
|
+
/**
|
|
1456
|
+
* Zoom in.
|
|
1457
|
+
*/
|
|
1458
|
+
zoomIn() {
|
|
1459
|
+
this.activeInstance?.zoomIn?.();
|
|
1460
|
+
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Zoom out.
|
|
1463
|
+
*/
|
|
1464
|
+
zoomOut() {
|
|
1465
|
+
this.activeInstance?.zoomOut?.();
|
|
1466
|
+
}
|
|
1467
|
+
/**
|
|
1468
|
+
* Set specific zoom level.
|
|
1469
|
+
*/
|
|
1470
|
+
setZoom(level) {
|
|
1471
|
+
this.activeInstance?.setZoom?.(level);
|
|
1472
|
+
}
|
|
1473
|
+
/**
|
|
1474
|
+
* Get current zoom level.
|
|
1475
|
+
*/
|
|
1476
|
+
getZoom() {
|
|
1477
|
+
return this.activeInstance?.getZoom?.() ?? 1;
|
|
1478
|
+
}
|
|
1479
|
+
/**
|
|
1480
|
+
* Rotate 90 degrees clockwise.
|
|
1481
|
+
*/
|
|
1482
|
+
rotateCW() {
|
|
1483
|
+
this.activeInstance?.rotateCW?.();
|
|
1484
|
+
}
|
|
1485
|
+
/**
|
|
1486
|
+
* Rotate 90 degrees counter-clockwise.
|
|
1487
|
+
*/
|
|
1488
|
+
rotateCCW() {
|
|
1489
|
+
this.activeInstance?.rotateCCW?.();
|
|
1490
|
+
}
|
|
1491
|
+
/**
|
|
1492
|
+
* Navigate to a specific page number.
|
|
1493
|
+
*/
|
|
1494
|
+
goToPage(page) {
|
|
1495
|
+
this.activeInstance?.goToPage?.(page);
|
|
1496
|
+
this.toolbar?.setPage(page);
|
|
1497
|
+
}
|
|
1498
|
+
/**
|
|
1499
|
+
* Navigate to next page.
|
|
1500
|
+
*/
|
|
1501
|
+
nextPage() {
|
|
1502
|
+
const cur = this.getCurrentPage();
|
|
1503
|
+
const max = this.getPageCount();
|
|
1504
|
+
if (cur < max) {
|
|
1505
|
+
this.goToPage(cur + 1);
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
/**
|
|
1509
|
+
* Navigate to previous page.
|
|
1510
|
+
*/
|
|
1511
|
+
prevPage() {
|
|
1512
|
+
const cur = this.getCurrentPage();
|
|
1513
|
+
if (cur > 1) {
|
|
1514
|
+
this.goToPage(cur - 1);
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
/**
|
|
1518
|
+
* Get total page count.
|
|
1519
|
+
*/
|
|
1520
|
+
getPageCount() {
|
|
1521
|
+
return this.activeInstance?.getPageCount?.() ?? 1;
|
|
1522
|
+
}
|
|
1523
|
+
/**
|
|
1524
|
+
* Get current page number.
|
|
1525
|
+
*/
|
|
1526
|
+
getCurrentPage() {
|
|
1527
|
+
return this.activeInstance?.getCurrentPage?.() ?? 1;
|
|
1528
|
+
}
|
|
1529
|
+
/**
|
|
1530
|
+
* Download the current document.
|
|
1531
|
+
*/
|
|
1532
|
+
download() {
|
|
1533
|
+
this.activeInstance?.download?.();
|
|
1534
|
+
}
|
|
1535
|
+
/**
|
|
1536
|
+
* Print the current document.
|
|
1537
|
+
*/
|
|
1538
|
+
print() {
|
|
1539
|
+
this.activeInstance?.print?.();
|
|
1540
|
+
}
|
|
1541
|
+
/**
|
|
1542
|
+
* Toggle fullscreen mode.
|
|
1543
|
+
*/
|
|
1544
|
+
toggleFullscreen() {
|
|
1545
|
+
try {
|
|
1546
|
+
if (!document.fullscreenElement) {
|
|
1547
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
1548
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
1549
|
+
} else {
|
|
1550
|
+
document.exitFullscreen?.();
|
|
1551
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
1552
|
+
}
|
|
1553
|
+
} catch {
|
|
1554
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
1555
|
+
}
|
|
1556
|
+
setTimeout(() => {
|
|
1557
|
+
this.activeInstance?.fitToPage?.();
|
|
1558
|
+
}, 120);
|
|
1559
|
+
}
|
|
1560
|
+
/**
|
|
1561
|
+
* Toggle thumbnails sidebar panel.
|
|
1562
|
+
*/
|
|
1563
|
+
toggleThumbnails() {
|
|
1564
|
+
if (!this.thumbnailPanel) return;
|
|
1565
|
+
this.thumbnailPanel.toggle();
|
|
1566
|
+
const isOpen = this.thumbnailPanel.isOpen();
|
|
1567
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1568
|
+
setTimeout(() => {
|
|
1569
|
+
this.activeInstance?.fitToPage?.();
|
|
1570
|
+
}, 260);
|
|
1571
|
+
}
|
|
1572
|
+
/**
|
|
1573
|
+
* Set whether to display the file name / title bar above the toolbar.
|
|
1574
|
+
*/
|
|
1575
|
+
setShowFileName(show) {
|
|
1576
|
+
if (this.currentOptions) {
|
|
1577
|
+
this.currentOptions.showFileName = show;
|
|
1578
|
+
}
|
|
1579
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1580
|
+
}
|
|
1581
|
+
/**
|
|
1582
|
+
* Set or override the displayed file name in the preview panel.
|
|
1583
|
+
*/
|
|
1584
|
+
setFileName(name) {
|
|
1585
|
+
if (this.currentOptions) {
|
|
1586
|
+
this.currentOptions.fileName = name;
|
|
1587
|
+
}
|
|
1588
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1589
|
+
}
|
|
1133
1590
|
// --- Private methods ---
|
|
1591
|
+
updateTitleBar(options, metadata) {
|
|
1592
|
+
if (!this.titleBarEl) return;
|
|
1593
|
+
const show = options?.showFileName !== false;
|
|
1594
|
+
if (!show) {
|
|
1595
|
+
this.titleBarEl.style.display = "none";
|
|
1596
|
+
return;
|
|
1597
|
+
}
|
|
1598
|
+
const name = options?.fileName || metadata?.name || this.currentMetadata?.name || "";
|
|
1599
|
+
if (!name) {
|
|
1600
|
+
this.titleBarEl.style.display = "none";
|
|
1601
|
+
return;
|
|
1602
|
+
}
|
|
1603
|
+
this.titleBarEl.style.display = "flex";
|
|
1604
|
+
const ext = metadata?.extension || (name.includes(".") ? "." + name.split(".").pop() : "");
|
|
1605
|
+
const badge = ext ? ext.replace(".", "").toUpperCase() : "";
|
|
1606
|
+
this.titleBarEl.innerHTML = `
|
|
1607
|
+
<div class="fp-titlebar-info">
|
|
1608
|
+
<span class="fp-titlebar-icon">\u{1F4C4}</span>
|
|
1609
|
+
<span class="fp-titlebar-name" title="${name}">${name}</span>
|
|
1610
|
+
${badge ? `<span class="fp-titlebar-badge">${badge}</span>` : ""}
|
|
1611
|
+
</div>
|
|
1612
|
+
`;
|
|
1613
|
+
}
|
|
1614
|
+
extractToolbarConfig(options) {
|
|
1615
|
+
if (!options) return {};
|
|
1616
|
+
const nested = typeof options.toolbar === "object" ? options.toolbar : {};
|
|
1617
|
+
return {
|
|
1618
|
+
...options,
|
|
1619
|
+
...nested
|
|
1620
|
+
};
|
|
1621
|
+
}
|
|
1134
1622
|
abort() {
|
|
1135
1623
|
if (this.abortController) {
|
|
1136
1624
|
this.abortController.abort();
|
|
@@ -1173,17 +1661,29 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1173
1661
|
bodyEl.className = "fp-body";
|
|
1174
1662
|
bodyEl.appendChild(thumbnailEl);
|
|
1175
1663
|
bodyEl.appendChild(this.contentEl);
|
|
1664
|
+
const titleBarEl = document.createElement("div");
|
|
1665
|
+
titleBarEl.className = "fp-titlebar";
|
|
1666
|
+
this.titleBarEl = titleBarEl;
|
|
1667
|
+
this.updateTitleBar(options, this.currentMetadata);
|
|
1176
1668
|
if (toolbarPos === "top") {
|
|
1669
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1177
1670
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1178
1671
|
this.wrapperEl.appendChild(bodyEl);
|
|
1179
1672
|
} else {
|
|
1673
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1180
1674
|
this.wrapperEl.appendChild(bodyEl);
|
|
1181
1675
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1182
1676
|
}
|
|
1183
1677
|
container.innerHTML = "";
|
|
1184
1678
|
container.appendChild(this.wrapperEl);
|
|
1185
|
-
|
|
1186
|
-
this.
|
|
1679
|
+
const initialToolbarConfig = this.extractToolbarConfig(options);
|
|
1680
|
+
this.toolbar = new ToolbarController(toolbarEl, initialToolbarConfig);
|
|
1681
|
+
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl, (isOpen) => {
|
|
1682
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1683
|
+
setTimeout(() => {
|
|
1684
|
+
this.activeInstance?.fitToPage?.();
|
|
1685
|
+
}, 260);
|
|
1686
|
+
});
|
|
1187
1687
|
this.setupKeyboardShortcuts();
|
|
1188
1688
|
this.setupDragAndDrop(container, options);
|
|
1189
1689
|
this.setupResizeAndFullscreenListeners();
|
|
@@ -1573,6 +2073,14 @@ var PdfPlugin = class {
|
|
|
1573
2073
|
group: "zoom",
|
|
1574
2074
|
execute: () => instance.fitToPage?.()
|
|
1575
2075
|
},
|
|
2076
|
+
{
|
|
2077
|
+
id: "fit-width",
|
|
2078
|
+
icon: "fit-width",
|
|
2079
|
+
label: "Fit to Width",
|
|
2080
|
+
type: "button",
|
|
2081
|
+
group: "zoom",
|
|
2082
|
+
execute: () => instance.fitToWidth?.()
|
|
2083
|
+
},
|
|
1576
2084
|
{
|
|
1577
2085
|
id: "rotate-cw",
|
|
1578
2086
|
icon: "rotate-cw",
|
|
@@ -1581,6 +2089,14 @@ var PdfPlugin = class {
|
|
|
1581
2089
|
group: "view",
|
|
1582
2090
|
execute: () => instance.rotateCW?.()
|
|
1583
2091
|
},
|
|
2092
|
+
{
|
|
2093
|
+
id: "rotate-ccw",
|
|
2094
|
+
icon: "rotate-ccw",
|
|
2095
|
+
label: "Rotate Counter-Clockwise",
|
|
2096
|
+
type: "button",
|
|
2097
|
+
group: "view",
|
|
2098
|
+
execute: () => instance.rotateCCW?.()
|
|
2099
|
+
},
|
|
1584
2100
|
{
|
|
1585
2101
|
id: "download",
|
|
1586
2102
|
icon: "download",
|
|
@@ -1612,12 +2128,13 @@ var PdfPlugin = class {
|
|
|
1612
2128
|
container.className = "fp-pdf-container";
|
|
1613
2129
|
container.style.width = "100%";
|
|
1614
2130
|
container.style.height = "100%";
|
|
1615
|
-
container.style.
|
|
2131
|
+
container.style.overflowX = "hidden";
|
|
2132
|
+
container.style.overflowY = "auto";
|
|
1616
2133
|
container.style.display = "flex";
|
|
1617
2134
|
container.style.flexDirection = "column";
|
|
1618
2135
|
container.style.alignItems = "center";
|
|
1619
2136
|
container.style.justifyContent = "flex-start";
|
|
1620
|
-
container.style.padding = "
|
|
2137
|
+
container.style.padding = "16px 8px";
|
|
1621
2138
|
container.style.backgroundColor = "#0f172a";
|
|
1622
2139
|
container.style.boxSizing = "border-box";
|
|
1623
2140
|
container.style.position = "relative";
|
|
@@ -1628,30 +2145,12 @@ var PdfPlugin = class {
|
|
|
1628
2145
|
pageCard.style.borderRadius = "4px";
|
|
1629
2146
|
pageCard.style.overflow = "hidden";
|
|
1630
2147
|
pageCard.style.lineHeight = "0";
|
|
1631
|
-
pageCard.style.transition = "transform 0.15s ease";
|
|
1632
2148
|
pageCard.style.position = "relative";
|
|
1633
2149
|
pageCard.style.flexShrink = "0";
|
|
2150
|
+
pageCard.style.transition = "box-shadow 0.2s ease";
|
|
1634
2151
|
let canvas = document.createElement("canvas");
|
|
1635
2152
|
pageCard.appendChild(canvas);
|
|
1636
2153
|
container.appendChild(pageCard);
|
|
1637
|
-
const indicator = document.createElement("div");
|
|
1638
|
-
indicator.className = "fp-pdf-page-indicator";
|
|
1639
|
-
indicator.style.position = "sticky";
|
|
1640
|
-
indicator.style.bottom = "16px";
|
|
1641
|
-
indicator.style.marginTop = "16px";
|
|
1642
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1643
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
1644
|
-
indicator.style.color = "#f8fafc";
|
|
1645
|
-
indicator.style.fontSize = "12px";
|
|
1646
|
-
indicator.style.fontWeight = "600";
|
|
1647
|
-
indicator.style.padding = "5px 14px";
|
|
1648
|
-
indicator.style.borderRadius = "20px";
|
|
1649
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1650
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1651
|
-
indicator.style.zIndex = "10";
|
|
1652
|
-
indicator.style.userSelect = "none";
|
|
1653
|
-
indicator.style.pointerEvents = "none";
|
|
1654
|
-
container.appendChild(indicator);
|
|
1655
2154
|
ctx.container.appendChild(container);
|
|
1656
2155
|
const standardFontsUrl = typeof window !== "undefined" && window.__PDF_STANDARD_FONTS_URL__ || "./standard_fonts/";
|
|
1657
2156
|
const cmapsUrl = typeof window !== "undefined" && window.__PDF_CMAPS_URL__ || "./cmaps/";
|
|
@@ -1667,8 +2166,9 @@ var PdfPlugin = class {
|
|
|
1667
2166
|
let currentPage = 1;
|
|
1668
2167
|
let zoomScale = 1;
|
|
1669
2168
|
let rotation = 0;
|
|
1670
|
-
let fitMode = "
|
|
2169
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
1671
2170
|
let currentRenderTask = null;
|
|
2171
|
+
let textLayerDiv = null;
|
|
1672
2172
|
const renderPage = async (pageNum) => {
|
|
1673
2173
|
if (currentRenderTask) {
|
|
1674
2174
|
try {
|
|
@@ -1680,30 +2180,37 @@ var PdfPlugin = class {
|
|
|
1680
2180
|
const newCanvas = document.createElement("canvas");
|
|
1681
2181
|
pageCard.replaceChild(newCanvas, canvas);
|
|
1682
2182
|
canvas = newCanvas;
|
|
2183
|
+
if (textLayerDiv) {
|
|
2184
|
+
textLayerDiv.remove();
|
|
2185
|
+
textLayerDiv = null;
|
|
2186
|
+
}
|
|
1683
2187
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1684
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1685
2188
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1686
2189
|
const page = await pdfDoc.getPage(currentPage);
|
|
1687
2190
|
const containerWidth = container.clientWidth || 900;
|
|
1688
2191
|
const containerHeight = container.clientHeight || 700;
|
|
1689
2192
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1690
|
-
const availWidth = Math.max(
|
|
1691
|
-
const availHeight = Math.max(
|
|
2193
|
+
const availWidth = Math.max(280, containerWidth - 36);
|
|
2194
|
+
const availHeight = Math.max(280, containerHeight - 32);
|
|
1692
2195
|
const scaleW = availWidth / unscaledVp.width;
|
|
1693
2196
|
const scaleH = availHeight / unscaledVp.height;
|
|
1694
2197
|
let fitScale;
|
|
1695
2198
|
if (fitMode === "page") {
|
|
1696
|
-
fitScale = Math.max(0.4, Math.min(scaleW, scaleH));
|
|
2199
|
+
fitScale = Math.max(0.2, Math.min(4, Math.min(scaleW, scaleH)));
|
|
1697
2200
|
} else {
|
|
1698
|
-
fitScale = Math.max(0.
|
|
2201
|
+
fitScale = Math.max(0.2, Math.min(4, scaleW));
|
|
1699
2202
|
}
|
|
1700
2203
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1701
2204
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1702
2205
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
2206
|
+
const displayWidth = Math.floor(viewport.width);
|
|
2207
|
+
const displayHeight = Math.floor(viewport.height);
|
|
1703
2208
|
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1704
2209
|
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1705
|
-
canvas.style.width = `${
|
|
1706
|
-
canvas.style.height = `${
|
|
2210
|
+
canvas.style.width = `${displayWidth}px`;
|
|
2211
|
+
canvas.style.height = `${displayHeight}px`;
|
|
2212
|
+
pageCard.style.width = `${displayWidth}px`;
|
|
2213
|
+
pageCard.style.height = `${displayHeight}px`;
|
|
1707
2214
|
const canvasCtx = canvas.getContext("2d");
|
|
1708
2215
|
if (!canvasCtx) return;
|
|
1709
2216
|
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
@@ -1717,9 +2224,31 @@ var PdfPlugin = class {
|
|
|
1717
2224
|
if (err?.name !== "RenderingCancelledException") {
|
|
1718
2225
|
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1719
2226
|
}
|
|
2227
|
+
return;
|
|
1720
2228
|
} finally {
|
|
1721
2229
|
currentRenderTask = null;
|
|
1722
2230
|
}
|
|
2231
|
+
try {
|
|
2232
|
+
textLayerDiv = document.createElement("div");
|
|
2233
|
+
textLayerDiv.className = "textLayer";
|
|
2234
|
+
textLayerDiv.style.width = `${displayWidth}px`;
|
|
2235
|
+
textLayerDiv.style.height = `${displayHeight}px`;
|
|
2236
|
+
textLayerDiv.style.position = "absolute";
|
|
2237
|
+
textLayerDiv.style.top = "0";
|
|
2238
|
+
textLayerDiv.style.left = "0";
|
|
2239
|
+
textLayerDiv.style.lineHeight = "1";
|
|
2240
|
+
pageCard.appendChild(textLayerDiv);
|
|
2241
|
+
if (pdfjsLib__namespace.TextLayer) {
|
|
2242
|
+
const textLayer = new pdfjsLib__namespace.TextLayer({
|
|
2243
|
+
textContentSource: page.streamTextContent(),
|
|
2244
|
+
container: textLayerDiv,
|
|
2245
|
+
viewport
|
|
2246
|
+
});
|
|
2247
|
+
await textLayer.render();
|
|
2248
|
+
}
|
|
2249
|
+
} catch (err) {
|
|
2250
|
+
console.debug("[PdfPlugin] TextLayer notice:", err);
|
|
2251
|
+
}
|
|
1723
2252
|
};
|
|
1724
2253
|
renderPage(1);
|
|
1725
2254
|
let resizeTimer = null;
|
|
@@ -1729,11 +2258,48 @@ var PdfPlugin = class {
|
|
|
1729
2258
|
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1730
2259
|
renderPage(currentPage);
|
|
1731
2260
|
}
|
|
1732
|
-
},
|
|
2261
|
+
}, 120);
|
|
1733
2262
|
});
|
|
1734
2263
|
resizeObserver.observe(container);
|
|
2264
|
+
const onWheel = (e) => {
|
|
2265
|
+
if (e.ctrlKey || e.metaKey) {
|
|
2266
|
+
e.preventDefault();
|
|
2267
|
+
const delta = e.deltaY > 0 ? -0.15 : 0.15;
|
|
2268
|
+
zoomScale = Math.max(0.25, Math.min(4, Math.round((zoomScale + delta) * 100) / 100));
|
|
2269
|
+
renderPage(currentPage);
|
|
2270
|
+
}
|
|
2271
|
+
};
|
|
2272
|
+
container.addEventListener("wheel", onWheel, { passive: false });
|
|
2273
|
+
const onKeyDown = (e) => {
|
|
2274
|
+
const tag = e.target?.tagName?.toLowerCase();
|
|
2275
|
+
if (tag === "input" || tag === "textarea" || tag === "select") return;
|
|
2276
|
+
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
2277
|
+
if (currentPage < totalPages) {
|
|
2278
|
+
e.preventDefault();
|
|
2279
|
+
container.scrollTop = 0;
|
|
2280
|
+
renderPage(currentPage + 1);
|
|
2281
|
+
}
|
|
2282
|
+
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
2283
|
+
if (currentPage > 1) {
|
|
2284
|
+
e.preventDefault();
|
|
2285
|
+
container.scrollTop = 0;
|
|
2286
|
+
renderPage(currentPage - 1);
|
|
2287
|
+
}
|
|
2288
|
+
} else if (e.key === "Home") {
|
|
2289
|
+
e.preventDefault();
|
|
2290
|
+
container.scrollTop = 0;
|
|
2291
|
+
renderPage(1);
|
|
2292
|
+
} else if (e.key === "End") {
|
|
2293
|
+
e.preventDefault();
|
|
2294
|
+
container.scrollTop = 0;
|
|
2295
|
+
renderPage(totalPages);
|
|
2296
|
+
}
|
|
2297
|
+
};
|
|
2298
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1735
2299
|
const cleanup = () => {
|
|
1736
2300
|
resizeObserver.disconnect();
|
|
2301
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
2302
|
+
container.removeEventListener("wheel", onWheel);
|
|
1737
2303
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1738
2304
|
if (currentRenderTask) {
|
|
1739
2305
|
try {
|
|
@@ -1752,22 +2318,26 @@ var PdfPlugin = class {
|
|
|
1752
2318
|
const instance = {
|
|
1753
2319
|
destroy: cleanup,
|
|
1754
2320
|
zoomIn: () => {
|
|
1755
|
-
zoomScale = Math.min(
|
|
2321
|
+
zoomScale = Math.min(4, Math.round((zoomScale + 0.2) * 10) / 10);
|
|
1756
2322
|
renderPage(currentPage);
|
|
1757
2323
|
},
|
|
1758
2324
|
zoomOut: () => {
|
|
1759
|
-
zoomScale = Math.max(0.
|
|
2325
|
+
zoomScale = Math.max(0.25, Math.round((zoomScale - 0.2) * 10) / 10);
|
|
1760
2326
|
renderPage(currentPage);
|
|
1761
2327
|
},
|
|
1762
2328
|
getZoom: () => zoomScale,
|
|
1763
2329
|
setZoom: (level) => {
|
|
1764
|
-
zoomScale = Math.max(0.
|
|
2330
|
+
zoomScale = Math.max(0.25, Math.min(4, level));
|
|
1765
2331
|
renderPage(currentPage);
|
|
1766
2332
|
},
|
|
1767
2333
|
fitToPage: () => {
|
|
1768
|
-
fitMode =
|
|
2334
|
+
fitMode = "page";
|
|
2335
|
+
zoomScale = 1;
|
|
2336
|
+
renderPage(currentPage);
|
|
2337
|
+
},
|
|
2338
|
+
fitToWidth: () => {
|
|
2339
|
+
fitMode = "width";
|
|
1769
2340
|
zoomScale = 1;
|
|
1770
|
-
rotation = 0;
|
|
1771
2341
|
renderPage(currentPage);
|
|
1772
2342
|
},
|
|
1773
2343
|
rotateCW: () => {
|
|
@@ -1785,6 +2355,9 @@ var PdfPlugin = class {
|
|
|
1785
2355
|
container.scrollTop = 0;
|
|
1786
2356
|
renderPage(page);
|
|
1787
2357
|
},
|
|
2358
|
+
toggleThumbnails: () => {
|
|
2359
|
+
ctx?.toggleThumbnails?.();
|
|
2360
|
+
},
|
|
1788
2361
|
download: () => {
|
|
1789
2362
|
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1790
2363
|
const url = URL.createObjectURL(blob);
|
|
@@ -1818,7 +2391,7 @@ var PdfPlugin = class {
|
|
|
1818
2391
|
},
|
|
1819
2392
|
getThumbnails: async () => {
|
|
1820
2393
|
const thumbnails = [];
|
|
1821
|
-
const count =
|
|
2394
|
+
const count = totalPages;
|
|
1822
2395
|
for (let i = 1; i <= count; i++) {
|
|
1823
2396
|
thumbnails.push({
|
|
1824
2397
|
index: i,
|
|
@@ -1826,9 +2399,10 @@ var PdfPlugin = class {
|
|
|
1826
2399
|
render: async (thumbCanvas) => {
|
|
1827
2400
|
try {
|
|
1828
2401
|
const p = await pdfDoc.getPage(i);
|
|
1829
|
-
const baseVp = p.getViewport({ scale: 1 });
|
|
1830
|
-
const
|
|
1831
|
-
const
|
|
2402
|
+
const baseVp = p.getViewport({ scale: 1, rotation });
|
|
2403
|
+
const targetW = thumbCanvas.width || 130;
|
|
2404
|
+
const thumbScale = targetW / baseVp.width;
|
|
2405
|
+
const thumbVp = p.getViewport({ scale: thumbScale, rotation });
|
|
1832
2406
|
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1833
2407
|
const tCtx = thumbCanvas.getContext("2d");
|
|
1834
2408
|
if (tCtx) {
|
|
@@ -2172,28 +2746,26 @@ var DocxPlugin = class {
|
|
|
2172
2746
|
getToolbarActions(instance) {
|
|
2173
2747
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2174
2748
|
const actions = [];
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
if (
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
instance.goToPage?.(page);
|
|
2193
|
-
}
|
|
2749
|
+
actions.push({
|
|
2750
|
+
id: "page-nav",
|
|
2751
|
+
icon: "",
|
|
2752
|
+
label: "Page Navigation",
|
|
2753
|
+
type: "page-nav",
|
|
2754
|
+
group: "navigation",
|
|
2755
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2756
|
+
max: totalPages,
|
|
2757
|
+
execute: (action, page) => {
|
|
2758
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2759
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2760
|
+
if (action === "prev") {
|
|
2761
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2762
|
+
} else if (action === "next") {
|
|
2763
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2764
|
+
} else if (typeof page === "number") {
|
|
2765
|
+
instance.goToPage?.(page);
|
|
2194
2766
|
}
|
|
2195
|
-
}
|
|
2196
|
-
}
|
|
2767
|
+
}
|
|
2768
|
+
});
|
|
2197
2769
|
actions.push(
|
|
2198
2770
|
{
|
|
2199
2771
|
id: "zoom-out",
|
|
@@ -2259,11 +2831,17 @@ var DocxPlugin = class {
|
|
|
2259
2831
|
wrapper.className = "fp-docx-wrapper";
|
|
2260
2832
|
wrapper.style.transformOrigin = "top center";
|
|
2261
2833
|
wrapper.style.transition = "transform 0.2s ease";
|
|
2262
|
-
wrapper.style.padding = "
|
|
2263
|
-
wrapper.style.maxWidth = "
|
|
2834
|
+
wrapper.style.padding = "0";
|
|
2835
|
+
wrapper.style.maxWidth = "none";
|
|
2836
|
+
wrapper.style.width = "816px";
|
|
2264
2837
|
wrapper.style.margin = "0 auto";
|
|
2838
|
+
wrapper.style.display = "flex";
|
|
2839
|
+
wrapper.style.flexDirection = "column";
|
|
2840
|
+
wrapper.style.alignItems = "center";
|
|
2265
2841
|
wrapper.style.boxSizing = "border-box";
|
|
2266
|
-
ctx.container.style.
|
|
2842
|
+
ctx.container.style.overflowX = "hidden";
|
|
2843
|
+
ctx.container.style.overflowY = "auto";
|
|
2844
|
+
ctx.container.style.padding = "16px 8px";
|
|
2267
2845
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
2268
2846
|
ctx.container.appendChild(wrapper);
|
|
2269
2847
|
const styleOverride = document.createElement("style");
|
|
@@ -2437,39 +3015,13 @@ var DocxPlugin = class {
|
|
|
2437
3015
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2438
3016
|
const totalPages = Math.max(1, pageElements.length);
|
|
2439
3017
|
let currentPage = 1;
|
|
2440
|
-
let indicator = null;
|
|
2441
|
-
if (totalPages > 1) {
|
|
2442
|
-
indicator = document.createElement("div");
|
|
2443
|
-
indicator.className = "fp-docx-page-indicator";
|
|
2444
|
-
indicator.style.position = "sticky";
|
|
2445
|
-
indicator.style.bottom = "16px";
|
|
2446
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2447
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
2448
|
-
indicator.style.color = "#f8fafc";
|
|
2449
|
-
indicator.style.fontSize = "12px";
|
|
2450
|
-
indicator.style.fontWeight = "600";
|
|
2451
|
-
indicator.style.padding = "5px 14px";
|
|
2452
|
-
indicator.style.borderRadius = "20px";
|
|
2453
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2454
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2455
|
-
indicator.style.zIndex = "10";
|
|
2456
|
-
indicator.style.userSelect = "none";
|
|
2457
|
-
indicator.style.pointerEvents = "none";
|
|
2458
|
-
indicator.style.textAlign = "center";
|
|
2459
|
-
indicator.style.width = "fit-content";
|
|
2460
|
-
indicator.style.margin = "16px auto 0";
|
|
2461
|
-
ctx.container.appendChild(indicator);
|
|
2462
|
-
}
|
|
2463
3018
|
const showPage = (pageNum) => {
|
|
2464
3019
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2465
3020
|
if (pageElements.length > 1) {
|
|
2466
3021
|
pageElements.forEach((sec, idx) => {
|
|
2467
|
-
sec.style.display = idx + 1 === currentPage ? "
|
|
3022
|
+
sec.style.display = idx + 1 === currentPage ? "" : "none";
|
|
2468
3023
|
});
|
|
2469
3024
|
}
|
|
2470
|
-
if (indicator) {
|
|
2471
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2472
|
-
}
|
|
2473
3025
|
ctx.container.scrollTop = 0;
|
|
2474
3026
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2475
3027
|
};
|
|
@@ -2478,31 +3030,46 @@ var DocxPlugin = class {
|
|
|
2478
3030
|
}
|
|
2479
3031
|
scale = 1;
|
|
2480
3032
|
let rotation = 0;
|
|
2481
|
-
let fitMode = "
|
|
2482
|
-
|
|
2483
|
-
|
|
3033
|
+
let fitMode = "page";
|
|
3034
|
+
let isUserZoomed = false;
|
|
3035
|
+
const calculateFitScale = (_mode = fitMode) => {
|
|
3036
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
2484
3037
|
const elW = activeEl.offsetWidth || 816;
|
|
2485
|
-
const
|
|
2486
|
-
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
2487
|
-
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
3038
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
2488
3039
|
const sW = availW / elW;
|
|
2489
|
-
|
|
2490
|
-
if (mode === "page") {
|
|
2491
|
-
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
2492
|
-
}
|
|
2493
|
-
return Math.max(0.65, Math.min(1.05, sW));
|
|
3040
|
+
return Math.max(0.35, Math.min(3, sW));
|
|
2494
3041
|
};
|
|
2495
3042
|
const applyTransform = () => {
|
|
2496
3043
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2497
3044
|
wrapper.style.transformOrigin = "top center";
|
|
3045
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
3046
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
3047
|
+
if (scale > 1) {
|
|
3048
|
+
wrapper.style.marginBottom = `${Math.round(elH * scale - elH + 32)}px`;
|
|
3049
|
+
} else {
|
|
3050
|
+
wrapper.style.marginBottom = "32px";
|
|
3051
|
+
}
|
|
2498
3052
|
};
|
|
3053
|
+
let resizeObserver = null;
|
|
3054
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
3055
|
+
resizeObserver = new ResizeObserver(() => {
|
|
3056
|
+
if (!isUserZoomed) {
|
|
3057
|
+
const newFit = calculateFitScale("page");
|
|
3058
|
+
if (Math.abs(scale - newFit) > 0.015) {
|
|
3059
|
+
scale = newFit;
|
|
3060
|
+
applyTransform();
|
|
3061
|
+
}
|
|
3062
|
+
}
|
|
3063
|
+
});
|
|
3064
|
+
resizeObserver.observe(ctx.container);
|
|
3065
|
+
}
|
|
2499
3066
|
setTimeout(() => {
|
|
2500
|
-
|
|
2501
|
-
scale = calculateFitScale("width");
|
|
3067
|
+
scale = calculateFitScale("page");
|
|
2502
3068
|
applyTransform();
|
|
2503
|
-
},
|
|
3069
|
+
}, 40);
|
|
2504
3070
|
const cleanup = () => {
|
|
2505
|
-
|
|
3071
|
+
resizeObserver?.disconnect();
|
|
3072
|
+
resizeObserver = null;
|
|
2506
3073
|
for (const url of createdBlobUrls) {
|
|
2507
3074
|
URL.revokeObjectURL(url);
|
|
2508
3075
|
}
|
|
@@ -2519,21 +3086,24 @@ var DocxPlugin = class {
|
|
|
2519
3086
|
showPage(page);
|
|
2520
3087
|
},
|
|
2521
3088
|
zoomIn: () => {
|
|
2522
|
-
|
|
3089
|
+
isUserZoomed = true;
|
|
3090
|
+
scale = Math.min(3.5, scale + 0.15);
|
|
2523
3091
|
applyTransform();
|
|
2524
3092
|
},
|
|
2525
3093
|
zoomOut: () => {
|
|
3094
|
+
isUserZoomed = true;
|
|
2526
3095
|
scale = Math.max(0.2, scale - 0.15);
|
|
2527
3096
|
applyTransform();
|
|
2528
3097
|
},
|
|
2529
3098
|
getZoom: () => scale,
|
|
2530
3099
|
setZoom: (level) => {
|
|
3100
|
+
isUserZoomed = true;
|
|
2531
3101
|
scale = level;
|
|
2532
3102
|
applyTransform();
|
|
2533
3103
|
},
|
|
2534
3104
|
fitToPage: () => {
|
|
2535
|
-
|
|
2536
|
-
scale = calculateFitScale(
|
|
3105
|
+
isUserZoomed = false;
|
|
3106
|
+
scale = calculateFitScale("page");
|
|
2537
3107
|
rotation = 0;
|
|
2538
3108
|
applyTransform();
|
|
2539
3109
|
},
|
|
@@ -2923,7 +3493,7 @@ var ExcelPlugin = class {
|
|
|
2923
3493
|
"application/vnd.ms-excel.template.macroEnabled.12",
|
|
2924
3494
|
"application/vnd.oasis.opendocument.spreadsheet"
|
|
2925
3495
|
];
|
|
2926
|
-
weight =
|
|
3496
|
+
weight = 85;
|
|
2927
3497
|
supports(file) {
|
|
2928
3498
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2929
3499
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
@@ -2935,6 +3505,14 @@ var ExcelPlugin = class {
|
|
|
2935
3505
|
getToolbarActions(instance) {
|
|
2936
3506
|
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2937
3507
|
const actions = [];
|
|
3508
|
+
actions.push({
|
|
3509
|
+
id: "thumbnails",
|
|
3510
|
+
icon: "thumbnails",
|
|
3511
|
+
label: "Sheet Thumbnails",
|
|
3512
|
+
type: "button",
|
|
3513
|
+
group: "navigation",
|
|
3514
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3515
|
+
});
|
|
2938
3516
|
if (totalSheets > 1) {
|
|
2939
3517
|
actions.push({
|
|
2940
3518
|
id: "page-nav",
|
|
@@ -3017,6 +3595,16 @@ var ExcelPlugin = class {
|
|
|
3017
3595
|
execute: () => {
|
|
3018
3596
|
instance.print?.();
|
|
3019
3597
|
}
|
|
3598
|
+
},
|
|
3599
|
+
{
|
|
3600
|
+
id: "open-window",
|
|
3601
|
+
icon: "open-window",
|
|
3602
|
+
label: "Open in Separate Full Window",
|
|
3603
|
+
type: "button",
|
|
3604
|
+
group: "actions",
|
|
3605
|
+
execute: () => {
|
|
3606
|
+
instance.openInSeparateWindow?.();
|
|
3607
|
+
}
|
|
3020
3608
|
}
|
|
3021
3609
|
);
|
|
3022
3610
|
return actions;
|
|
@@ -3182,6 +3770,63 @@ var ExcelPlugin = class {
|
|
|
3182
3770
|
},
|
|
3183
3771
|
getPageCount: () => sheetNames.length,
|
|
3184
3772
|
getCurrentPage: () => currentSheetIndex,
|
|
3773
|
+
getThumbnails: () => {
|
|
3774
|
+
return sheetNames.map((name, idx) => ({
|
|
3775
|
+
index: idx,
|
|
3776
|
+
label: name,
|
|
3777
|
+
render: async (canvas) => {
|
|
3778
|
+
canvas.width = 140;
|
|
3779
|
+
canvas.height = 100;
|
|
3780
|
+
const c = canvas.getContext("2d");
|
|
3781
|
+
if (!c) return;
|
|
3782
|
+
c.fillStyle = "#ffffff";
|
|
3783
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
3784
|
+
c.fillStyle = "#107c41";
|
|
3785
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
3786
|
+
c.fillStyle = "#ffffff";
|
|
3787
|
+
c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
3788
|
+
c.fillText(`\u{1F4CA} ${name.slice(0, 16)}`, 6, 11);
|
|
3789
|
+
const startY = 17;
|
|
3790
|
+
const rowH = 13;
|
|
3791
|
+
const colW = 30;
|
|
3792
|
+
const colHeaders = ["A", "B", "C", "D"];
|
|
3793
|
+
c.fillStyle = "#f1f5f9";
|
|
3794
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
3795
|
+
c.strokeStyle = "#cbd5e1";
|
|
3796
|
+
c.lineWidth = 0.8;
|
|
3797
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
3798
|
+
c.fillStyle = "#64748b";
|
|
3799
|
+
c.font = "bold 7px sans-serif";
|
|
3800
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3801
|
+
c.fillText(colHeaders[ci], 14 + ci * colW, startY + 9);
|
|
3802
|
+
}
|
|
3803
|
+
const ws = wb?.Sheets[name];
|
|
3804
|
+
for (let ri = 1; ri <= 5; ri++) {
|
|
3805
|
+
const y = startY + ri * rowH;
|
|
3806
|
+
if (y > canvas.height - 2) break;
|
|
3807
|
+
c.fillStyle = "#f8fafc";
|
|
3808
|
+
c.fillRect(0, y, 12, rowH);
|
|
3809
|
+
c.fillStyle = "#94a3b8";
|
|
3810
|
+
c.font = "6px sans-serif";
|
|
3811
|
+
c.fillText(String(ri), 3, y + 9);
|
|
3812
|
+
c.strokeStyle = "#e2e8f0";
|
|
3813
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
3814
|
+
c.fillStyle = "#334155";
|
|
3815
|
+
c.font = "6px sans-serif";
|
|
3816
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3817
|
+
const cellRef = `${colHeaders[ci]}${ri}`;
|
|
3818
|
+
const cellVal = ws?.[cellRef]?.w || ws?.[cellRef]?.v;
|
|
3819
|
+
if (cellVal !== void 0) {
|
|
3820
|
+
c.fillText(String(cellVal).slice(0, 6), 14 + ci * colW, y + 9);
|
|
3821
|
+
}
|
|
3822
|
+
}
|
|
3823
|
+
}
|
|
3824
|
+
c.strokeStyle = "#cbd5e1";
|
|
3825
|
+
c.lineWidth = 1;
|
|
3826
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
3827
|
+
}
|
|
3828
|
+
}));
|
|
3829
|
+
},
|
|
3185
3830
|
download: () => {
|
|
3186
3831
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
3187
3832
|
const url = URL.createObjectURL(blob);
|
|
@@ -3214,7 +3859,39 @@ var CsvPlugin = class {
|
|
|
3214
3859
|
return ext === ".csv" || ext === ".tsv" || mime === "text/csv" || mime === "text/tab-separated-values";
|
|
3215
3860
|
}
|
|
3216
3861
|
getToolbarActions(instance) {
|
|
3217
|
-
|
|
3862
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3863
|
+
const actions = [];
|
|
3864
|
+
actions.push({
|
|
3865
|
+
id: "thumbnails",
|
|
3866
|
+
icon: "thumbnails",
|
|
3867
|
+
label: "Page Thumbnails",
|
|
3868
|
+
type: "button",
|
|
3869
|
+
group: "navigation",
|
|
3870
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3871
|
+
});
|
|
3872
|
+
if (totalPages > 1) {
|
|
3873
|
+
actions.push({
|
|
3874
|
+
id: "page-nav",
|
|
3875
|
+
icon: "",
|
|
3876
|
+
label: "Page Navigation",
|
|
3877
|
+
type: "page-nav",
|
|
3878
|
+
group: "navigation",
|
|
3879
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3880
|
+
max: totalPages,
|
|
3881
|
+
execute: (action, page) => {
|
|
3882
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3883
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
3884
|
+
if (action === "prev") {
|
|
3885
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3886
|
+
} else if (action === "next") {
|
|
3887
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
3888
|
+
} else if (typeof page === "number") {
|
|
3889
|
+
instance.goToPage?.(page);
|
|
3890
|
+
}
|
|
3891
|
+
}
|
|
3892
|
+
});
|
|
3893
|
+
}
|
|
3894
|
+
actions.push(
|
|
3218
3895
|
{
|
|
3219
3896
|
id: "zoom-out",
|
|
3220
3897
|
icon: "zoom-out",
|
|
@@ -3235,6 +3912,16 @@ var CsvPlugin = class {
|
|
|
3235
3912
|
instance.zoomIn?.();
|
|
3236
3913
|
}
|
|
3237
3914
|
},
|
|
3915
|
+
{
|
|
3916
|
+
id: "fit-page",
|
|
3917
|
+
icon: "fit-page",
|
|
3918
|
+
label: "Fit to View",
|
|
3919
|
+
type: "button",
|
|
3920
|
+
group: "zoom",
|
|
3921
|
+
execute: () => {
|
|
3922
|
+
instance.fitToPage?.();
|
|
3923
|
+
}
|
|
3924
|
+
},
|
|
3238
3925
|
{
|
|
3239
3926
|
id: "download",
|
|
3240
3927
|
icon: "download",
|
|
@@ -3252,10 +3939,21 @@ var CsvPlugin = class {
|
|
|
3252
3939
|
type: "button",
|
|
3253
3940
|
group: "actions",
|
|
3254
3941
|
execute: () => {
|
|
3255
|
-
instance.print?.();
|
|
3942
|
+
instance.print?.();
|
|
3943
|
+
}
|
|
3944
|
+
},
|
|
3945
|
+
{
|
|
3946
|
+
id: "open-window",
|
|
3947
|
+
icon: "open-window",
|
|
3948
|
+
label: "Open in Separate Full Window",
|
|
3949
|
+
type: "button",
|
|
3950
|
+
group: "actions",
|
|
3951
|
+
execute: () => {
|
|
3952
|
+
instance.openInSeparateWindow?.();
|
|
3256
3953
|
}
|
|
3257
3954
|
}
|
|
3258
|
-
|
|
3955
|
+
);
|
|
3956
|
+
return actions;
|
|
3259
3957
|
}
|
|
3260
3958
|
async render(ctx) {
|
|
3261
3959
|
const decoder = new TextDecoder("utf-8");
|
|
@@ -3267,33 +3965,62 @@ var CsvPlugin = class {
|
|
|
3267
3965
|
container.style.padding = "16px";
|
|
3268
3966
|
container.style.boxSizing = "border-box";
|
|
3269
3967
|
container.style.transformOrigin = "top left";
|
|
3968
|
+
const delimiter = ctx.metadata.extension === ".tsv" ? " " : ",";
|
|
3969
|
+
const allLines = text.split(/\r?\n/).filter((r) => r.trim().length > 0);
|
|
3970
|
+
const headerLine = allLines[0] || "";
|
|
3971
|
+
const headerCells = headerLine.split(delimiter);
|
|
3972
|
+
const dataLines = allLines.slice(1);
|
|
3973
|
+
const ROWS_PER_PAGE = 100;
|
|
3974
|
+
const totalPages = Math.max(1, Math.ceil(dataLines.length / ROWS_PER_PAGE));
|
|
3975
|
+
let currentPage = 1;
|
|
3270
3976
|
const table = document.createElement("table");
|
|
3271
3977
|
table.style.borderCollapse = "collapse";
|
|
3272
3978
|
table.style.width = "100%";
|
|
3273
|
-
table.style.fontFamily = "monospace
|
|
3979
|
+
table.style.fontFamily = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace';
|
|
3274
3980
|
table.style.fontSize = "13px";
|
|
3275
|
-
const
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
td.style.fontWeight = "bold";
|
|
3289
|
-
}
|
|
3290
|
-
tr.appendChild(td);
|
|
3981
|
+
const renderPage = (pageNum) => {
|
|
3982
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3983
|
+
table.innerHTML = "";
|
|
3984
|
+
const headerTr = document.createElement("tr");
|
|
3985
|
+
headerCells.forEach((cell) => {
|
|
3986
|
+
const th = document.createElement("th");
|
|
3987
|
+
th.textContent = cell.trim();
|
|
3988
|
+
th.style.border = "1px solid #d0d7de";
|
|
3989
|
+
th.style.padding = "8px 12px";
|
|
3990
|
+
th.style.backgroundColor = "#f6f8fa";
|
|
3991
|
+
th.style.fontWeight = "600";
|
|
3992
|
+
th.style.whiteSpace = "nowrap";
|
|
3993
|
+
headerTr.appendChild(th);
|
|
3291
3994
|
});
|
|
3292
|
-
table.appendChild(
|
|
3293
|
-
|
|
3995
|
+
table.appendChild(headerTr);
|
|
3996
|
+
const start = (currentPage - 1) * ROWS_PER_PAGE;
|
|
3997
|
+
const end = Math.min(dataLines.length, start + ROWS_PER_PAGE);
|
|
3998
|
+
const pageRows = dataLines.slice(start, end);
|
|
3999
|
+
pageRows.forEach((row, idx) => {
|
|
4000
|
+
const tr = document.createElement("tr");
|
|
4001
|
+
if (idx % 2 === 1) tr.style.backgroundColor = "#f8fafc";
|
|
4002
|
+
const cells = row.split(delimiter);
|
|
4003
|
+
cells.forEach((cell) => {
|
|
4004
|
+
const td = document.createElement("td");
|
|
4005
|
+
td.textContent = cell.trim();
|
|
4006
|
+
td.style.border = "1px solid #d0d7de";
|
|
4007
|
+
td.style.padding = "6px 12px";
|
|
4008
|
+
td.style.whiteSpace = "nowrap";
|
|
4009
|
+
tr.appendChild(td);
|
|
4010
|
+
});
|
|
4011
|
+
table.appendChild(tr);
|
|
4012
|
+
});
|
|
4013
|
+
container.scrollTop = 0;
|
|
4014
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4015
|
+
};
|
|
4016
|
+
renderPage(1);
|
|
3294
4017
|
container.appendChild(table);
|
|
3295
4018
|
ctx.container.appendChild(container);
|
|
3296
4019
|
let scale = 1;
|
|
4020
|
+
const applyScale = () => {
|
|
4021
|
+
container.style.transform = `scale(${scale})`;
|
|
4022
|
+
container.style.transformOrigin = "top left";
|
|
4023
|
+
};
|
|
3297
4024
|
const cleanup = () => {
|
|
3298
4025
|
container.remove();
|
|
3299
4026
|
ctx.container.innerHTML = "";
|
|
@@ -3301,22 +4028,86 @@ var CsvPlugin = class {
|
|
|
3301
4028
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3302
4029
|
return {
|
|
3303
4030
|
destroy: cleanup,
|
|
4031
|
+
getPageCount: () => totalPages,
|
|
4032
|
+
getCurrentPage: () => currentPage,
|
|
4033
|
+
goToPage: (page) => renderPage(page),
|
|
4034
|
+
getThumbnails: () => {
|
|
4035
|
+
const thumbnails = [];
|
|
4036
|
+
for (let i = 0; i < totalPages; i++) {
|
|
4037
|
+
const pageIdx = i;
|
|
4038
|
+
const startRow = pageIdx * ROWS_PER_PAGE + 1;
|
|
4039
|
+
const endRow = Math.min(dataLines.length, (pageIdx + 1) * ROWS_PER_PAGE);
|
|
4040
|
+
const label = totalPages === 1 ? "Table" : `Page ${pageIdx + 1} (${startRow}-${endRow})`;
|
|
4041
|
+
thumbnails.push({
|
|
4042
|
+
index: pageIdx,
|
|
4043
|
+
label,
|
|
4044
|
+
render: async (canvas) => {
|
|
4045
|
+
canvas.width = 140;
|
|
4046
|
+
canvas.height = 100;
|
|
4047
|
+
const c = canvas.getContext("2d");
|
|
4048
|
+
if (!c) return;
|
|
4049
|
+
c.fillStyle = "#ffffff";
|
|
4050
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4051
|
+
c.fillStyle = "#2563eb";
|
|
4052
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
4053
|
+
c.fillStyle = "#ffffff";
|
|
4054
|
+
c.font = "bold 8px sans-serif";
|
|
4055
|
+
c.fillText(`\u{1F4C8} ${label.slice(0, 18)}`, 6, 11);
|
|
4056
|
+
const startY = 17;
|
|
4057
|
+
const rowH = 13;
|
|
4058
|
+
const colW = 28;
|
|
4059
|
+
const cols = Math.min(4, headerCells.length || 4);
|
|
4060
|
+
c.fillStyle = "#f1f5f9";
|
|
4061
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
4062
|
+
c.strokeStyle = "#cbd5e1";
|
|
4063
|
+
c.lineWidth = 0.8;
|
|
4064
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
4065
|
+
c.fillStyle = "#64748b";
|
|
4066
|
+
c.font = "bold 7px sans-serif";
|
|
4067
|
+
for (let ci = 0; ci < cols; ci++) {
|
|
4068
|
+
const hName = headerCells[ci] || `Col ${ci + 1}`;
|
|
4069
|
+
c.fillText(hName.slice(0, 5), 8 + ci * colW, startY + 9);
|
|
4070
|
+
}
|
|
4071
|
+
const rowsToPreview = dataLines.slice(pageIdx * ROWS_PER_PAGE, pageIdx * ROWS_PER_PAGE + 5);
|
|
4072
|
+
for (let ri = 0; ri < rowsToPreview.length; ri++) {
|
|
4073
|
+
const y = startY + (ri + 1) * rowH;
|
|
4074
|
+
if (y > canvas.height - 2) break;
|
|
4075
|
+
c.strokeStyle = "#e2e8f0";
|
|
4076
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
4077
|
+
const cVals = rowsToPreview[ri].split(delimiter);
|
|
4078
|
+
c.fillStyle = "#334155";
|
|
4079
|
+
c.font = "6px sans-serif";
|
|
4080
|
+
for (let ci = 0; ci < cols; ci++) {
|
|
4081
|
+
const val = cVals[ci] || "";
|
|
4082
|
+
c.fillText(val.trim().slice(0, 6), 8 + ci * colW, y + 9);
|
|
4083
|
+
}
|
|
4084
|
+
}
|
|
4085
|
+
c.strokeStyle = "#cbd5e1";
|
|
4086
|
+
c.lineWidth = 1;
|
|
4087
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4088
|
+
}
|
|
4089
|
+
});
|
|
4090
|
+
}
|
|
4091
|
+
return thumbnails;
|
|
4092
|
+
},
|
|
3304
4093
|
zoomIn: () => {
|
|
3305
4094
|
scale += 0.1;
|
|
3306
|
-
|
|
4095
|
+
applyScale();
|
|
3307
4096
|
},
|
|
3308
4097
|
zoomOut: () => {
|
|
3309
4098
|
scale = Math.max(0.2, scale - 0.1);
|
|
3310
|
-
|
|
4099
|
+
applyScale();
|
|
3311
4100
|
},
|
|
3312
4101
|
getZoom: () => scale,
|
|
3313
4102
|
setZoom: (level) => {
|
|
3314
4103
|
scale = level;
|
|
3315
|
-
|
|
4104
|
+
applyScale();
|
|
3316
4105
|
},
|
|
3317
4106
|
fitToPage: () => {
|
|
3318
|
-
|
|
3319
|
-
|
|
4107
|
+
const availW = Math.max(280, (ctx.container.clientWidth || window.innerWidth) - 48);
|
|
4108
|
+
const tW = table.offsetWidth || 600;
|
|
4109
|
+
scale = Math.max(0.35, Math.min(1, availW / tW));
|
|
4110
|
+
applyScale();
|
|
3320
4111
|
},
|
|
3321
4112
|
download: () => {
|
|
3322
4113
|
const blob = new Blob([ctx.buffer], { type: "text/csv" });
|
|
@@ -3380,28 +4171,34 @@ var CodePlugin = class {
|
|
|
3380
4171
|
getToolbarActions(instance) {
|
|
3381
4172
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3382
4173
|
const actions = [];
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
4174
|
+
actions.push({
|
|
4175
|
+
id: "thumbnails",
|
|
4176
|
+
icon: "thumbnails",
|
|
4177
|
+
label: "Page Thumbnails",
|
|
4178
|
+
type: "button",
|
|
4179
|
+
group: "navigation",
|
|
4180
|
+
execute: () => instance.toggleThumbnails?.()
|
|
4181
|
+
});
|
|
4182
|
+
actions.push({
|
|
4183
|
+
id: "page-nav",
|
|
4184
|
+
icon: "",
|
|
4185
|
+
label: "Page Navigation",
|
|
4186
|
+
type: "page-nav",
|
|
4187
|
+
group: "navigation",
|
|
4188
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4189
|
+
max: totalPages,
|
|
4190
|
+
execute: (action, page) => {
|
|
4191
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4192
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4193
|
+
if (action === "prev") {
|
|
4194
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4195
|
+
} else if (action === "next") {
|
|
4196
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4197
|
+
} else if (typeof page === "number") {
|
|
4198
|
+
instance.goToPage?.(page);
|
|
3402
4199
|
}
|
|
3403
|
-
}
|
|
3404
|
-
}
|
|
4200
|
+
}
|
|
4201
|
+
});
|
|
3405
4202
|
actions.push(
|
|
3406
4203
|
{
|
|
3407
4204
|
id: "zoom-out",
|
|
@@ -3545,16 +4342,19 @@ var CodePlugin = class {
|
|
|
3545
4342
|
let fontSize = 13;
|
|
3546
4343
|
let rotation = 0;
|
|
3547
4344
|
let zoomLevel = 1;
|
|
4345
|
+
let isUserZoomed = false;
|
|
3548
4346
|
const pre = document.createElement("pre");
|
|
3549
4347
|
const code = document.createElement("code");
|
|
3550
4348
|
if (isTxt) {
|
|
4349
|
+
container.style.overflowX = "hidden";
|
|
4350
|
+
container.style.overflowY = "auto";
|
|
3551
4351
|
container.style.backgroundColor = "#f1f5f9";
|
|
3552
|
-
container.style.padding = "
|
|
4352
|
+
container.style.padding = "16px 8px";
|
|
3553
4353
|
container.style.boxSizing = "border-box";
|
|
3554
4354
|
container.style.display = "flex";
|
|
3555
4355
|
container.style.flexDirection = "column";
|
|
3556
4356
|
container.style.alignItems = "center";
|
|
3557
|
-
pre.style.margin = "0";
|
|
4357
|
+
pre.style.margin = "0 auto";
|
|
3558
4358
|
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3559
4359
|
pre.style.fontSize = "13px";
|
|
3560
4360
|
pre.style.color = "#1e293b";
|
|
@@ -3566,10 +4366,12 @@ var CodePlugin = class {
|
|
|
3566
4366
|
pre.style.minHeight = "1056px";
|
|
3567
4367
|
pre.style.padding = "72px 56px";
|
|
3568
4368
|
pre.style.boxSizing = "border-box";
|
|
3569
|
-
pre.style.boxShadow = "0 4px
|
|
4369
|
+
pre.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
3570
4370
|
pre.style.borderRadius = "4px";
|
|
3571
4371
|
pre.style.transformOrigin = "top center";
|
|
4372
|
+
pre.style.transition = "transform 0.15s ease";
|
|
3572
4373
|
} else {
|
|
4374
|
+
container.style.overflow = "auto";
|
|
3573
4375
|
container.style.backgroundColor = "#1e1e1e";
|
|
3574
4376
|
container.style.color = "#d4d4d4";
|
|
3575
4377
|
container.style.padding = "16px";
|
|
@@ -3601,42 +4403,9 @@ var CodePlugin = class {
|
|
|
3601
4403
|
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
3602
4404
|
pre.appendChild(code);
|
|
3603
4405
|
container.appendChild(pre);
|
|
3604
|
-
let indicator = null;
|
|
3605
|
-
if (totalPages > 1) {
|
|
3606
|
-
indicator = document.createElement("div");
|
|
3607
|
-
indicator.className = "fp-code-page-indicator";
|
|
3608
|
-
indicator.style.position = "sticky";
|
|
3609
|
-
indicator.style.bottom = "16px";
|
|
3610
|
-
if (isTxt) {
|
|
3611
|
-
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3612
|
-
indicator.style.color = "#334155";
|
|
3613
|
-
indicator.style.border = "1px solid #e2e8f0";
|
|
3614
|
-
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3615
|
-
} else {
|
|
3616
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3617
|
-
indicator.style.color = "#f8fafc";
|
|
3618
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3619
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3620
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
3621
|
-
}
|
|
3622
|
-
indicator.style.fontSize = "12px";
|
|
3623
|
-
indicator.style.fontWeight = "600";
|
|
3624
|
-
indicator.style.padding = "5px 14px";
|
|
3625
|
-
indicator.style.borderRadius = "20px";
|
|
3626
|
-
indicator.style.zIndex = "10";
|
|
3627
|
-
indicator.style.userSelect = "none";
|
|
3628
|
-
indicator.style.pointerEvents = "none";
|
|
3629
|
-
indicator.style.textAlign = "center";
|
|
3630
|
-
indicator.style.width = "fit-content";
|
|
3631
|
-
indicator.style.margin = "16px auto 0";
|
|
3632
|
-
container.appendChild(indicator);
|
|
3633
|
-
}
|
|
3634
4406
|
const showPage = (pageNum) => {
|
|
3635
4407
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3636
4408
|
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
3637
|
-
if (indicator) {
|
|
3638
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3639
|
-
}
|
|
3640
4409
|
container.scrollTop = 0;
|
|
3641
4410
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3642
4411
|
};
|
|
@@ -3644,36 +4413,90 @@ var CodePlugin = class {
|
|
|
3644
4413
|
showPage(1);
|
|
3645
4414
|
}
|
|
3646
4415
|
ctx.container.appendChild(container);
|
|
3647
|
-
const
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
ctx.container.innerHTML = "";
|
|
4416
|
+
const calculateTxtFit = () => {
|
|
4417
|
+
const availW = Math.max(280, container.clientWidth - 32);
|
|
4418
|
+
return Math.max(0.4, Math.min(3, availW / 816));
|
|
3651
4419
|
};
|
|
3652
|
-
ctx.signal.addEventListener("abort", cleanup);
|
|
3653
4420
|
const updateTransform = () => {
|
|
3654
4421
|
if (isTxt) {
|
|
3655
4422
|
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
4423
|
+
const scaledH = 1056 * zoomLevel;
|
|
4424
|
+
const extraH = Math.max(0, scaledH - 1056);
|
|
4425
|
+
pre.style.marginBottom = `${extraH + 32}px`;
|
|
3656
4426
|
} else {
|
|
3657
4427
|
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3658
4428
|
pre.style.fontSize = `${fontSize}px`;
|
|
3659
4429
|
}
|
|
3660
4430
|
};
|
|
4431
|
+
let resizeObserver = null;
|
|
4432
|
+
if (isTxt) {
|
|
4433
|
+
setTimeout(() => {
|
|
4434
|
+
zoomLevel = calculateTxtFit();
|
|
4435
|
+
updateTransform();
|
|
4436
|
+
}, 60);
|
|
4437
|
+
resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
4438
|
+
if (!isUserZoomed) {
|
|
4439
|
+
zoomLevel = calculateTxtFit();
|
|
4440
|
+
updateTransform();
|
|
4441
|
+
}
|
|
4442
|
+
}) : null;
|
|
4443
|
+
resizeObserver?.observe(container);
|
|
4444
|
+
}
|
|
4445
|
+
const cleanup = () => {
|
|
4446
|
+
resizeObserver?.disconnect();
|
|
4447
|
+
container.remove();
|
|
4448
|
+
ctx.container.innerHTML = "";
|
|
4449
|
+
};
|
|
4450
|
+
ctx.signal.addEventListener("abort", cleanup);
|
|
3661
4451
|
return {
|
|
3662
4452
|
destroy: cleanup,
|
|
3663
4453
|
getPageCount: () => totalPages,
|
|
3664
4454
|
getCurrentPage: () => currentPage,
|
|
3665
4455
|
goToPage: (page) => showPage(page),
|
|
4456
|
+
getThumbnails: () => {
|
|
4457
|
+
return rawPages.map((pageText, idx) => ({
|
|
4458
|
+
index: idx,
|
|
4459
|
+
label: `Page ${idx + 1}`,
|
|
4460
|
+
render: async (canvas) => {
|
|
4461
|
+
canvas.width = 140;
|
|
4462
|
+
canvas.height = 180;
|
|
4463
|
+
const c = canvas.getContext("2d");
|
|
4464
|
+
if (!c) return;
|
|
4465
|
+
c.fillStyle = "#ffffff";
|
|
4466
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4467
|
+
c.strokeStyle = "#cbd5e1";
|
|
4468
|
+
c.lineWidth = 1;
|
|
4469
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4470
|
+
c.fillStyle = "#64748b";
|
|
4471
|
+
const lines = (pageText || "").split("\n").slice(0, 24);
|
|
4472
|
+
const lineH = 6;
|
|
4473
|
+
const startY = 14;
|
|
4474
|
+
const startX = 12;
|
|
4475
|
+
const maxW = canvas.width - 24;
|
|
4476
|
+
c.font = "5px monospace";
|
|
4477
|
+
for (let li = 0; li < lines.length; li++) {
|
|
4478
|
+
const l = lines[li].trim();
|
|
4479
|
+
if (!l) continue;
|
|
4480
|
+
const y = startY + li * lineH;
|
|
4481
|
+
if (y > canvas.height - 12) break;
|
|
4482
|
+
c.fillText(l.slice(0, 30), startX, y, maxW);
|
|
4483
|
+
}
|
|
4484
|
+
}
|
|
4485
|
+
}));
|
|
4486
|
+
},
|
|
3666
4487
|
zoomIn: () => {
|
|
4488
|
+
isUserZoomed = true;
|
|
3667
4489
|
if (isTxt) {
|
|
3668
|
-
zoomLevel = Math.min(3, zoomLevel + 0.
|
|
4490
|
+
zoomLevel = Math.min(3.5, zoomLevel + 0.15);
|
|
3669
4491
|
} else {
|
|
3670
4492
|
fontSize = Math.min(32, fontSize + 2);
|
|
3671
4493
|
}
|
|
3672
4494
|
updateTransform();
|
|
3673
4495
|
},
|
|
3674
4496
|
zoomOut: () => {
|
|
4497
|
+
isUserZoomed = true;
|
|
3675
4498
|
if (isTxt) {
|
|
3676
|
-
zoomLevel = Math.max(0.1, zoomLevel - 0.
|
|
4499
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.15);
|
|
3677
4500
|
} else {
|
|
3678
4501
|
fontSize = Math.max(8, fontSize - 2);
|
|
3679
4502
|
}
|
|
@@ -3681,6 +4504,7 @@ var CodePlugin = class {
|
|
|
3681
4504
|
},
|
|
3682
4505
|
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
3683
4506
|
setZoom: (level) => {
|
|
4507
|
+
isUserZoomed = true;
|
|
3684
4508
|
if (isTxt) {
|
|
3685
4509
|
zoomLevel = level;
|
|
3686
4510
|
} else {
|
|
@@ -3689,9 +4513,10 @@ var CodePlugin = class {
|
|
|
3689
4513
|
updateTransform();
|
|
3690
4514
|
},
|
|
3691
4515
|
fitToPage: () => {
|
|
4516
|
+
isUserZoomed = false;
|
|
3692
4517
|
fontSize = 13;
|
|
3693
4518
|
rotation = 0;
|
|
3694
|
-
zoomLevel = isTxt ?
|
|
4519
|
+
zoomLevel = isTxt ? calculateTxtFit() : 1;
|
|
3695
4520
|
updateTransform();
|
|
3696
4521
|
},
|
|
3697
4522
|
rotateCW: () => {
|
|
@@ -4572,28 +5397,26 @@ var RtfPlugin = class {
|
|
|
4572
5397
|
getToolbarActions(instance) {
|
|
4573
5398
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4574
5399
|
const actions = [];
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
if (
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
instance.goToPage?.(page);
|
|
4593
|
-
}
|
|
5400
|
+
actions.push({
|
|
5401
|
+
id: "page-nav",
|
|
5402
|
+
icon: "",
|
|
5403
|
+
label: "Page Navigation",
|
|
5404
|
+
type: "page-nav",
|
|
5405
|
+
group: "navigation",
|
|
5406
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5407
|
+
max: totalPages,
|
|
5408
|
+
execute: (action, page) => {
|
|
5409
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5410
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5411
|
+
if (action === "prev") {
|
|
5412
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5413
|
+
} else if (action === "next") {
|
|
5414
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5415
|
+
} else if (typeof page === "number") {
|
|
5416
|
+
instance.goToPage?.(page);
|
|
4594
5417
|
}
|
|
4595
|
-
}
|
|
4596
|
-
}
|
|
5418
|
+
}
|
|
5419
|
+
});
|
|
4597
5420
|
actions.push(
|
|
4598
5421
|
{
|
|
4599
5422
|
id: "zoom-out",
|
|
@@ -4665,43 +5488,57 @@ var RtfPlugin = class {
|
|
|
4665
5488
|
async render(ctx) {
|
|
4666
5489
|
const wrapper = document.createElement("div");
|
|
4667
5490
|
wrapper.className = "fp-rtf-wrapper";
|
|
4668
|
-
wrapper.style.padding = "
|
|
4669
|
-
wrapper.style.
|
|
5491
|
+
wrapper.style.padding = "0";
|
|
5492
|
+
wrapper.style.width = "816px";
|
|
4670
5493
|
wrapper.style.margin = "0 auto";
|
|
4671
|
-
wrapper.style.
|
|
4672
|
-
wrapper.style.
|
|
4673
|
-
wrapper.style.
|
|
4674
|
-
wrapper.style.
|
|
5494
|
+
wrapper.style.boxSizing = "border-box";
|
|
5495
|
+
wrapper.style.display = "flex";
|
|
5496
|
+
wrapper.style.flexDirection = "column";
|
|
5497
|
+
wrapper.style.alignItems = "center";
|
|
5498
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4675
5499
|
wrapper.style.transformOrigin = "top center";
|
|
4676
|
-
wrapper.style.transition = "transform 0.
|
|
4677
|
-
ctx.container.style.
|
|
4678
|
-
ctx.container.style.
|
|
5500
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5501
|
+
ctx.container.style.overflowX = "hidden";
|
|
5502
|
+
ctx.container.style.overflowY = "auto";
|
|
5503
|
+
ctx.container.style.padding = "16px 8px";
|
|
4679
5504
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
4680
5505
|
ctx.container.appendChild(wrapper);
|
|
4681
5506
|
let scale = 1;
|
|
4682
5507
|
let rotation = 0;
|
|
4683
5508
|
let pageElements = [];
|
|
4684
|
-
let
|
|
5509
|
+
let isUserZoomed = false;
|
|
5510
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
4685
5511
|
const calculateFitScale = (mode = fitMode) => {
|
|
4686
5512
|
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4687
|
-
const elW =
|
|
4688
|
-
const singlePageH =
|
|
4689
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
4690
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
5513
|
+
const elW = 816;
|
|
5514
|
+
const singlePageH = activeEl?.offsetHeight || 1056;
|
|
5515
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
5516
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
4691
5517
|
const sW = availW / elW;
|
|
4692
5518
|
const sH = availH / singlePageH;
|
|
4693
5519
|
if (mode === "page") {
|
|
4694
|
-
return Math.max(0.
|
|
5520
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
4695
5521
|
}
|
|
4696
|
-
return Math.max(0.
|
|
5522
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
4697
5523
|
};
|
|
4698
5524
|
const applyTransform = () => {
|
|
4699
5525
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4700
5526
|
wrapper.style.transformOrigin = "top center";
|
|
5527
|
+
const activeEl = pageElements[currentPage - 1];
|
|
5528
|
+
const baseH = activeEl?.offsetHeight || 1056;
|
|
5529
|
+
const scaledH = baseH * scale;
|
|
5530
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
5531
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
4701
5532
|
};
|
|
5533
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
5534
|
+
if (!isUserZoomed) {
|
|
5535
|
+
scale = calculateFitScale(fitMode);
|
|
5536
|
+
applyTransform();
|
|
5537
|
+
}
|
|
5538
|
+
}) : null;
|
|
5539
|
+
resizeObserver?.observe(ctx.container);
|
|
4702
5540
|
setTimeout(() => {
|
|
4703
|
-
|
|
4704
|
-
scale = calculateFitScale("width");
|
|
5541
|
+
scale = calculateFitScale(fitMode);
|
|
4705
5542
|
applyTransform();
|
|
4706
5543
|
}, 60);
|
|
4707
5544
|
try {
|
|
@@ -4711,20 +5548,34 @@ var RtfPlugin = class {
|
|
|
4711
5548
|
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
4712
5549
|
const htmlElements = await doc.render();
|
|
4713
5550
|
const contentNodes = [];
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
5551
|
+
const extractBlocks = (nodes) => {
|
|
5552
|
+
for (const item of nodes) {
|
|
5553
|
+
if (!item || !(item instanceof HTMLElement)) continue;
|
|
5554
|
+
const tag = item.tagName.toLowerCase();
|
|
5555
|
+
const hasChildBlocks = Array.from(item.children).some((c) => {
|
|
5556
|
+
const ct = c.tagName.toLowerCase();
|
|
5557
|
+
return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
|
|
5558
|
+
});
|
|
5559
|
+
if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
|
|
5560
|
+
extractBlocks(Array.from(item.children));
|
|
5561
|
+
} else {
|
|
5562
|
+
if (tag === "p" || tag === "div") {
|
|
5563
|
+
item.style.display = "block";
|
|
5564
|
+
item.style.marginBottom = "12px";
|
|
5565
|
+
item.style.lineHeight = "1.6";
|
|
5566
|
+
}
|
|
5567
|
+
contentNodes.push(item);
|
|
5568
|
+
}
|
|
4719
5569
|
}
|
|
4720
|
-
}
|
|
5570
|
+
};
|
|
5571
|
+
extractBlocks(htmlElements);
|
|
4721
5572
|
wrapper.innerHTML = "";
|
|
4722
5573
|
contentNodes.forEach((node) => wrapper.appendChild(node));
|
|
4723
5574
|
const childHeights = contentNodes.map((c) => {
|
|
4724
5575
|
const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
|
|
4725
5576
|
const offH = c.offsetHeight || 0;
|
|
4726
5577
|
const textLen = c.textContent?.trim().length || 0;
|
|
4727
|
-
const estH = Math.max(
|
|
5578
|
+
const estH = Math.max(28, Math.ceil(textLen / 75) * 24 + 16);
|
|
4728
5579
|
return Math.max(rectH, offH, estH);
|
|
4729
5580
|
});
|
|
4730
5581
|
wrapper.innerHTML = "";
|
|
@@ -4741,6 +5592,7 @@ var RtfPlugin = class {
|
|
|
4741
5592
|
card.style.marginBottom = "24px";
|
|
4742
5593
|
card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4743
5594
|
card.style.lineHeight = "1.6";
|
|
5595
|
+
card.style.color = "#1e293b";
|
|
4744
5596
|
return card;
|
|
4745
5597
|
};
|
|
4746
5598
|
let curCard = createRtfCard();
|
|
@@ -4776,9 +5628,8 @@ var RtfPlugin = class {
|
|
|
4776
5628
|
pageCard.style.padding = "72px 56px";
|
|
4777
5629
|
pageCard.style.width = "816px";
|
|
4778
5630
|
pageCard.style.minHeight = "1056px";
|
|
4779
|
-
pageCard.style.maxWidth = "100%";
|
|
4780
5631
|
pageCard.style.boxSizing = "border-box";
|
|
4781
|
-
pageCard.style.fontFamily = "serif
|
|
5632
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4782
5633
|
pageCard.style.fontSize = "12pt";
|
|
4783
5634
|
pageCard.style.lineHeight = "1.6";
|
|
4784
5635
|
pageCard.style.color = "#1e293b";
|
|
@@ -4791,29 +5642,6 @@ var RtfPlugin = class {
|
|
|
4791
5642
|
}
|
|
4792
5643
|
const totalPages = Math.max(1, pageElements.length);
|
|
4793
5644
|
let currentPage = 1;
|
|
4794
|
-
let indicator = null;
|
|
4795
|
-
if (totalPages > 1) {
|
|
4796
|
-
indicator = document.createElement("div");
|
|
4797
|
-
indicator.className = "fp-rtf-page-indicator";
|
|
4798
|
-
indicator.style.position = "sticky";
|
|
4799
|
-
indicator.style.bottom = "16px";
|
|
4800
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4801
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
4802
|
-
indicator.style.color = "#f8fafc";
|
|
4803
|
-
indicator.style.fontSize = "12px";
|
|
4804
|
-
indicator.style.fontWeight = "600";
|
|
4805
|
-
indicator.style.padding = "5px 14px";
|
|
4806
|
-
indicator.style.borderRadius = "20px";
|
|
4807
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4808
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4809
|
-
indicator.style.zIndex = "10";
|
|
4810
|
-
indicator.style.userSelect = "none";
|
|
4811
|
-
indicator.style.pointerEvents = "none";
|
|
4812
|
-
indicator.style.textAlign = "center";
|
|
4813
|
-
indicator.style.width = "fit-content";
|
|
4814
|
-
indicator.style.margin = "16px auto 0";
|
|
4815
|
-
ctx.container.appendChild(indicator);
|
|
4816
|
-
}
|
|
4817
5645
|
const showPage = (pageNum) => {
|
|
4818
5646
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4819
5647
|
if (totalPages > 1) {
|
|
@@ -4821,9 +5649,6 @@ var RtfPlugin = class {
|
|
|
4821
5649
|
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4822
5650
|
});
|
|
4823
5651
|
}
|
|
4824
|
-
if (indicator) {
|
|
4825
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4826
|
-
}
|
|
4827
5652
|
ctx.container.scrollTop = 0;
|
|
4828
5653
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4829
5654
|
};
|
|
@@ -4831,7 +5656,7 @@ var RtfPlugin = class {
|
|
|
4831
5656
|
showPage(1);
|
|
4832
5657
|
}
|
|
4833
5658
|
const cleanup = () => {
|
|
4834
|
-
|
|
5659
|
+
resizeObserver?.disconnect();
|
|
4835
5660
|
wrapper.remove();
|
|
4836
5661
|
ctx.container.innerHTML = "";
|
|
4837
5662
|
};
|
|
@@ -4842,21 +5667,25 @@ var RtfPlugin = class {
|
|
|
4842
5667
|
getCurrentPage: () => currentPage,
|
|
4843
5668
|
goToPage: (page) => showPage(page),
|
|
4844
5669
|
zoomIn: () => {
|
|
5670
|
+
isUserZoomed = true;
|
|
4845
5671
|
scale += 0.15;
|
|
4846
5672
|
applyTransform();
|
|
4847
5673
|
},
|
|
4848
5674
|
zoomOut: () => {
|
|
5675
|
+
isUserZoomed = true;
|
|
4849
5676
|
scale = Math.max(0.2, scale - 0.15);
|
|
4850
5677
|
applyTransform();
|
|
4851
5678
|
},
|
|
4852
5679
|
getZoom: () => scale,
|
|
4853
5680
|
setZoom: (level) => {
|
|
5681
|
+
isUserZoomed = true;
|
|
4854
5682
|
scale = level;
|
|
4855
5683
|
applyTransform();
|
|
4856
5684
|
},
|
|
4857
5685
|
fitToPage: () => {
|
|
4858
|
-
|
|
4859
|
-
|
|
5686
|
+
isUserZoomed = false;
|
|
5687
|
+
fitMode = "width";
|
|
5688
|
+
scale = calculateFitScale("width");
|
|
4860
5689
|
rotation = 0;
|
|
4861
5690
|
applyTransform();
|
|
4862
5691
|
},
|
|
@@ -5044,40 +5873,36 @@ var OpenDocumentPlugin = class {
|
|
|
5044
5873
|
const isPresentation = instance.isPresentation;
|
|
5045
5874
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5046
5875
|
const actions = [];
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
max
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
if (
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
instance.goToPage?.(page);
|
|
5075
|
-
} else if (typeof action === "number") {
|
|
5076
|
-
instance.goToPage?.(action);
|
|
5077
|
-
}
|
|
5876
|
+
actions.push({
|
|
5877
|
+
id: "thumbnails",
|
|
5878
|
+
icon: "thumbnails",
|
|
5879
|
+
label: isPresentation ? "Slide Thumbnails" : "Page Thumbnails",
|
|
5880
|
+
type: "button",
|
|
5881
|
+
group: "navigation",
|
|
5882
|
+
execute: () => instance.toggleThumbnails?.()
|
|
5883
|
+
});
|
|
5884
|
+
actions.push({
|
|
5885
|
+
id: "page-nav",
|
|
5886
|
+
icon: "",
|
|
5887
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
5888
|
+
type: "page-nav",
|
|
5889
|
+
group: "navigation",
|
|
5890
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5891
|
+
max: totalPages,
|
|
5892
|
+
execute: (action, page) => {
|
|
5893
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5894
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5895
|
+
if (action === "prev") {
|
|
5896
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5897
|
+
} else if (action === "next") {
|
|
5898
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5899
|
+
} else if (typeof page === "number") {
|
|
5900
|
+
instance.goToPage?.(page);
|
|
5901
|
+
} else if (typeof action === "number") {
|
|
5902
|
+
instance.goToPage?.(action);
|
|
5078
5903
|
}
|
|
5079
|
-
}
|
|
5080
|
-
}
|
|
5904
|
+
}
|
|
5905
|
+
});
|
|
5081
5906
|
actions.push(
|
|
5082
5907
|
{
|
|
5083
5908
|
id: "zoom-out",
|
|
@@ -5168,49 +5993,65 @@ var OpenDocumentPlugin = class {
|
|
|
5168
5993
|
container.className = "fp-odf-container";
|
|
5169
5994
|
container.style.width = "100%";
|
|
5170
5995
|
container.style.height = "100%";
|
|
5171
|
-
container.style.
|
|
5172
|
-
container.style.
|
|
5996
|
+
container.style.overflowX = "hidden";
|
|
5997
|
+
container.style.overflowY = "auto";
|
|
5998
|
+
container.style.padding = "16px 8px";
|
|
5173
5999
|
container.style.backgroundColor = "#f1f5f9";
|
|
5174
6000
|
const wrapper = document.createElement("div");
|
|
5175
6001
|
wrapper.className = "fp-odf-wrapper";
|
|
5176
6002
|
wrapper.style.margin = "0 auto";
|
|
6003
|
+
wrapper.style.width = isPresentation ? "960px" : "816px";
|
|
6004
|
+
wrapper.style.boxSizing = "border-box";
|
|
5177
6005
|
wrapper.style.backgroundColor = "#ffffff";
|
|
5178
6006
|
wrapper.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
5179
6007
|
wrapper.style.borderRadius = "4px";
|
|
5180
6008
|
wrapper.style.transformOrigin = "top center";
|
|
5181
|
-
wrapper.style.transition = "transform 0.
|
|
6009
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5182
6010
|
container.appendChild(wrapper);
|
|
5183
6011
|
ctx.container.appendChild(container);
|
|
5184
6012
|
let scale = 1;
|
|
5185
6013
|
let rotation = 0;
|
|
5186
|
-
let
|
|
6014
|
+
let isUserZoomed = false;
|
|
6015
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6016
|
+
let currentPage = 1;
|
|
6017
|
+
let totalPages = 1;
|
|
6018
|
+
let slides = [];
|
|
5187
6019
|
const calculateFitScale = (mode = fitMode) => {
|
|
5188
|
-
const
|
|
5189
|
-
const
|
|
5190
|
-
const
|
|
5191
|
-
const
|
|
6020
|
+
const activeSlide = slides[currentPage - 1];
|
|
6021
|
+
const elW = isPresentation ? 960 : 816;
|
|
6022
|
+
const singlePageH = Math.min(activeSlide?.offsetHeight || wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
6023
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6024
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5192
6025
|
const sW = availW / elW;
|
|
5193
6026
|
const sH = availH / (isPresentation ? 540 : singlePageH);
|
|
5194
6027
|
if (isPresentation) {
|
|
5195
|
-
return Math.min(
|
|
6028
|
+
return Math.min(2.5, Math.min(sW, sH));
|
|
5196
6029
|
}
|
|
5197
6030
|
if (mode === "page") {
|
|
5198
|
-
return Math.max(0.
|
|
6031
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5199
6032
|
}
|
|
5200
|
-
return Math.max(0.
|
|
6033
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5201
6034
|
};
|
|
5202
6035
|
const applyTransform = () => {
|
|
5203
6036
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5204
6037
|
wrapper.style.transformOrigin = "top center";
|
|
6038
|
+
const activeSlide = slides[currentPage - 1];
|
|
6039
|
+
const baseH = activeSlide?.offsetHeight || wrapper.offsetHeight || 1056;
|
|
6040
|
+
const scaledH = baseH * scale;
|
|
6041
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6042
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
5205
6043
|
};
|
|
6044
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6045
|
+
if (!isUserZoomed) {
|
|
6046
|
+
scale = calculateFitScale(fitMode);
|
|
6047
|
+
applyTransform();
|
|
6048
|
+
}
|
|
6049
|
+
}) : null;
|
|
6050
|
+
resizeObserver?.observe(ctx.container);
|
|
5206
6051
|
setTimeout(() => {
|
|
5207
|
-
|
|
5208
|
-
scale = calculateFitScale("width");
|
|
6052
|
+
scale = calculateFitScale(fitMode);
|
|
5209
6053
|
applyTransform();
|
|
5210
6054
|
}, 60);
|
|
5211
|
-
let currentPage = 1;
|
|
5212
|
-
let totalPages = 1;
|
|
5213
|
-
let slides = [];
|
|
5214
6055
|
if (isPresentation) {
|
|
5215
6056
|
wrapper.style.maxWidth = "960px";
|
|
5216
6057
|
wrapper.style.aspectRatio = "16 / 9";
|
|
@@ -5311,24 +6152,9 @@ var OpenDocumentPlugin = class {
|
|
|
5311
6152
|
wrapper.appendChild(page);
|
|
5312
6153
|
slides.push(page);
|
|
5313
6154
|
});
|
|
5314
|
-
const pageIndicator = document.createElement("div");
|
|
5315
|
-
pageIndicator.className = "fp-odt-page-indicator";
|
|
5316
|
-
pageIndicator.style.position = "sticky";
|
|
5317
|
-
pageIndicator.style.bottom = "16px";
|
|
5318
|
-
pageIndicator.style.left = "50%";
|
|
5319
|
-
pageIndicator.style.transform = "translateX(-50%)";
|
|
5320
|
-
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
5321
|
-
pageIndicator.style.color = "#fff";
|
|
5322
|
-
pageIndicator.style.padding = "6px 12px";
|
|
5323
|
-
pageIndicator.style.borderRadius = "16px";
|
|
5324
|
-
pageIndicator.style.fontSize = "12px";
|
|
5325
|
-
pageIndicator.style.zIndex = "100";
|
|
5326
|
-
pageIndicator.style.display = "inline-block";
|
|
5327
|
-
pageIndicator.style.width = "fit-content";
|
|
5328
|
-
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
5329
|
-
container.appendChild(pageIndicator);
|
|
5330
6155
|
}
|
|
5331
6156
|
const cleanup = () => {
|
|
6157
|
+
resizeObserver?.disconnect();
|
|
5332
6158
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
5333
6159
|
container.remove();
|
|
5334
6160
|
ctx.container.innerHTML = "";
|
|
@@ -5340,10 +6166,6 @@ var OpenDocumentPlugin = class {
|
|
|
5340
6166
|
slides.forEach((s, idx) => {
|
|
5341
6167
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
5342
6168
|
});
|
|
5343
|
-
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
5344
|
-
if (indicator) {
|
|
5345
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5346
|
-
}
|
|
5347
6169
|
container.scrollTop = 0;
|
|
5348
6170
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5349
6171
|
};
|
|
@@ -5351,21 +6173,25 @@ var OpenDocumentPlugin = class {
|
|
|
5351
6173
|
destroy: cleanup,
|
|
5352
6174
|
isPresentation,
|
|
5353
6175
|
zoomIn: () => {
|
|
6176
|
+
isUserZoomed = true;
|
|
5354
6177
|
scale += 0.15;
|
|
5355
6178
|
applyTransform();
|
|
5356
6179
|
},
|
|
5357
6180
|
zoomOut: () => {
|
|
6181
|
+
isUserZoomed = true;
|
|
5358
6182
|
scale = Math.max(0.2, scale - 0.15);
|
|
5359
6183
|
applyTransform();
|
|
5360
6184
|
},
|
|
5361
6185
|
getZoom: () => scale,
|
|
5362
6186
|
setZoom: (level) => {
|
|
6187
|
+
isUserZoomed = true;
|
|
5363
6188
|
scale = level;
|
|
5364
6189
|
applyTransform();
|
|
5365
6190
|
},
|
|
5366
6191
|
fitToPage: () => {
|
|
5367
|
-
|
|
5368
|
-
|
|
6192
|
+
isUserZoomed = false;
|
|
6193
|
+
fitMode = "width";
|
|
6194
|
+
scale = calculateFitScale("width");
|
|
5369
6195
|
rotation = 0;
|
|
5370
6196
|
applyTransform();
|
|
5371
6197
|
},
|
|
@@ -5381,23 +6207,45 @@ var OpenDocumentPlugin = class {
|
|
|
5381
6207
|
getPageCount: () => totalPages,
|
|
5382
6208
|
getCurrentPage: () => currentPage,
|
|
5383
6209
|
getThumbnails: async () => {
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
canvas
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
6210
|
+
const count = totalPages || slides.length || 1;
|
|
6211
|
+
const items = [];
|
|
6212
|
+
for (let idx = 0; idx < count; idx++) {
|
|
6213
|
+
const itemIdx = idx;
|
|
6214
|
+
items.push({
|
|
6215
|
+
index: itemIdx,
|
|
6216
|
+
label: isPresentation ? `Slide ${itemIdx + 1}` : `Page ${itemIdx + 1}`,
|
|
6217
|
+
render: async (canvas) => {
|
|
6218
|
+
const ctx2d = canvas.getContext("2d");
|
|
6219
|
+
if (!ctx2d) return;
|
|
6220
|
+
if (isPresentation) {
|
|
6221
|
+
canvas.width = 160;
|
|
6222
|
+
canvas.height = 90;
|
|
6223
|
+
ctx2d.fillStyle = "#f8fafc";
|
|
6224
|
+
ctx2d.fillRect(0, 0, 160, 90);
|
|
6225
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6226
|
+
ctx2d.lineWidth = 1;
|
|
6227
|
+
ctx2d.strokeRect(0.5, 0.5, 159, 89);
|
|
6228
|
+
ctx2d.fillStyle = "#334155";
|
|
6229
|
+
ctx2d.font = "bold 11px sans-serif";
|
|
6230
|
+
ctx2d.textAlign = "center";
|
|
6231
|
+
ctx2d.fillText(`Slide ${itemIdx + 1}`, 80, 50);
|
|
6232
|
+
} else {
|
|
6233
|
+
canvas.width = 140;
|
|
6234
|
+
canvas.height = 180;
|
|
6235
|
+
ctx2d.fillStyle = "#ffffff";
|
|
6236
|
+
ctx2d.fillRect(0, 0, 140, 180);
|
|
6237
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6238
|
+
ctx2d.lineWidth = 1;
|
|
6239
|
+
ctx2d.strokeRect(0.5, 0.5, 139, 179);
|
|
6240
|
+
ctx2d.fillStyle = "#64748b";
|
|
6241
|
+
ctx2d.font = "bold 10px sans-serif";
|
|
6242
|
+
ctx2d.textAlign = "center";
|
|
6243
|
+
ctx2d.fillText(`Page ${itemIdx + 1}`, 70, 90);
|
|
6244
|
+
}
|
|
6245
|
+
}
|
|
6246
|
+
});
|
|
6247
|
+
}
|
|
6248
|
+
return items;
|
|
5401
6249
|
},
|
|
5402
6250
|
download: () => {
|
|
5403
6251
|
const mimeType = this.mimeTypes.find((m) => m.includes(ext.replace(".", ""))) || "application/octet-stream";
|
|
@@ -5502,23 +6350,24 @@ var OpenDocumentPlugin = class {
|
|
|
5502
6350
|
case "h": {
|
|
5503
6351
|
const level = Math.min(6, Math.max(1, Number(node.getAttribute("text:outline-level") || 1)));
|
|
5504
6352
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5505
|
-
html += `<h${level} style="${style}; font-family:
|
|
6353
|
+
html += `<h${level} style="${style}; margin: 18px 0 8px; color: #1e3a8a; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${node.textContent || ""}</h${level}>`;
|
|
5506
6354
|
break;
|
|
5507
6355
|
}
|
|
5508
6356
|
case "p": {
|
|
5509
6357
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5510
6358
|
const inner = this.renderSpans(node, styles, images);
|
|
5511
|
-
|
|
6359
|
+
const isInsideLi = node.parentElement?.localName === "list-item" || node.parentElement?.tagName?.toLowerCase() === "list-item";
|
|
6360
|
+
html += `<p style="${style}; line-height: 1.5; margin: ${isInsideLi ? "0" : "8px 0 12px"}; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${inner}</p>`;
|
|
5512
6361
|
break;
|
|
5513
6362
|
}
|
|
5514
6363
|
case "list": {
|
|
5515
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
6364
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
5516
6365
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5517
6366
|
html += "</ul>";
|
|
5518
6367
|
break;
|
|
5519
6368
|
}
|
|
5520
6369
|
case "list-item": {
|
|
5521
|
-
html +=
|
|
6370
|
+
html += '<li style="margin: 4px 0; font-size: 11pt; line-height: 1.5; color: #1e293b;">';
|
|
5522
6371
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5523
6372
|
html += "</li>";
|
|
5524
6373
|
break;
|
|
@@ -5644,28 +6493,26 @@ var DocPlugin = class {
|
|
|
5644
6493
|
getToolbarActions(instance) {
|
|
5645
6494
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5646
6495
|
const actions = [];
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
if (
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
instance.goToPage?.(page);
|
|
5665
|
-
}
|
|
6496
|
+
actions.push({
|
|
6497
|
+
id: "page-nav",
|
|
6498
|
+
icon: "",
|
|
6499
|
+
label: "Page Navigation",
|
|
6500
|
+
type: "page-nav",
|
|
6501
|
+
group: "navigation",
|
|
6502
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
6503
|
+
max: totalPages,
|
|
6504
|
+
execute: (action, page) => {
|
|
6505
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
6506
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
6507
|
+
if (action === "prev") {
|
|
6508
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
6509
|
+
} else if (action === "next") {
|
|
6510
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
6511
|
+
} else if (typeof page === "number") {
|
|
6512
|
+
instance.goToPage?.(page);
|
|
5666
6513
|
}
|
|
5667
|
-
}
|
|
5668
|
-
}
|
|
6514
|
+
}
|
|
6515
|
+
});
|
|
5669
6516
|
actions.push(
|
|
5670
6517
|
{
|
|
5671
6518
|
id: "zoom-out",
|
|
@@ -5739,8 +6586,9 @@ var DocPlugin = class {
|
|
|
5739
6586
|
container.className = "fp-doc-container";
|
|
5740
6587
|
container.style.width = "100%";
|
|
5741
6588
|
container.style.height = "100%";
|
|
5742
|
-
container.style.
|
|
5743
|
-
container.style.
|
|
6589
|
+
container.style.overflowX = "hidden";
|
|
6590
|
+
container.style.overflowY = "auto";
|
|
6591
|
+
container.style.padding = "16px 8px";
|
|
5744
6592
|
container.style.backgroundColor = "#f1f5f9";
|
|
5745
6593
|
container.style.display = "flex";
|
|
5746
6594
|
container.style.justifyContent = "center";
|
|
@@ -5749,8 +6597,17 @@ var DocPlugin = class {
|
|
|
5749
6597
|
let scale = 1;
|
|
5750
6598
|
let extractedRawText = "";
|
|
5751
6599
|
let isFallback = false;
|
|
6600
|
+
let chartSvg = "";
|
|
5752
6601
|
try {
|
|
5753
6602
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
6603
|
+
try {
|
|
6604
|
+
const pkg = cfbf.readStream("package_stream");
|
|
6605
|
+
if (pkg && pkg.length > 100) {
|
|
6606
|
+
chartSvg = this.parseOdfChartToSvg(pkg);
|
|
6607
|
+
}
|
|
6608
|
+
} catch (chartErr) {
|
|
6609
|
+
console.warn("[DocPlugin] Chart stream parsing info:", chartErr);
|
|
6610
|
+
}
|
|
5754
6611
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
5755
6612
|
if (!wordDocStream || wordDocStream.length < 512) {
|
|
5756
6613
|
throw new Error("WordDocument stream not found or invalid in CFBF archive");
|
|
@@ -5768,7 +6625,7 @@ var DocPlugin = class {
|
|
|
5768
6625
|
extractedRawText = fallback;
|
|
5769
6626
|
isFallback = true;
|
|
5770
6627
|
}
|
|
5771
|
-
const rawPages = this.splitIntoPages(extractedRawText);
|
|
6628
|
+
const rawPages = this.splitIntoPages(extractedRawText, chartSvg);
|
|
5772
6629
|
const totalPages = Math.max(1, rawPages.length);
|
|
5773
6630
|
let currentPage = 1;
|
|
5774
6631
|
const pageCards = [];
|
|
@@ -5776,16 +6633,15 @@ var DocPlugin = class {
|
|
|
5776
6633
|
const pageCard = document.createElement("div");
|
|
5777
6634
|
pageCard.className = "fp-doc-page-card";
|
|
5778
6635
|
pageCard.style.width = "816px";
|
|
5779
|
-
pageCard.style.
|
|
6636
|
+
pageCard.style.minHeight = "1056px";
|
|
5780
6637
|
pageCard.style.backgroundColor = "#ffffff";
|
|
5781
|
-
pageCard.style.boxShadow = "0
|
|
6638
|
+
pageCard.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
5782
6639
|
pageCard.style.borderRadius = "4px";
|
|
5783
|
-
pageCard.style.padding = "
|
|
6640
|
+
pageCard.style.padding = "72px 56px";
|
|
5784
6641
|
pageCard.style.boxSizing = "border-box";
|
|
5785
|
-
pageCard.style.overflow = "hidden";
|
|
5786
6642
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5787
6643
|
pageCard.style.transformOrigin = "top center";
|
|
5788
|
-
pageCard.style.transition = "transform 0.
|
|
6644
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
5789
6645
|
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5790
6646
|
pageCard.style.color = "#1e293b";
|
|
5791
6647
|
if (isFallback && i === 0) {
|
|
@@ -5802,34 +6658,15 @@ var DocPlugin = class {
|
|
|
5802
6658
|
container.appendChild(pageCard);
|
|
5803
6659
|
pageCards.push(pageCard);
|
|
5804
6660
|
}
|
|
5805
|
-
let indicator = null;
|
|
5806
|
-
if (totalPages > 1) {
|
|
5807
|
-
indicator = document.createElement("div");
|
|
5808
|
-
indicator.className = "fp-doc-page-indicator";
|
|
5809
|
-
indicator.style.position = "fixed";
|
|
5810
|
-
indicator.style.bottom = "16px";
|
|
5811
|
-
indicator.style.left = "50%";
|
|
5812
|
-
indicator.style.transform = "translateX(-50%)";
|
|
5813
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
5814
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
5815
|
-
indicator.style.color = "#f8fafc";
|
|
5816
|
-
indicator.style.fontSize = "12px";
|
|
5817
|
-
indicator.style.fontWeight = "600";
|
|
5818
|
-
indicator.style.padding = "5px 14px";
|
|
5819
|
-
indicator.style.borderRadius = "20px";
|
|
5820
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
5821
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
5822
|
-
indicator.style.zIndex = "10";
|
|
5823
|
-
indicator.style.userSelect = "none";
|
|
5824
|
-
indicator.style.pointerEvents = "none";
|
|
5825
|
-
indicator.style.textAlign = "center";
|
|
5826
|
-
container.appendChild(indicator);
|
|
5827
|
-
}
|
|
5828
6661
|
let rotation = 0;
|
|
5829
6662
|
const applyTransform = () => {
|
|
5830
6663
|
const activeCard = pageCards[currentPage - 1];
|
|
5831
6664
|
if (activeCard) {
|
|
5832
6665
|
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
6666
|
+
const baseH = activeCard.offsetHeight || 1056;
|
|
6667
|
+
const scaledH = baseH * scale;
|
|
6668
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6669
|
+
activeCard.style.marginBottom = `${extraH + 32}px`;
|
|
5833
6670
|
}
|
|
5834
6671
|
};
|
|
5835
6672
|
const showPage = (pageNum) => {
|
|
@@ -5842,35 +6679,39 @@ var DocPlugin = class {
|
|
|
5842
6679
|
card.style.display = "none";
|
|
5843
6680
|
}
|
|
5844
6681
|
});
|
|
5845
|
-
if (indicator) {
|
|
5846
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5847
|
-
}
|
|
5848
6682
|
container.scrollTop = 0;
|
|
5849
6683
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5850
6684
|
};
|
|
5851
6685
|
if (totalPages > 1) {
|
|
5852
6686
|
showPage(1);
|
|
5853
6687
|
}
|
|
5854
|
-
let fitMode = "width";
|
|
6688
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6689
|
+
let isUserZoomed = false;
|
|
5855
6690
|
const calculateFitScale = (mode = fitMode) => {
|
|
5856
6691
|
const elW = 816;
|
|
5857
6692
|
const elH = 1056;
|
|
5858
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
5859
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
6693
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6694
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5860
6695
|
const sW = availW / elW;
|
|
5861
6696
|
const sH = availH / elH;
|
|
5862
6697
|
if (mode === "page") {
|
|
5863
|
-
return Math.max(0.
|
|
6698
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5864
6699
|
}
|
|
5865
|
-
return Math.max(0.
|
|
6700
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5866
6701
|
};
|
|
6702
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6703
|
+
if (!isUserZoomed) {
|
|
6704
|
+
scale = calculateFitScale(fitMode);
|
|
6705
|
+
applyTransform();
|
|
6706
|
+
}
|
|
6707
|
+
}) : null;
|
|
6708
|
+
resizeObserver?.observe(ctx.container);
|
|
5867
6709
|
setTimeout(() => {
|
|
5868
|
-
|
|
5869
|
-
scale = calculateFitScale("width");
|
|
6710
|
+
scale = calculateFitScale(fitMode);
|
|
5870
6711
|
applyTransform();
|
|
5871
6712
|
}, 60);
|
|
5872
6713
|
const cleanup = () => {
|
|
5873
|
-
|
|
6714
|
+
resizeObserver?.disconnect();
|
|
5874
6715
|
container.remove();
|
|
5875
6716
|
ctx.container.innerHTML = "";
|
|
5876
6717
|
};
|
|
@@ -5881,21 +6722,25 @@ var DocPlugin = class {
|
|
|
5881
6722
|
getCurrentPage: () => currentPage,
|
|
5882
6723
|
goToPage: (page) => showPage(page),
|
|
5883
6724
|
zoomIn: () => {
|
|
6725
|
+
isUserZoomed = true;
|
|
5884
6726
|
scale += 0.15;
|
|
5885
6727
|
applyTransform();
|
|
5886
6728
|
},
|
|
5887
6729
|
zoomOut: () => {
|
|
6730
|
+
isUserZoomed = true;
|
|
5888
6731
|
scale = Math.max(0.2, scale - 0.15);
|
|
5889
6732
|
applyTransform();
|
|
5890
6733
|
},
|
|
5891
6734
|
getZoom: () => scale,
|
|
5892
6735
|
setZoom: (level) => {
|
|
6736
|
+
isUserZoomed = true;
|
|
5893
6737
|
scale = level;
|
|
5894
6738
|
applyTransform();
|
|
5895
6739
|
},
|
|
5896
6740
|
fitToPage: () => {
|
|
5897
|
-
|
|
5898
|
-
|
|
6741
|
+
isUserZoomed = false;
|
|
6742
|
+
fitMode = "width";
|
|
6743
|
+
scale = calculateFitScale("width");
|
|
5899
6744
|
rotation = 0;
|
|
5900
6745
|
applyTransform();
|
|
5901
6746
|
},
|
|
@@ -6010,7 +6855,7 @@ var DocPlugin = class {
|
|
|
6010
6855
|
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
6011
6856
|
const trimmed = run.trim();
|
|
6012
6857
|
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
6013
|
-
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)) {
|
|
6858
|
+
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)) {
|
|
6014
6859
|
seen.add(trimmed);
|
|
6015
6860
|
candidateLines.push(trimmed);
|
|
6016
6861
|
}
|
|
@@ -6021,9 +6866,114 @@ var DocPlugin = class {
|
|
|
6021
6866
|
heuristicTextExtraction(buffer) {
|
|
6022
6867
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
6023
6868
|
}
|
|
6024
|
-
|
|
6869
|
+
/**
|
|
6870
|
+
* Parses an embedded OpenDocument Chart package into a vector SVG bar/column chart
|
|
6871
|
+
*/
|
|
6872
|
+
parseOdfChartToSvg(zipBytes) {
|
|
6873
|
+
try {
|
|
6874
|
+
const unzipped = fflate__namespace.unzipSync(zipBytes);
|
|
6875
|
+
const contentXml = unzipped["content.xml"] ? new TextDecoder("utf-8").decode(unzipped["content.xml"]) : "";
|
|
6876
|
+
if (!contentXml) return "";
|
|
6877
|
+
const rowsMatch = contentXml.match(/<table:table-row[\s\S]*?<\/table:table-row>/g) || [];
|
|
6878
|
+
if (rowsMatch.length < 2) return "";
|
|
6879
|
+
const headers = [];
|
|
6880
|
+
const firstRow = rowsMatch[0];
|
|
6881
|
+
const headerCells = firstRow ? firstRow.match(/<text:p>([^<]+)<\/text:p>/g) || [] : [];
|
|
6882
|
+
for (const h of headerCells) {
|
|
6883
|
+
headers.push(h.replace(/<\/?text:p>/g, "").trim());
|
|
6884
|
+
}
|
|
6885
|
+
const categories = [];
|
|
6886
|
+
const seriesValues = headers.map(() => []);
|
|
6887
|
+
for (let r = 1; r < rowsMatch.length; r++) {
|
|
6888
|
+
const rowStr = rowsMatch[r];
|
|
6889
|
+
if (!rowStr) continue;
|
|
6890
|
+
const cells = rowStr.match(/<table:table-cell[\s\S]*?<\/table:table-cell>/g) || [];
|
|
6891
|
+
if (cells.length > 0 && cells[0]) {
|
|
6892
|
+
const catMatch = cells[0].match(/<text:p>([^<]+)<\/text:p>/);
|
|
6893
|
+
categories.push(catMatch ? catMatch[1] : "Row " + r);
|
|
6894
|
+
for (let c = 1; c < cells.length && c - 1 < headers.length; c++) {
|
|
6895
|
+
const cellStr = cells[c];
|
|
6896
|
+
if (!cellStr) continue;
|
|
6897
|
+
const valMatch = cellStr.match(/office:value="([0-9.]+)"/) || cellStr.match(/<text:p>([0-9.]+)<\/text:p>/);
|
|
6898
|
+
const series = seriesValues[c - 1];
|
|
6899
|
+
if (series) {
|
|
6900
|
+
series.push(valMatch ? parseFloat(valMatch[1]) : 0);
|
|
6901
|
+
}
|
|
6902
|
+
}
|
|
6903
|
+
}
|
|
6904
|
+
}
|
|
6905
|
+
const colors = ["#004586", "#ff420e", "#ffd320", "#579d1c", "#7e0021"];
|
|
6906
|
+
const colorMatches = contentXml.matchAll(/draw:fill-color="(#[0-9a-fA-F]{6})"/g);
|
|
6907
|
+
let cIdx = 0;
|
|
6908
|
+
for (const cm of colorMatches) {
|
|
6909
|
+
if (cIdx < colors.length) colors[cIdx] = cm[1];
|
|
6910
|
+
cIdx++;
|
|
6911
|
+
}
|
|
6912
|
+
let maxVal = 10;
|
|
6913
|
+
for (const s of seriesValues) {
|
|
6914
|
+
for (const v of s) {
|
|
6915
|
+
if (v > maxVal) maxVal = v;
|
|
6916
|
+
}
|
|
6917
|
+
}
|
|
6918
|
+
maxVal = Math.ceil(maxVal * 1.15);
|
|
6919
|
+
const width = 560;
|
|
6920
|
+
const height = 280;
|
|
6921
|
+
const padLeft = 45;
|
|
6922
|
+
const padRight = 100;
|
|
6923
|
+
const padTop = 20;
|
|
6924
|
+
const padBottom = 40;
|
|
6925
|
+
const chartW = width - padLeft - padRight;
|
|
6926
|
+
const chartH = height - padTop - padBottom;
|
|
6927
|
+
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);">`;
|
|
6928
|
+
for (let step = 0; step <= 4; step++) {
|
|
6929
|
+
const yVal = (maxVal / 4 * step).toFixed(1);
|
|
6930
|
+
const yPos = padTop + chartH - step / 4 * chartH;
|
|
6931
|
+
svg += `<line x1="${padLeft}" y1="${yPos}" x2="${padLeft + chartW}" y2="${yPos}" stroke="#e2e8f0" stroke-dasharray="2,2" />`;
|
|
6932
|
+
svg += `<text x="${padLeft - 8}" y="${yPos + 4}" font-size="11" fill="#64748b" text-anchor="end">${yVal}</text>`;
|
|
6933
|
+
}
|
|
6934
|
+
const numCats = categories.length;
|
|
6935
|
+
const numSeries = headers.length;
|
|
6936
|
+
const groupW = chartW / numCats;
|
|
6937
|
+
const barW = Math.max(8, groupW * 0.7 / numSeries);
|
|
6938
|
+
const groupPad = (groupW - barW * numSeries) / 2;
|
|
6939
|
+
for (let catIdx = 0; catIdx < numCats; catIdx++) {
|
|
6940
|
+
const groupX = padLeft + catIdx * groupW + groupPad;
|
|
6941
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6942
|
+
const val = seriesValues[sIdx][catIdx] || 0;
|
|
6943
|
+
const barH = val / maxVal * chartH;
|
|
6944
|
+
const barX = groupX + sIdx * barW;
|
|
6945
|
+
const barY = padTop + chartH - barH;
|
|
6946
|
+
const col = colors[sIdx % colors.length];
|
|
6947
|
+
svg += `<rect x="${barX}" y="${barY}" width="${barW - 2}" height="${barH}" fill="${col}" rx="2"><title>${headers[sIdx]}: ${val}</title></rect>`;
|
|
6948
|
+
}
|
|
6949
|
+
const catX = padLeft + catIdx * groupW + groupW / 2;
|
|
6950
|
+
svg += `<text x="${catX}" y="${padTop + chartH + 18}" font-size="11" fill="#475569" text-anchor="middle">${categories[catIdx]}</text>`;
|
|
6951
|
+
}
|
|
6952
|
+
let legendY = padTop + 20;
|
|
6953
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6954
|
+
const col = colors[sIdx % colors.length];
|
|
6955
|
+
svg += `<rect x="${padLeft + chartW + 15}" y="${legendY}" width="12" height="12" fill="${col}" rx="2" />`;
|
|
6956
|
+
svg += `<text x="${padLeft + chartW + 32}" y="${legendY + 10}" font-size="11" fill="#334155">${headers[sIdx]}</text>`;
|
|
6957
|
+
legendY += 20;
|
|
6958
|
+
}
|
|
6959
|
+
svg += "</svg>";
|
|
6960
|
+
return svg;
|
|
6961
|
+
} catch (e) {
|
|
6962
|
+
console.warn("[DocPlugin] Error generating chart SVG:", e);
|
|
6963
|
+
return "";
|
|
6964
|
+
}
|
|
6965
|
+
}
|
|
6966
|
+
cleanWordDocFields(text, chartSvg = "") {
|
|
6025
6967
|
if (!text) return "";
|
|
6026
6968
|
let cleaned = text.replace(
|
|
6969
|
+
/\x13\s*EMBED\b[\s\S]*?\x15/gi,
|
|
6970
|
+
() => chartSvg ? `
|
|
6971
|
+
|
|
6972
|
+
${chartSvg}
|
|
6973
|
+
|
|
6974
|
+
` : ""
|
|
6975
|
+
);
|
|
6976
|
+
cleaned = cleaned.replace(
|
|
6027
6977
|
/\x13\s*HYPERLINK\s*"?([^"\x14]+)"?\s*\x14([\s\S]*?)\x15/gi,
|
|
6028
6978
|
(_match, url, label) => {
|
|
6029
6979
|
const cleanUrl = url.trim();
|
|
@@ -6031,18 +6981,23 @@ var DocPlugin = class {
|
|
|
6031
6981
|
return `<a href="${cleanUrl}" target="_blank" rel="noopener noreferrer" style="color: #2563eb; text-decoration: underline;">${cleanLabel}</a>`;
|
|
6032
6982
|
}
|
|
6033
6983
|
);
|
|
6034
|
-
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g,
|
|
6984
|
+
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g, (_m, res) => {
|
|
6985
|
+
if (/[\x00-\x1F]/.test(res)) return "";
|
|
6986
|
+
return res.trim();
|
|
6987
|
+
});
|
|
6035
6988
|
cleaned = cleaned.replace(/\x13[^\x15]*\x15/g, "");
|
|
6036
6989
|
cleaned = cleaned.replace(/[\x13\x14\x15]/g, "");
|
|
6990
|
+
cleaned = cleaned.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/g, "");
|
|
6991
|
+
cleaned = cleaned.replace(/EMBED\s+LibreOffice\.ChartDocument\.[0-9]+/gi, chartSvg || "");
|
|
6037
6992
|
return cleaned;
|
|
6038
6993
|
}
|
|
6039
|
-
splitIntoPages(text) {
|
|
6994
|
+
splitIntoPages(text, chartSvg = "") {
|
|
6040
6995
|
if (!text) return [""];
|
|
6041
|
-
const cleanedText = this.cleanWordDocFields(text);
|
|
6996
|
+
const cleanedText = this.cleanWordDocFields(text, chartSvg);
|
|
6042
6997
|
const normalized = cleanedText.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ");
|
|
6043
6998
|
const explicitParts = normalized.split(/[\x0C\f]|\n\s*[-=_]{3,}\s*(?:PAGE|Page|page break)[\s\d\w-]*[-=_]{3,}\s*\n/i).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
6044
6999
|
if (explicitParts.length === 0) explicitParts.push(normalized);
|
|
6045
|
-
const maxLinesPerPage =
|
|
7000
|
+
const maxLinesPerPage = 34;
|
|
6046
7001
|
const charsPerLine = 80;
|
|
6047
7002
|
const finalPages = [];
|
|
6048
7003
|
for (const part of explicitParts) {
|
|
@@ -6050,8 +7005,8 @@ var DocPlugin = class {
|
|
|
6050
7005
|
let currentLines = [];
|
|
6051
7006
|
let count = 0;
|
|
6052
7007
|
for (const line of lines) {
|
|
6053
|
-
const
|
|
6054
|
-
const vLines = Math.max(1, Math.ceil((
|
|
7008
|
+
const isSvg = line.includes("<svg");
|
|
7009
|
+
const vLines = isSvg ? 12 : Math.max(1, Math.ceil((line.replace(/<[^>]+>/g, "").length || 1) / charsPerLine));
|
|
6055
7010
|
if (count + vLines > maxLinesPerPage && currentLines.length > 0) {
|
|
6056
7011
|
finalPages.push(currentLines.join("\n"));
|
|
6057
7012
|
currentLines = [];
|
|
@@ -6091,9 +7046,44 @@ var DocPlugin = class {
|
|
|
6091
7046
|
tableLines = [];
|
|
6092
7047
|
}
|
|
6093
7048
|
};
|
|
7049
|
+
const sanitizeOptions = {
|
|
7050
|
+
ADD_TAGS: ["a", "svg", "g", "path", "line", "rect", "circle", "text", "title"],
|
|
7051
|
+
ADD_ATTR: [
|
|
7052
|
+
"href",
|
|
7053
|
+
"target",
|
|
7054
|
+
"rel",
|
|
7055
|
+
"style",
|
|
7056
|
+
"viewBox",
|
|
7057
|
+
"width",
|
|
7058
|
+
"height",
|
|
7059
|
+
"x",
|
|
7060
|
+
"y",
|
|
7061
|
+
"x1",
|
|
7062
|
+
"y1",
|
|
7063
|
+
"x2",
|
|
7064
|
+
"y2",
|
|
7065
|
+
"fill",
|
|
7066
|
+
"stroke",
|
|
7067
|
+
"stroke-width",
|
|
7068
|
+
"stroke-dasharray",
|
|
7069
|
+
"rx",
|
|
7070
|
+
"font-size",
|
|
7071
|
+
"text-anchor"
|
|
7072
|
+
]
|
|
7073
|
+
};
|
|
6094
7074
|
let i = 0;
|
|
6095
7075
|
while (i < lines.length) {
|
|
6096
7076
|
let line = lines[i];
|
|
7077
|
+
if (line.includes("<svg")) {
|
|
7078
|
+
if (inList) {
|
|
7079
|
+
html += "</ul>";
|
|
7080
|
+
inList = false;
|
|
7081
|
+
}
|
|
7082
|
+
flushTable();
|
|
7083
|
+
html += line;
|
|
7084
|
+
i++;
|
|
7085
|
+
continue;
|
|
7086
|
+
}
|
|
6097
7087
|
let tabCount = (line.match(/\t/g) || []).length;
|
|
6098
7088
|
if (tabCount > 0) {
|
|
6099
7089
|
let j = i;
|
|
@@ -6127,26 +7117,31 @@ var DocPlugin = class {
|
|
|
6127
7117
|
i++;
|
|
6128
7118
|
continue;
|
|
6129
7119
|
}
|
|
6130
|
-
|
|
6131
|
-
|
|
7120
|
+
if (/^\d{1,2}$/.test(line.trim())) {
|
|
7121
|
+
i++;
|
|
7122
|
+
continue;
|
|
7123
|
+
}
|
|
7124
|
+
const isShortLine = line.length < 60 && !line.endsWith(".") && !line.endsWith(",");
|
|
7125
|
+
const isTitleLike = isShortLine && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#") || /^(?:Chapter|Section|Part|\d+\.)\b/i.test(line) || /^[A-Z][a-zA-Z0-9\s#:-]{2,45}$/.test(line));
|
|
7126
|
+
if (isTitleLike) {
|
|
6132
7127
|
if (inList) {
|
|
6133
7128
|
html += "</ul>";
|
|
6134
7129
|
inList = false;
|
|
6135
7130
|
}
|
|
6136
|
-
html += `<h2 style="font-size:
|
|
7131
|
+
html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 18px 0 10px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6__default.default.sanitize(line, sanitizeOptions)}</h2>`;
|
|
6137
7132
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
6138
7133
|
if (!inList) {
|
|
6139
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
7134
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
6140
7135
|
inList = true;
|
|
6141
7136
|
}
|
|
6142
7137
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
6143
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
7138
|
+
html += `<li style="margin: 4px 0; line-height: 1.5; font-size: 11pt; color: #1e293b;">${DOMPurify6__default.default.sanitize(bulletText, sanitizeOptions)}</li>`;
|
|
6144
7139
|
} else {
|
|
6145
7140
|
if (inList) {
|
|
6146
7141
|
html += "</ul>";
|
|
6147
7142
|
inList = false;
|
|
6148
7143
|
}
|
|
6149
|
-
html += `<p style="line-height: 1.
|
|
7144
|
+
html += `<p style="line-height: 1.5; margin: 0 0 12px 0; font-size: 11pt; color: #1e293b; text-align: justify;">${DOMPurify6__default.default.sanitize(line, sanitizeOptions)}</p>`;
|
|
6150
7145
|
}
|
|
6151
7146
|
i++;
|
|
6152
7147
|
}
|