@files-preview-app/preview-file 1.3.1 → 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 +1307 -468
- 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 +1307 -468
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +1307 -468
- 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 +1307 -468
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +1307 -468
- 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 +1307 -468
- package/dist/react.js.map +1 -1
- package/dist/styles.css +195 -14
- package/dist/vue.cjs +1307 -468
- 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 +1307 -468
- package/dist/vue.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -578,8 +578,7 @@ var ICON_FULLSCREEN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="non
|
|
|
578
578
|
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>`;
|
|
579
579
|
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>`;
|
|
580
580
|
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>`;
|
|
581
|
-
var
|
|
582
|
-
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>`;
|
|
581
|
+
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>`;
|
|
583
582
|
var ICON_MAP = {
|
|
584
583
|
"zoom-in": ICON_ZOOM_IN,
|
|
585
584
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -606,28 +605,177 @@ var ICON_MAP = {
|
|
|
606
605
|
"forward-10": ICON_FAST_FORWARD,
|
|
607
606
|
"rewind": ICON_REWIND,
|
|
608
607
|
"replay-10": ICON_REWIND,
|
|
609
|
-
"speed": ICON_SPEED,
|
|
610
608
|
"open-window": ICON_EXTERNAL_WINDOW,
|
|
611
|
-
"external-window": ICON_EXTERNAL_WINDOW
|
|
609
|
+
"external-window": ICON_EXTERNAL_WINDOW,
|
|
610
|
+
"openWindow": ICON_EXTERNAL_WINDOW,
|
|
611
|
+
"openSeparateWindow": ICON_EXTERNAL_WINDOW
|
|
612
612
|
};
|
|
613
613
|
var ToolbarController = class {
|
|
614
614
|
el;
|
|
615
615
|
toolbarEl;
|
|
616
616
|
actions = [];
|
|
617
|
+
config = {};
|
|
617
618
|
pageInputEl = null;
|
|
618
619
|
pageLabelEl = null;
|
|
619
|
-
|
|
620
|
+
prevPageBtn = null;
|
|
621
|
+
nextPageBtn = null;
|
|
622
|
+
constructor(container, config) {
|
|
620
623
|
this.el = container;
|
|
624
|
+
if (config) this.config = { ...config };
|
|
621
625
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
622
626
|
this.el.appendChild(this.toolbarEl);
|
|
623
627
|
}
|
|
628
|
+
setConfig(config) {
|
|
629
|
+
this.config = { ...config };
|
|
630
|
+
this.render();
|
|
631
|
+
}
|
|
632
|
+
getConfig() {
|
|
633
|
+
return { ...this.config };
|
|
634
|
+
}
|
|
635
|
+
hideAction(actionId) {
|
|
636
|
+
this.config[actionId] = false;
|
|
637
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = false;
|
|
638
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = false;
|
|
639
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
640
|
+
this.config.fitPage = false;
|
|
641
|
+
this.config.fitToPage = false;
|
|
642
|
+
this.config.fitWidth = false;
|
|
643
|
+
}
|
|
644
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = false;
|
|
645
|
+
if (actionId === "fullscreen") this.config.fullscreen = false;
|
|
646
|
+
if (actionId === "download") this.config.download = false;
|
|
647
|
+
if (actionId === "print") this.config.print = false;
|
|
648
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
649
|
+
this.config.openWindow = false;
|
|
650
|
+
this.config.openSeparateWindow = false;
|
|
651
|
+
}
|
|
652
|
+
if (actionId === "copy") this.config.copy = false;
|
|
653
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
654
|
+
this.config.pageNav = false;
|
|
655
|
+
this.config.pagination = false;
|
|
656
|
+
}
|
|
657
|
+
this.render();
|
|
658
|
+
}
|
|
659
|
+
showAction(actionId) {
|
|
660
|
+
this.config[actionId] = true;
|
|
661
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = true;
|
|
662
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = true;
|
|
663
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
664
|
+
this.config.fitPage = true;
|
|
665
|
+
this.config.fitToPage = true;
|
|
666
|
+
this.config.fitWidth = true;
|
|
667
|
+
}
|
|
668
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = true;
|
|
669
|
+
if (actionId === "fullscreen") this.config.fullscreen = true;
|
|
670
|
+
if (actionId === "download") this.config.download = true;
|
|
671
|
+
if (actionId === "print") this.config.print = true;
|
|
672
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
673
|
+
this.config.openWindow = true;
|
|
674
|
+
this.config.openSeparateWindow = true;
|
|
675
|
+
}
|
|
676
|
+
if (actionId === "copy") this.config.copy = true;
|
|
677
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
678
|
+
this.config.pageNav = true;
|
|
679
|
+
this.config.pagination = true;
|
|
680
|
+
}
|
|
681
|
+
this.render();
|
|
682
|
+
}
|
|
683
|
+
normalizeActionId(actionId) {
|
|
684
|
+
if (actionId === "zoomIn") return "zoom-in";
|
|
685
|
+
if (actionId === "zoomOut") return "zoom-out";
|
|
686
|
+
if (actionId === "fitPage" || actionId === "fitToPage" || actionId === "fitWidth") return "fit-page";
|
|
687
|
+
if (actionId === "rotateCW") return "rotate-cw";
|
|
688
|
+
if (actionId === "rotateCCW") return "rotate-ccw";
|
|
689
|
+
if (actionId === "openWindow" || actionId === "openSeparateWindow") return "open-window";
|
|
690
|
+
if (actionId === "pageNav") return "page-nav";
|
|
691
|
+
return actionId;
|
|
692
|
+
}
|
|
693
|
+
enableAction(actionId) {
|
|
694
|
+
const norm = this.normalizeActionId(actionId);
|
|
695
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
696
|
+
if (btn) {
|
|
697
|
+
btn.disabled = false;
|
|
698
|
+
btn.classList.remove("disabled");
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
disableAction(actionId) {
|
|
702
|
+
const norm = this.normalizeActionId(actionId);
|
|
703
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
704
|
+
if (btn) {
|
|
705
|
+
btn.disabled = true;
|
|
706
|
+
btn.classList.add("disabled");
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
setActionActive(actionId, active) {
|
|
710
|
+
const norm = this.normalizeActionId(actionId);
|
|
711
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
712
|
+
if (btn) {
|
|
713
|
+
if (active) {
|
|
714
|
+
btn.classList.add("active");
|
|
715
|
+
} else {
|
|
716
|
+
btn.classList.remove("active");
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
isActionEnabled(action) {
|
|
721
|
+
const c = this.config;
|
|
722
|
+
const id = action.id;
|
|
723
|
+
if (c[id] === false) return false;
|
|
724
|
+
if (id === "zoom-in" && (c.zoomIn === false || c["zoom-in"] === false)) return false;
|
|
725
|
+
if (id === "zoom-out" && (c.zoomOut === false || c["zoom-out"] === false)) return false;
|
|
726
|
+
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)) {
|
|
727
|
+
return false;
|
|
728
|
+
}
|
|
729
|
+
if ((id === "rotate-cw" || id === "rotate-ccw" || id === "rotate") && (c.rotate === false || c.rotateCW === false || c.rotateCCW === false || c["rotate-cw"] === false)) {
|
|
730
|
+
return false;
|
|
731
|
+
}
|
|
732
|
+
if (id === "fullscreen" && c.fullscreen === false) return false;
|
|
733
|
+
if (id === "download" && c.download === false) return false;
|
|
734
|
+
if (id === "print" && c.print === false) return false;
|
|
735
|
+
if ((id === "open-window" || id === "external-window") && (c.openWindow === false || c.openSeparateWindow === false || c["open-window"] === false)) {
|
|
736
|
+
return false;
|
|
737
|
+
}
|
|
738
|
+
if (id === "copy" && c.copy === false) return false;
|
|
739
|
+
if (id === "thumbnails" && c.thumbnails === false) return false;
|
|
740
|
+
if (id === "page-nav" && (c.pageNav === false || c.pagination === false || c["page-nav"] === false)) {
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
743
|
+
if ((id === "prev" || id === "page-prev") && (c.prevPage === false || c.prev === false || c["prev"] === false || c.pageNav === false || c.pagination === false)) {
|
|
744
|
+
return false;
|
|
745
|
+
}
|
|
746
|
+
if ((id === "next" || id === "page-next") && (c.nextPage === false || c.next === false || c["next"] === false || c.pageNav === false || c.pagination === false)) {
|
|
747
|
+
return false;
|
|
748
|
+
}
|
|
749
|
+
if (id === "play" && c.play === false) return false;
|
|
750
|
+
if (id === "pause" && c.pause === false) return false;
|
|
751
|
+
if ((id === "fast-forward" || id === "forward-10") && (c.fastForward === false || c["fast-forward"] === false)) {
|
|
752
|
+
return false;
|
|
753
|
+
}
|
|
754
|
+
if ((id === "rewind" || id === "replay-10") && (c.rewind === false || c["rewind"] === false)) {
|
|
755
|
+
return false;
|
|
756
|
+
}
|
|
757
|
+
if (id === "speed" && c.speed === false) return false;
|
|
758
|
+
return true;
|
|
759
|
+
}
|
|
624
760
|
setPage(page, max) {
|
|
625
761
|
if (this.pageInputEl) {
|
|
626
762
|
this.pageInputEl.value = page.toString();
|
|
763
|
+
if (max !== void 0) {
|
|
764
|
+
this.pageInputEl.max = max.toString();
|
|
765
|
+
}
|
|
627
766
|
}
|
|
628
767
|
if (max !== void 0 && this.pageLabelEl) {
|
|
629
768
|
this.pageLabelEl.textContent = ` / ${max}`;
|
|
630
769
|
}
|
|
770
|
+
const currentMax = max !== void 0 ? max : parseInt(this.pageInputEl?.max || "1", 10) || 1;
|
|
771
|
+
if (this.prevPageBtn) {
|
|
772
|
+
this.prevPageBtn.disabled = page <= 1;
|
|
773
|
+
this.prevPageBtn.style.opacity = page <= 1 ? "0.4" : "1";
|
|
774
|
+
}
|
|
775
|
+
if (this.nextPageBtn) {
|
|
776
|
+
this.nextPageBtn.disabled = page >= currentMax;
|
|
777
|
+
this.nextPageBtn.style.opacity = page >= currentMax ? "0.4" : "1";
|
|
778
|
+
}
|
|
631
779
|
}
|
|
632
780
|
update(actions) {
|
|
633
781
|
this.actions = actions;
|
|
@@ -650,8 +798,9 @@ var ToolbarController = class {
|
|
|
650
798
|
view: [],
|
|
651
799
|
actions: []
|
|
652
800
|
};
|
|
653
|
-
const
|
|
654
|
-
const
|
|
801
|
+
const enabledActions = this.actions.filter((a) => this.isActionEnabled(a));
|
|
802
|
+
const hasPageNav = enabledActions.some((a) => a.type === "page-nav");
|
|
803
|
+
const effectiveActions = hasPageNav ? enabledActions.filter((a) => a.id !== "page-prev" && a.id !== "page-next" && a.id !== "prev" && a.id !== "next") : enabledActions;
|
|
655
804
|
for (const action of effectiveActions) {
|
|
656
805
|
if (groups[action.group]) {
|
|
657
806
|
groups[action.group].push(action);
|
|
@@ -711,6 +860,13 @@ var ToolbarController = class {
|
|
|
711
860
|
action.execute("go", val);
|
|
712
861
|
});
|
|
713
862
|
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
863
|
+
const curVal = action.value ?? 1;
|
|
864
|
+
prevBtn.disabled = curVal <= 1;
|
|
865
|
+
prevBtn.style.opacity = curVal <= 1 ? "0.4" : "1";
|
|
866
|
+
nextBtn.disabled = curVal >= max;
|
|
867
|
+
nextBtn.style.opacity = curVal >= max ? "0.4" : "1";
|
|
868
|
+
this.prevPageBtn = prevBtn;
|
|
869
|
+
this.nextPageBtn = nextBtn;
|
|
714
870
|
this.pageInputEl = input;
|
|
715
871
|
this.pageLabelEl = label;
|
|
716
872
|
groupEl.appendChild(prevBtn);
|
|
@@ -766,25 +922,63 @@ var ToolbarController = class {
|
|
|
766
922
|
var ThumbnailPanel = class {
|
|
767
923
|
el;
|
|
768
924
|
panelEl;
|
|
925
|
+
listEl;
|
|
926
|
+
headerEl;
|
|
769
927
|
thumbnails = [];
|
|
770
928
|
onSelect;
|
|
929
|
+
onToggleCallback;
|
|
771
930
|
activeIndex = 0;
|
|
772
|
-
|
|
931
|
+
observer;
|
|
932
|
+
renderedIndices = /* @__PURE__ */ new Set();
|
|
933
|
+
constructor(container, onToggle) {
|
|
773
934
|
this.el = container;
|
|
935
|
+
this.onToggleCallback = onToggle;
|
|
774
936
|
this.panelEl = createElement("div", { className: "fp-thumbnail-panel hidden" });
|
|
937
|
+
this.panelEl.style.width = "0px";
|
|
938
|
+
this.panelEl.style.minWidth = "0px";
|
|
939
|
+
this.panelEl.style.opacity = "0";
|
|
940
|
+
this.headerEl = createElement("div", { className: "fp-thumbnail-header" });
|
|
941
|
+
const title = createElement("span", { className: "fp-thumbnail-title" }, "Pages");
|
|
942
|
+
const closeBtn = createElement("button", {
|
|
943
|
+
className: "fp-thumbnail-close-btn",
|
|
944
|
+
title: "Close Thumbnails",
|
|
945
|
+
type: "button"
|
|
946
|
+
});
|
|
947
|
+
closeBtn.innerHTML = ICON_CLOSE;
|
|
948
|
+
closeBtn.addEventListener("click", (e) => {
|
|
949
|
+
e.stopPropagation();
|
|
950
|
+
this.hide();
|
|
951
|
+
});
|
|
952
|
+
this.headerEl.appendChild(title);
|
|
953
|
+
this.headerEl.appendChild(closeBtn);
|
|
954
|
+
this.listEl = createElement("div", { className: "fp-thumbnail-list" });
|
|
955
|
+
this.panelEl.appendChild(this.headerEl);
|
|
956
|
+
this.panelEl.appendChild(this.listEl);
|
|
775
957
|
this.el.appendChild(this.panelEl);
|
|
776
958
|
}
|
|
959
|
+
isOpen() {
|
|
960
|
+
return !this.panelEl.classList.contains("hidden") && this.panelEl.style.width !== "0px";
|
|
961
|
+
}
|
|
777
962
|
update(thumbnails, onSelect) {
|
|
778
963
|
this.thumbnails = thumbnails;
|
|
779
964
|
this.onSelect = onSelect;
|
|
965
|
+
this.renderedIndices.clear();
|
|
966
|
+
const titleEl = this.headerEl.querySelector(".fp-thumbnail-title");
|
|
967
|
+
if (titleEl) {
|
|
968
|
+
titleEl.textContent = `Pages (${thumbnails.length})`;
|
|
969
|
+
}
|
|
780
970
|
this.render();
|
|
971
|
+
if (this.isOpen()) {
|
|
972
|
+
this.renderAllVisible();
|
|
973
|
+
}
|
|
781
974
|
}
|
|
782
975
|
setActive(index) {
|
|
783
976
|
this.activeIndex = index;
|
|
784
|
-
const items = this.
|
|
977
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
785
978
|
items.forEach((item, i) => {
|
|
786
979
|
if (i === index) {
|
|
787
980
|
item.classList.add("active");
|
|
981
|
+
item.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
788
982
|
} else {
|
|
789
983
|
item.classList.remove("active");
|
|
790
984
|
}
|
|
@@ -792,37 +986,102 @@ var ThumbnailPanel = class {
|
|
|
792
986
|
}
|
|
793
987
|
show() {
|
|
794
988
|
this.panelEl.classList.remove("hidden");
|
|
989
|
+
this.panelEl.style.width = "200px";
|
|
990
|
+
this.panelEl.style.minWidth = "200px";
|
|
991
|
+
this.panelEl.style.opacity = "1";
|
|
992
|
+
this.panelEl.style.display = "flex";
|
|
993
|
+
this.onToggleCallback?.(true);
|
|
994
|
+
this.renderAllVisible();
|
|
795
995
|
}
|
|
796
996
|
hide() {
|
|
797
997
|
this.panelEl.classList.add("hidden");
|
|
998
|
+
this.panelEl.style.width = "0px";
|
|
999
|
+
this.panelEl.style.minWidth = "0px";
|
|
1000
|
+
this.panelEl.style.opacity = "0";
|
|
1001
|
+
this.onToggleCallback?.(false);
|
|
798
1002
|
}
|
|
799
1003
|
toggle() {
|
|
800
|
-
this.
|
|
1004
|
+
if (this.isOpen()) {
|
|
1005
|
+
this.hide();
|
|
1006
|
+
} else {
|
|
1007
|
+
this.show();
|
|
1008
|
+
}
|
|
801
1009
|
}
|
|
802
1010
|
destroy() {
|
|
1011
|
+
if (this.observer) {
|
|
1012
|
+
this.observer.disconnect();
|
|
1013
|
+
this.observer = void 0;
|
|
1014
|
+
}
|
|
1015
|
+
this.renderedIndices.clear();
|
|
803
1016
|
this.el.innerHTML = "";
|
|
804
1017
|
}
|
|
805
|
-
|
|
806
|
-
this.
|
|
1018
|
+
renderAllVisible() {
|
|
1019
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
1020
|
+
items.forEach((item) => {
|
|
1021
|
+
const idx = parseInt(item.dataset.thumbIndex || "-1", 10);
|
|
1022
|
+
if (idx >= 0 && !this.renderedIndices.has(idx)) {
|
|
1023
|
+
this.renderThumbnailItem(idx, item);
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
renderThumbnailItem(idx, itemEl) {
|
|
1028
|
+
if (this.renderedIndices.has(idx)) return;
|
|
1029
|
+
this.renderedIndices.add(idx);
|
|
1030
|
+
const canvas = itemEl.querySelector("canvas");
|
|
1031
|
+
const thumb = this.thumbnails[idx];
|
|
1032
|
+
if (canvas && thumb) {
|
|
1033
|
+
Promise.resolve(thumb.render(canvas)).catch((err) => {
|
|
1034
|
+
console.warn(`[FilePreview] Error rendering thumbnail ${idx}:`, err);
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
render() {
|
|
1039
|
+
if (this.observer) {
|
|
1040
|
+
this.observer.disconnect();
|
|
1041
|
+
}
|
|
1042
|
+
this.listEl.innerHTML = "";
|
|
1043
|
+
const useObserver = typeof IntersectionObserver !== "undefined";
|
|
1044
|
+
if (useObserver) {
|
|
1045
|
+
this.observer = new IntersectionObserver(
|
|
1046
|
+
(entries) => {
|
|
1047
|
+
for (const entry of entries) {
|
|
1048
|
+
if (entry.isIntersecting) {
|
|
1049
|
+
const target = entry.target;
|
|
1050
|
+
const idx = parseInt(target.dataset.thumbIndex || "-1", 10);
|
|
1051
|
+
if (idx >= 0) {
|
|
1052
|
+
this.renderThumbnailItem(idx, target);
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
},
|
|
1057
|
+
{
|
|
1058
|
+
root: this.listEl,
|
|
1059
|
+
rootMargin: "120px 0px 120px 0px"
|
|
1060
|
+
}
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
807
1063
|
for (let i = 0; i < this.thumbnails.length; i++) {
|
|
808
1064
|
const thumb = this.thumbnails[i];
|
|
809
|
-
const itemEl = createElement("div", {
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1065
|
+
const itemEl = createElement("div", {
|
|
1066
|
+
className: "fp-thumbnail-item" + (i === this.activeIndex ? " active" : "")
|
|
1067
|
+
});
|
|
1068
|
+
itemEl.dataset.thumbIndex = i.toString();
|
|
813
1069
|
itemEl.addEventListener("click", () => {
|
|
814
1070
|
this.setActive(i);
|
|
815
1071
|
this.onSelect?.(i);
|
|
816
1072
|
});
|
|
817
|
-
const
|
|
818
|
-
const
|
|
819
|
-
|
|
1073
|
+
const canvasWrapper = createElement("div", { className: "fp-thumbnail-canvas-wrapper" });
|
|
1074
|
+
const canvas = createElement("canvas", { width: "130", height: "170" });
|
|
1075
|
+
canvasWrapper.appendChild(canvas);
|
|
1076
|
+
const label = createElement("span", { className: "fp-thumbnail-label" }, thumb.label || `Page ${i + 1}`);
|
|
1077
|
+
itemEl.appendChild(canvasWrapper);
|
|
820
1078
|
itemEl.appendChild(label);
|
|
821
|
-
this.
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
}
|
|
825
|
-
|
|
1079
|
+
this.listEl.appendChild(itemEl);
|
|
1080
|
+
if (this.observer) {
|
|
1081
|
+
this.observer.observe(itemEl);
|
|
1082
|
+
}
|
|
1083
|
+
if (i < 4) {
|
|
1084
|
+
this.renderThumbnailItem(i, itemEl);
|
|
826
1085
|
}
|
|
827
1086
|
}
|
|
828
1087
|
}
|
|
@@ -843,6 +1102,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
843
1102
|
currentOptions = {};
|
|
844
1103
|
resizeObserver = null;
|
|
845
1104
|
fullscreenHandler = null;
|
|
1105
|
+
titleBarEl = null;
|
|
846
1106
|
/**
|
|
847
1107
|
* Register a preview plugin.
|
|
848
1108
|
*/
|
|
@@ -879,6 +1139,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
879
1139
|
}
|
|
880
1140
|
this.currentBuffer = buffer.slice(0);
|
|
881
1141
|
this.currentMetadata = metadata;
|
|
1142
|
+
this.updateTitleBar(options, metadata);
|
|
882
1143
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
883
1144
|
const fileInfo = { metadata, buffer };
|
|
884
1145
|
const matchedPlugin = await this.findPlugin(fileInfo);
|
|
@@ -902,15 +1163,21 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
902
1163
|
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
903
1164
|
const total = payload.total ?? payload.totalPages;
|
|
904
1165
|
this.toolbar?.setPage(payload.page, total);
|
|
1166
|
+
this.thumbnailPanel?.setActive(payload.page - 1);
|
|
905
1167
|
}
|
|
906
1168
|
this.eventEmitter.emit(event, payload);
|
|
907
|
-
}
|
|
1169
|
+
},
|
|
1170
|
+
toggleThumbnails: () => this.toggleThumbnails()
|
|
908
1171
|
});
|
|
909
1172
|
this.activeInstance = instance;
|
|
910
1173
|
instance.openInSeparateWindow = () => this.openInSeparateWindow();
|
|
1174
|
+
instance.toggleThumbnails = () => this.toggleThumbnails();
|
|
911
1175
|
this.hideLoading();
|
|
912
1176
|
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
913
|
-
|
|
1177
|
+
const isToolbarVisible = options.showToolbar !== false && options.toolbar !== false;
|
|
1178
|
+
if (isToolbarVisible && this.toolbar) {
|
|
1179
|
+
const toolbarConfig = this.extractToolbarConfig(options);
|
|
1180
|
+
this.toolbar.setConfig(toolbarConfig);
|
|
914
1181
|
const actions = matchedPlugin.getToolbarActions(instance);
|
|
915
1182
|
const hasFullscreen = actions.some((a) => a.id === "fullscreen");
|
|
916
1183
|
if (!hasFullscreen && this.wrapperEl) {
|
|
@@ -960,6 +1227,12 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
960
1227
|
}
|
|
961
1228
|
});
|
|
962
1229
|
}
|
|
1230
|
+
const thumbAction = actions.find((a) => a.id === "thumbnails");
|
|
1231
|
+
if (thumbAction) {
|
|
1232
|
+
thumbAction.execute = () => {
|
|
1233
|
+
this.toggleThumbnails();
|
|
1234
|
+
};
|
|
1235
|
+
}
|
|
963
1236
|
this.toolbar.update(actions);
|
|
964
1237
|
this.toolbar.show();
|
|
965
1238
|
}
|
|
@@ -1044,7 +1317,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1044
1317
|
if (targetUrl) {
|
|
1045
1318
|
const newWin2 = window.open(targetUrl, "_blank");
|
|
1046
1319
|
if (!newWin2) {
|
|
1047
|
-
|
|
1320
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
1048
1321
|
return null;
|
|
1049
1322
|
}
|
|
1050
1323
|
return newWin2;
|
|
@@ -1052,7 +1325,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1052
1325
|
const title = (this.currentMetadata?.name || "Document Preview") + " - Full Preview";
|
|
1053
1326
|
const newWin = window.open("", "_blank");
|
|
1054
1327
|
if (!newWin) {
|
|
1055
|
-
|
|
1328
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
1056
1329
|
return null;
|
|
1057
1330
|
}
|
|
1058
1331
|
newWin.document.title = title;
|
|
@@ -1129,6 +1402,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1129
1402
|
this.currentBuffer = null;
|
|
1130
1403
|
this.currentMetadata = null;
|
|
1131
1404
|
this.currentContainer = null;
|
|
1405
|
+
this.titleBarEl = null;
|
|
1132
1406
|
}
|
|
1133
1407
|
/**
|
|
1134
1408
|
* Get the currently active preview instance.
|
|
@@ -1136,7 +1410,218 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1136
1410
|
getInstance() {
|
|
1137
1411
|
return this.activeInstance;
|
|
1138
1412
|
}
|
|
1413
|
+
// --- Toolbar Configuration & Feature Toggles ---
|
|
1414
|
+
/**
|
|
1415
|
+
* Configure toolbar features dynamically through options or methods.
|
|
1416
|
+
* e.g. viewer.setToolbarConfig({ zoomIn: false, print: false })
|
|
1417
|
+
*/
|
|
1418
|
+
setToolbarConfig(config) {
|
|
1419
|
+
this.toolbar?.setConfig(config);
|
|
1420
|
+
}
|
|
1421
|
+
/**
|
|
1422
|
+
* Get current toolbar configuration.
|
|
1423
|
+
*/
|
|
1424
|
+
getToolbarConfig() {
|
|
1425
|
+
return this.toolbar?.getConfig() ?? {};
|
|
1426
|
+
}
|
|
1427
|
+
/**
|
|
1428
|
+
* Hide a specific toolbar action by ID or alias (e.g. 'zoom-in', 'print', 'download').
|
|
1429
|
+
*/
|
|
1430
|
+
hideToolbarAction(actionId) {
|
|
1431
|
+
this.toolbar?.hideAction(actionId);
|
|
1432
|
+
}
|
|
1433
|
+
/**
|
|
1434
|
+
* Show a specific toolbar action by ID or alias.
|
|
1435
|
+
*/
|
|
1436
|
+
showToolbarAction(actionId) {
|
|
1437
|
+
this.toolbar?.showAction(actionId);
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* Enable a specific toolbar action button.
|
|
1441
|
+
*/
|
|
1442
|
+
enableToolbarAction(actionId) {
|
|
1443
|
+
this.toolbar?.enableAction(actionId);
|
|
1444
|
+
}
|
|
1445
|
+
/**
|
|
1446
|
+
* Disable a specific toolbar action button.
|
|
1447
|
+
*/
|
|
1448
|
+
disableToolbarAction(actionId) {
|
|
1449
|
+
this.toolbar?.disableAction(actionId);
|
|
1450
|
+
}
|
|
1451
|
+
// --- Programmatic Toolbar Action Methods ---
|
|
1452
|
+
/**
|
|
1453
|
+
* Fit document to page so it fills the frame width with minimal margins.
|
|
1454
|
+
*/
|
|
1455
|
+
fitToPage() {
|
|
1456
|
+
this.activeInstance?.fitToPage?.();
|
|
1457
|
+
}
|
|
1458
|
+
/**
|
|
1459
|
+
* Zoom in.
|
|
1460
|
+
*/
|
|
1461
|
+
zoomIn() {
|
|
1462
|
+
this.activeInstance?.zoomIn?.();
|
|
1463
|
+
}
|
|
1464
|
+
/**
|
|
1465
|
+
* Zoom out.
|
|
1466
|
+
*/
|
|
1467
|
+
zoomOut() {
|
|
1468
|
+
this.activeInstance?.zoomOut?.();
|
|
1469
|
+
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Set specific zoom level.
|
|
1472
|
+
*/
|
|
1473
|
+
setZoom(level) {
|
|
1474
|
+
this.activeInstance?.setZoom?.(level);
|
|
1475
|
+
}
|
|
1476
|
+
/**
|
|
1477
|
+
* Get current zoom level.
|
|
1478
|
+
*/
|
|
1479
|
+
getZoom() {
|
|
1480
|
+
return this.activeInstance?.getZoom?.() ?? 1;
|
|
1481
|
+
}
|
|
1482
|
+
/**
|
|
1483
|
+
* Rotate 90 degrees clockwise.
|
|
1484
|
+
*/
|
|
1485
|
+
rotateCW() {
|
|
1486
|
+
this.activeInstance?.rotateCW?.();
|
|
1487
|
+
}
|
|
1488
|
+
/**
|
|
1489
|
+
* Rotate 90 degrees counter-clockwise.
|
|
1490
|
+
*/
|
|
1491
|
+
rotateCCW() {
|
|
1492
|
+
this.activeInstance?.rotateCCW?.();
|
|
1493
|
+
}
|
|
1494
|
+
/**
|
|
1495
|
+
* Navigate to a specific page number.
|
|
1496
|
+
*/
|
|
1497
|
+
goToPage(page) {
|
|
1498
|
+
this.activeInstance?.goToPage?.(page);
|
|
1499
|
+
this.toolbar?.setPage(page);
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* Navigate to next page.
|
|
1503
|
+
*/
|
|
1504
|
+
nextPage() {
|
|
1505
|
+
const cur = this.getCurrentPage();
|
|
1506
|
+
const max = this.getPageCount();
|
|
1507
|
+
if (cur < max) {
|
|
1508
|
+
this.goToPage(cur + 1);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
/**
|
|
1512
|
+
* Navigate to previous page.
|
|
1513
|
+
*/
|
|
1514
|
+
prevPage() {
|
|
1515
|
+
const cur = this.getCurrentPage();
|
|
1516
|
+
if (cur > 1) {
|
|
1517
|
+
this.goToPage(cur - 1);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
/**
|
|
1521
|
+
* Get total page count.
|
|
1522
|
+
*/
|
|
1523
|
+
getPageCount() {
|
|
1524
|
+
return this.activeInstance?.getPageCount?.() ?? 1;
|
|
1525
|
+
}
|
|
1526
|
+
/**
|
|
1527
|
+
* Get current page number.
|
|
1528
|
+
*/
|
|
1529
|
+
getCurrentPage() {
|
|
1530
|
+
return this.activeInstance?.getCurrentPage?.() ?? 1;
|
|
1531
|
+
}
|
|
1532
|
+
/**
|
|
1533
|
+
* Download the current document.
|
|
1534
|
+
*/
|
|
1535
|
+
download() {
|
|
1536
|
+
this.activeInstance?.download?.();
|
|
1537
|
+
}
|
|
1538
|
+
/**
|
|
1539
|
+
* Print the current document.
|
|
1540
|
+
*/
|
|
1541
|
+
print() {
|
|
1542
|
+
this.activeInstance?.print?.();
|
|
1543
|
+
}
|
|
1544
|
+
/**
|
|
1545
|
+
* Toggle fullscreen mode.
|
|
1546
|
+
*/
|
|
1547
|
+
toggleFullscreen() {
|
|
1548
|
+
try {
|
|
1549
|
+
if (!document.fullscreenElement) {
|
|
1550
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
1551
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
1552
|
+
} else {
|
|
1553
|
+
document.exitFullscreen?.();
|
|
1554
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
1555
|
+
}
|
|
1556
|
+
} catch {
|
|
1557
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
1558
|
+
}
|
|
1559
|
+
setTimeout(() => {
|
|
1560
|
+
this.activeInstance?.fitToPage?.();
|
|
1561
|
+
}, 120);
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* Toggle thumbnails sidebar panel.
|
|
1565
|
+
*/
|
|
1566
|
+
toggleThumbnails() {
|
|
1567
|
+
if (!this.thumbnailPanel) return;
|
|
1568
|
+
this.thumbnailPanel.toggle();
|
|
1569
|
+
const isOpen = this.thumbnailPanel.isOpen();
|
|
1570
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1571
|
+
setTimeout(() => {
|
|
1572
|
+
this.activeInstance?.fitToPage?.();
|
|
1573
|
+
}, 260);
|
|
1574
|
+
}
|
|
1575
|
+
/**
|
|
1576
|
+
* Set whether to display the file name / title bar above the toolbar.
|
|
1577
|
+
*/
|
|
1578
|
+
setShowFileName(show) {
|
|
1579
|
+
if (this.currentOptions) {
|
|
1580
|
+
this.currentOptions.showFileName = show;
|
|
1581
|
+
}
|
|
1582
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1583
|
+
}
|
|
1584
|
+
/**
|
|
1585
|
+
* Set or override the displayed file name in the preview panel.
|
|
1586
|
+
*/
|
|
1587
|
+
setFileName(name) {
|
|
1588
|
+
if (this.currentOptions) {
|
|
1589
|
+
this.currentOptions.fileName = name;
|
|
1590
|
+
}
|
|
1591
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1592
|
+
}
|
|
1139
1593
|
// --- Private methods ---
|
|
1594
|
+
updateTitleBar(options, metadata) {
|
|
1595
|
+
if (!this.titleBarEl) return;
|
|
1596
|
+
const show = options?.showFileName !== false;
|
|
1597
|
+
if (!show) {
|
|
1598
|
+
this.titleBarEl.style.display = "none";
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
const name = options?.fileName || metadata?.name || this.currentMetadata?.name || "";
|
|
1602
|
+
if (!name) {
|
|
1603
|
+
this.titleBarEl.style.display = "none";
|
|
1604
|
+
return;
|
|
1605
|
+
}
|
|
1606
|
+
this.titleBarEl.style.display = "flex";
|
|
1607
|
+
const ext = metadata?.extension || (name.includes(".") ? "." + name.split(".").pop() : "");
|
|
1608
|
+
const badge = ext ? ext.replace(".", "").toUpperCase() : "";
|
|
1609
|
+
this.titleBarEl.innerHTML = `
|
|
1610
|
+
<div class="fp-titlebar-info">
|
|
1611
|
+
<span class="fp-titlebar-icon">\u{1F4C4}</span>
|
|
1612
|
+
<span class="fp-titlebar-name" title="${name}">${name}</span>
|
|
1613
|
+
${badge ? `<span class="fp-titlebar-badge">${badge}</span>` : ""}
|
|
1614
|
+
</div>
|
|
1615
|
+
`;
|
|
1616
|
+
}
|
|
1617
|
+
extractToolbarConfig(options) {
|
|
1618
|
+
if (!options) return {};
|
|
1619
|
+
const nested = typeof options.toolbar === "object" ? options.toolbar : {};
|
|
1620
|
+
return {
|
|
1621
|
+
...options,
|
|
1622
|
+
...nested
|
|
1623
|
+
};
|
|
1624
|
+
}
|
|
1140
1625
|
abort() {
|
|
1141
1626
|
if (this.abortController) {
|
|
1142
1627
|
this.abortController.abort();
|
|
@@ -1179,17 +1664,29 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1179
1664
|
bodyEl.className = "fp-body";
|
|
1180
1665
|
bodyEl.appendChild(thumbnailEl);
|
|
1181
1666
|
bodyEl.appendChild(this.contentEl);
|
|
1667
|
+
const titleBarEl = document.createElement("div");
|
|
1668
|
+
titleBarEl.className = "fp-titlebar";
|
|
1669
|
+
this.titleBarEl = titleBarEl;
|
|
1670
|
+
this.updateTitleBar(options, this.currentMetadata);
|
|
1182
1671
|
if (toolbarPos === "top") {
|
|
1672
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1183
1673
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1184
1674
|
this.wrapperEl.appendChild(bodyEl);
|
|
1185
1675
|
} else {
|
|
1676
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1186
1677
|
this.wrapperEl.appendChild(bodyEl);
|
|
1187
1678
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1188
1679
|
}
|
|
1189
1680
|
container.innerHTML = "";
|
|
1190
1681
|
container.appendChild(this.wrapperEl);
|
|
1191
|
-
|
|
1192
|
-
this.
|
|
1682
|
+
const initialToolbarConfig = this.extractToolbarConfig(options);
|
|
1683
|
+
this.toolbar = new ToolbarController(toolbarEl, initialToolbarConfig);
|
|
1684
|
+
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl, (isOpen) => {
|
|
1685
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1686
|
+
setTimeout(() => {
|
|
1687
|
+
this.activeInstance?.fitToPage?.();
|
|
1688
|
+
}, 260);
|
|
1689
|
+
});
|
|
1193
1690
|
this.setupKeyboardShortcuts();
|
|
1194
1691
|
this.setupDragAndDrop(container, options);
|
|
1195
1692
|
this.setupResizeAndFullscreenListeners();
|
|
@@ -1579,6 +2076,14 @@ var PdfPlugin = class {
|
|
|
1579
2076
|
group: "zoom",
|
|
1580
2077
|
execute: () => instance.fitToPage?.()
|
|
1581
2078
|
},
|
|
2079
|
+
{
|
|
2080
|
+
id: "fit-width",
|
|
2081
|
+
icon: "fit-width",
|
|
2082
|
+
label: "Fit to Width",
|
|
2083
|
+
type: "button",
|
|
2084
|
+
group: "zoom",
|
|
2085
|
+
execute: () => instance.fitToWidth?.()
|
|
2086
|
+
},
|
|
1582
2087
|
{
|
|
1583
2088
|
id: "rotate-cw",
|
|
1584
2089
|
icon: "rotate-cw",
|
|
@@ -1587,6 +2092,14 @@ var PdfPlugin = class {
|
|
|
1587
2092
|
group: "view",
|
|
1588
2093
|
execute: () => instance.rotateCW?.()
|
|
1589
2094
|
},
|
|
2095
|
+
{
|
|
2096
|
+
id: "rotate-ccw",
|
|
2097
|
+
icon: "rotate-ccw",
|
|
2098
|
+
label: "Rotate Counter-Clockwise",
|
|
2099
|
+
type: "button",
|
|
2100
|
+
group: "view",
|
|
2101
|
+
execute: () => instance.rotateCCW?.()
|
|
2102
|
+
},
|
|
1590
2103
|
{
|
|
1591
2104
|
id: "download",
|
|
1592
2105
|
icon: "download",
|
|
@@ -1618,12 +2131,13 @@ var PdfPlugin = class {
|
|
|
1618
2131
|
container.className = "fp-pdf-container";
|
|
1619
2132
|
container.style.width = "100%";
|
|
1620
2133
|
container.style.height = "100%";
|
|
1621
|
-
container.style.
|
|
2134
|
+
container.style.overflowX = "hidden";
|
|
2135
|
+
container.style.overflowY = "auto";
|
|
1622
2136
|
container.style.display = "flex";
|
|
1623
2137
|
container.style.flexDirection = "column";
|
|
1624
2138
|
container.style.alignItems = "center";
|
|
1625
2139
|
container.style.justifyContent = "flex-start";
|
|
1626
|
-
container.style.padding = "
|
|
2140
|
+
container.style.padding = "16px 8px";
|
|
1627
2141
|
container.style.backgroundColor = "#0f172a";
|
|
1628
2142
|
container.style.boxSizing = "border-box";
|
|
1629
2143
|
container.style.position = "relative";
|
|
@@ -1634,30 +2148,12 @@ var PdfPlugin = class {
|
|
|
1634
2148
|
pageCard.style.borderRadius = "4px";
|
|
1635
2149
|
pageCard.style.overflow = "hidden";
|
|
1636
2150
|
pageCard.style.lineHeight = "0";
|
|
1637
|
-
pageCard.style.transition = "transform 0.15s ease";
|
|
1638
2151
|
pageCard.style.position = "relative";
|
|
1639
2152
|
pageCard.style.flexShrink = "0";
|
|
2153
|
+
pageCard.style.transition = "box-shadow 0.2s ease";
|
|
1640
2154
|
let canvas = document.createElement("canvas");
|
|
1641
2155
|
pageCard.appendChild(canvas);
|
|
1642
2156
|
container.appendChild(pageCard);
|
|
1643
|
-
const indicator = document.createElement("div");
|
|
1644
|
-
indicator.className = "fp-pdf-page-indicator";
|
|
1645
|
-
indicator.style.position = "sticky";
|
|
1646
|
-
indicator.style.bottom = "16px";
|
|
1647
|
-
indicator.style.marginTop = "16px";
|
|
1648
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1649
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
1650
|
-
indicator.style.color = "#f8fafc";
|
|
1651
|
-
indicator.style.fontSize = "12px";
|
|
1652
|
-
indicator.style.fontWeight = "600";
|
|
1653
|
-
indicator.style.padding = "5px 14px";
|
|
1654
|
-
indicator.style.borderRadius = "20px";
|
|
1655
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1656
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1657
|
-
indicator.style.zIndex = "10";
|
|
1658
|
-
indicator.style.userSelect = "none";
|
|
1659
|
-
indicator.style.pointerEvents = "none";
|
|
1660
|
-
container.appendChild(indicator);
|
|
1661
2157
|
ctx.container.appendChild(container);
|
|
1662
2158
|
const standardFontsUrl = typeof window !== "undefined" && window.__PDF_STANDARD_FONTS_URL__ || "./standard_fonts/";
|
|
1663
2159
|
const cmapsUrl = typeof window !== "undefined" && window.__PDF_CMAPS_URL__ || "./cmaps/";
|
|
@@ -1673,8 +2169,9 @@ var PdfPlugin = class {
|
|
|
1673
2169
|
let currentPage = 1;
|
|
1674
2170
|
let zoomScale = 1;
|
|
1675
2171
|
let rotation = 0;
|
|
1676
|
-
let fitMode = "
|
|
2172
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
1677
2173
|
let currentRenderTask = null;
|
|
2174
|
+
let textLayerDiv = null;
|
|
1678
2175
|
const renderPage = async (pageNum) => {
|
|
1679
2176
|
if (currentRenderTask) {
|
|
1680
2177
|
try {
|
|
@@ -1686,30 +2183,37 @@ var PdfPlugin = class {
|
|
|
1686
2183
|
const newCanvas = document.createElement("canvas");
|
|
1687
2184
|
pageCard.replaceChild(newCanvas, canvas);
|
|
1688
2185
|
canvas = newCanvas;
|
|
2186
|
+
if (textLayerDiv) {
|
|
2187
|
+
textLayerDiv.remove();
|
|
2188
|
+
textLayerDiv = null;
|
|
2189
|
+
}
|
|
1689
2190
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1690
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1691
2191
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1692
2192
|
const page = await pdfDoc.getPage(currentPage);
|
|
1693
2193
|
const containerWidth = container.clientWidth || 900;
|
|
1694
2194
|
const containerHeight = container.clientHeight || 700;
|
|
1695
2195
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1696
|
-
const availWidth = Math.max(
|
|
1697
|
-
const availHeight = Math.max(
|
|
2196
|
+
const availWidth = Math.max(280, containerWidth - 36);
|
|
2197
|
+
const availHeight = Math.max(280, containerHeight - 32);
|
|
1698
2198
|
const scaleW = availWidth / unscaledVp.width;
|
|
1699
2199
|
const scaleH = availHeight / unscaledVp.height;
|
|
1700
2200
|
let fitScale;
|
|
1701
2201
|
if (fitMode === "page") {
|
|
1702
|
-
fitScale = Math.max(0.4, Math.min(scaleW, scaleH));
|
|
2202
|
+
fitScale = Math.max(0.2, Math.min(4, Math.min(scaleW, scaleH)));
|
|
1703
2203
|
} else {
|
|
1704
|
-
fitScale = Math.max(0.
|
|
2204
|
+
fitScale = Math.max(0.2, Math.min(4, scaleW));
|
|
1705
2205
|
}
|
|
1706
2206
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1707
2207
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1708
2208
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
2209
|
+
const displayWidth = Math.floor(viewport.width);
|
|
2210
|
+
const displayHeight = Math.floor(viewport.height);
|
|
1709
2211
|
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1710
2212
|
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1711
|
-
canvas.style.width = `${
|
|
1712
|
-
canvas.style.height = `${
|
|
2213
|
+
canvas.style.width = `${displayWidth}px`;
|
|
2214
|
+
canvas.style.height = `${displayHeight}px`;
|
|
2215
|
+
pageCard.style.width = `${displayWidth}px`;
|
|
2216
|
+
pageCard.style.height = `${displayHeight}px`;
|
|
1713
2217
|
const canvasCtx = canvas.getContext("2d");
|
|
1714
2218
|
if (!canvasCtx) return;
|
|
1715
2219
|
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
@@ -1723,9 +2227,31 @@ var PdfPlugin = class {
|
|
|
1723
2227
|
if (err?.name !== "RenderingCancelledException") {
|
|
1724
2228
|
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1725
2229
|
}
|
|
2230
|
+
return;
|
|
1726
2231
|
} finally {
|
|
1727
2232
|
currentRenderTask = null;
|
|
1728
2233
|
}
|
|
2234
|
+
try {
|
|
2235
|
+
textLayerDiv = document.createElement("div");
|
|
2236
|
+
textLayerDiv.className = "textLayer";
|
|
2237
|
+
textLayerDiv.style.width = `${displayWidth}px`;
|
|
2238
|
+
textLayerDiv.style.height = `${displayHeight}px`;
|
|
2239
|
+
textLayerDiv.style.position = "absolute";
|
|
2240
|
+
textLayerDiv.style.top = "0";
|
|
2241
|
+
textLayerDiv.style.left = "0";
|
|
2242
|
+
textLayerDiv.style.lineHeight = "1";
|
|
2243
|
+
pageCard.appendChild(textLayerDiv);
|
|
2244
|
+
if (pdfjsLib.TextLayer) {
|
|
2245
|
+
const textLayer = new pdfjsLib.TextLayer({
|
|
2246
|
+
textContentSource: page.streamTextContent(),
|
|
2247
|
+
container: textLayerDiv,
|
|
2248
|
+
viewport
|
|
2249
|
+
});
|
|
2250
|
+
await textLayer.render();
|
|
2251
|
+
}
|
|
2252
|
+
} catch (err) {
|
|
2253
|
+
console.debug("[PdfPlugin] TextLayer notice:", err);
|
|
2254
|
+
}
|
|
1729
2255
|
};
|
|
1730
2256
|
renderPage(1);
|
|
1731
2257
|
let resizeTimer = null;
|
|
@@ -1735,11 +2261,48 @@ var PdfPlugin = class {
|
|
|
1735
2261
|
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1736
2262
|
renderPage(currentPage);
|
|
1737
2263
|
}
|
|
1738
|
-
},
|
|
2264
|
+
}, 120);
|
|
1739
2265
|
});
|
|
1740
2266
|
resizeObserver.observe(container);
|
|
2267
|
+
const onWheel = (e) => {
|
|
2268
|
+
if (e.ctrlKey || e.metaKey) {
|
|
2269
|
+
e.preventDefault();
|
|
2270
|
+
const delta = e.deltaY > 0 ? -0.15 : 0.15;
|
|
2271
|
+
zoomScale = Math.max(0.25, Math.min(4, Math.round((zoomScale + delta) * 100) / 100));
|
|
2272
|
+
renderPage(currentPage);
|
|
2273
|
+
}
|
|
2274
|
+
};
|
|
2275
|
+
container.addEventListener("wheel", onWheel, { passive: false });
|
|
2276
|
+
const onKeyDown = (e) => {
|
|
2277
|
+
const tag = e.target?.tagName?.toLowerCase();
|
|
2278
|
+
if (tag === "input" || tag === "textarea" || tag === "select") return;
|
|
2279
|
+
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
2280
|
+
if (currentPage < totalPages) {
|
|
2281
|
+
e.preventDefault();
|
|
2282
|
+
container.scrollTop = 0;
|
|
2283
|
+
renderPage(currentPage + 1);
|
|
2284
|
+
}
|
|
2285
|
+
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
2286
|
+
if (currentPage > 1) {
|
|
2287
|
+
e.preventDefault();
|
|
2288
|
+
container.scrollTop = 0;
|
|
2289
|
+
renderPage(currentPage - 1);
|
|
2290
|
+
}
|
|
2291
|
+
} else if (e.key === "Home") {
|
|
2292
|
+
e.preventDefault();
|
|
2293
|
+
container.scrollTop = 0;
|
|
2294
|
+
renderPage(1);
|
|
2295
|
+
} else if (e.key === "End") {
|
|
2296
|
+
e.preventDefault();
|
|
2297
|
+
container.scrollTop = 0;
|
|
2298
|
+
renderPage(totalPages);
|
|
2299
|
+
}
|
|
2300
|
+
};
|
|
2301
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1741
2302
|
const cleanup = () => {
|
|
1742
2303
|
resizeObserver.disconnect();
|
|
2304
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
2305
|
+
container.removeEventListener("wheel", onWheel);
|
|
1743
2306
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1744
2307
|
if (currentRenderTask) {
|
|
1745
2308
|
try {
|
|
@@ -1758,22 +2321,26 @@ var PdfPlugin = class {
|
|
|
1758
2321
|
const instance = {
|
|
1759
2322
|
destroy: cleanup,
|
|
1760
2323
|
zoomIn: () => {
|
|
1761
|
-
zoomScale = Math.min(
|
|
2324
|
+
zoomScale = Math.min(4, Math.round((zoomScale + 0.2) * 10) / 10);
|
|
1762
2325
|
renderPage(currentPage);
|
|
1763
2326
|
},
|
|
1764
2327
|
zoomOut: () => {
|
|
1765
|
-
zoomScale = Math.max(0.
|
|
2328
|
+
zoomScale = Math.max(0.25, Math.round((zoomScale - 0.2) * 10) / 10);
|
|
1766
2329
|
renderPage(currentPage);
|
|
1767
2330
|
},
|
|
1768
2331
|
getZoom: () => zoomScale,
|
|
1769
2332
|
setZoom: (level) => {
|
|
1770
|
-
zoomScale = Math.max(0.
|
|
2333
|
+
zoomScale = Math.max(0.25, Math.min(4, level));
|
|
1771
2334
|
renderPage(currentPage);
|
|
1772
2335
|
},
|
|
1773
2336
|
fitToPage: () => {
|
|
1774
|
-
fitMode =
|
|
2337
|
+
fitMode = "page";
|
|
2338
|
+
zoomScale = 1;
|
|
2339
|
+
renderPage(currentPage);
|
|
2340
|
+
},
|
|
2341
|
+
fitToWidth: () => {
|
|
2342
|
+
fitMode = "width";
|
|
1775
2343
|
zoomScale = 1;
|
|
1776
|
-
rotation = 0;
|
|
1777
2344
|
renderPage(currentPage);
|
|
1778
2345
|
},
|
|
1779
2346
|
rotateCW: () => {
|
|
@@ -1791,6 +2358,9 @@ var PdfPlugin = class {
|
|
|
1791
2358
|
container.scrollTop = 0;
|
|
1792
2359
|
renderPage(page);
|
|
1793
2360
|
},
|
|
2361
|
+
toggleThumbnails: () => {
|
|
2362
|
+
ctx?.toggleThumbnails?.();
|
|
2363
|
+
},
|
|
1794
2364
|
download: () => {
|
|
1795
2365
|
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1796
2366
|
const url = URL.createObjectURL(blob);
|
|
@@ -1824,7 +2394,7 @@ var PdfPlugin = class {
|
|
|
1824
2394
|
},
|
|
1825
2395
|
getThumbnails: async () => {
|
|
1826
2396
|
const thumbnails = [];
|
|
1827
|
-
const count =
|
|
2397
|
+
const count = totalPages;
|
|
1828
2398
|
for (let i = 1; i <= count; i++) {
|
|
1829
2399
|
thumbnails.push({
|
|
1830
2400
|
index: i,
|
|
@@ -1832,9 +2402,10 @@ var PdfPlugin = class {
|
|
|
1832
2402
|
render: async (thumbCanvas) => {
|
|
1833
2403
|
try {
|
|
1834
2404
|
const p = await pdfDoc.getPage(i);
|
|
1835
|
-
const baseVp = p.getViewport({ scale: 1 });
|
|
1836
|
-
const
|
|
1837
|
-
const
|
|
2405
|
+
const baseVp = p.getViewport({ scale: 1, rotation });
|
|
2406
|
+
const targetW = thumbCanvas.width || 130;
|
|
2407
|
+
const thumbScale = targetW / baseVp.width;
|
|
2408
|
+
const thumbVp = p.getViewport({ scale: thumbScale, rotation });
|
|
1838
2409
|
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1839
2410
|
const tCtx = thumbCanvas.getContext("2d");
|
|
1840
2411
|
if (tCtx) {
|
|
@@ -2178,28 +2749,26 @@ var DocxPlugin = class {
|
|
|
2178
2749
|
getToolbarActions(instance) {
|
|
2179
2750
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2180
2751
|
const actions = [];
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
if (
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
instance.goToPage?.(page);
|
|
2199
|
-
}
|
|
2752
|
+
actions.push({
|
|
2753
|
+
id: "page-nav",
|
|
2754
|
+
icon: "",
|
|
2755
|
+
label: "Page Navigation",
|
|
2756
|
+
type: "page-nav",
|
|
2757
|
+
group: "navigation",
|
|
2758
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2759
|
+
max: totalPages,
|
|
2760
|
+
execute: (action, page) => {
|
|
2761
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2762
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2763
|
+
if (action === "prev") {
|
|
2764
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2765
|
+
} else if (action === "next") {
|
|
2766
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2767
|
+
} else if (typeof page === "number") {
|
|
2768
|
+
instance.goToPage?.(page);
|
|
2200
2769
|
}
|
|
2201
|
-
}
|
|
2202
|
-
}
|
|
2770
|
+
}
|
|
2771
|
+
});
|
|
2203
2772
|
actions.push(
|
|
2204
2773
|
{
|
|
2205
2774
|
id: "zoom-out",
|
|
@@ -2265,11 +2834,17 @@ var DocxPlugin = class {
|
|
|
2265
2834
|
wrapper.className = "fp-docx-wrapper";
|
|
2266
2835
|
wrapper.style.transformOrigin = "top center";
|
|
2267
2836
|
wrapper.style.transition = "transform 0.2s ease";
|
|
2268
|
-
wrapper.style.padding = "
|
|
2269
|
-
wrapper.style.maxWidth = "
|
|
2837
|
+
wrapper.style.padding = "0";
|
|
2838
|
+
wrapper.style.maxWidth = "none";
|
|
2839
|
+
wrapper.style.width = "816px";
|
|
2270
2840
|
wrapper.style.margin = "0 auto";
|
|
2841
|
+
wrapper.style.display = "flex";
|
|
2842
|
+
wrapper.style.flexDirection = "column";
|
|
2843
|
+
wrapper.style.alignItems = "center";
|
|
2271
2844
|
wrapper.style.boxSizing = "border-box";
|
|
2272
|
-
ctx.container.style.
|
|
2845
|
+
ctx.container.style.overflowX = "hidden";
|
|
2846
|
+
ctx.container.style.overflowY = "auto";
|
|
2847
|
+
ctx.container.style.padding = "16px 8px";
|
|
2273
2848
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
2274
2849
|
ctx.container.appendChild(wrapper);
|
|
2275
2850
|
const styleOverride = document.createElement("style");
|
|
@@ -2443,39 +3018,13 @@ var DocxPlugin = class {
|
|
|
2443
3018
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2444
3019
|
const totalPages = Math.max(1, pageElements.length);
|
|
2445
3020
|
let currentPage = 1;
|
|
2446
|
-
let indicator = null;
|
|
2447
|
-
if (totalPages > 1) {
|
|
2448
|
-
indicator = document.createElement("div");
|
|
2449
|
-
indicator.className = "fp-docx-page-indicator";
|
|
2450
|
-
indicator.style.position = "sticky";
|
|
2451
|
-
indicator.style.bottom = "16px";
|
|
2452
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2453
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
2454
|
-
indicator.style.color = "#f8fafc";
|
|
2455
|
-
indicator.style.fontSize = "12px";
|
|
2456
|
-
indicator.style.fontWeight = "600";
|
|
2457
|
-
indicator.style.padding = "5px 14px";
|
|
2458
|
-
indicator.style.borderRadius = "20px";
|
|
2459
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2460
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2461
|
-
indicator.style.zIndex = "10";
|
|
2462
|
-
indicator.style.userSelect = "none";
|
|
2463
|
-
indicator.style.pointerEvents = "none";
|
|
2464
|
-
indicator.style.textAlign = "center";
|
|
2465
|
-
indicator.style.width = "fit-content";
|
|
2466
|
-
indicator.style.margin = "16px auto 0";
|
|
2467
|
-
ctx.container.appendChild(indicator);
|
|
2468
|
-
}
|
|
2469
3021
|
const showPage = (pageNum) => {
|
|
2470
3022
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2471
3023
|
if (pageElements.length > 1) {
|
|
2472
3024
|
pageElements.forEach((sec, idx) => {
|
|
2473
|
-
sec.style.display = idx + 1 === currentPage ? "
|
|
3025
|
+
sec.style.display = idx + 1 === currentPage ? "" : "none";
|
|
2474
3026
|
});
|
|
2475
3027
|
}
|
|
2476
|
-
if (indicator) {
|
|
2477
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2478
|
-
}
|
|
2479
3028
|
ctx.container.scrollTop = 0;
|
|
2480
3029
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2481
3030
|
};
|
|
@@ -2484,31 +3033,46 @@ var DocxPlugin = class {
|
|
|
2484
3033
|
}
|
|
2485
3034
|
scale = 1;
|
|
2486
3035
|
let rotation = 0;
|
|
2487
|
-
let fitMode = "
|
|
2488
|
-
|
|
2489
|
-
|
|
3036
|
+
let fitMode = "page";
|
|
3037
|
+
let isUserZoomed = false;
|
|
3038
|
+
const calculateFitScale = (_mode = fitMode) => {
|
|
3039
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
2490
3040
|
const elW = activeEl.offsetWidth || 816;
|
|
2491
|
-
const
|
|
2492
|
-
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
2493
|
-
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
3041
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
2494
3042
|
const sW = availW / elW;
|
|
2495
|
-
|
|
2496
|
-
if (mode === "page") {
|
|
2497
|
-
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
2498
|
-
}
|
|
2499
|
-
return Math.max(0.65, Math.min(1.05, sW));
|
|
3043
|
+
return Math.max(0.35, Math.min(3, sW));
|
|
2500
3044
|
};
|
|
2501
3045
|
const applyTransform = () => {
|
|
2502
3046
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2503
3047
|
wrapper.style.transformOrigin = "top center";
|
|
3048
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
3049
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
3050
|
+
if (scale > 1) {
|
|
3051
|
+
wrapper.style.marginBottom = `${Math.round(elH * scale - elH + 32)}px`;
|
|
3052
|
+
} else {
|
|
3053
|
+
wrapper.style.marginBottom = "32px";
|
|
3054
|
+
}
|
|
2504
3055
|
};
|
|
3056
|
+
let resizeObserver = null;
|
|
3057
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
3058
|
+
resizeObserver = new ResizeObserver(() => {
|
|
3059
|
+
if (!isUserZoomed) {
|
|
3060
|
+
const newFit = calculateFitScale("page");
|
|
3061
|
+
if (Math.abs(scale - newFit) > 0.015) {
|
|
3062
|
+
scale = newFit;
|
|
3063
|
+
applyTransform();
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
});
|
|
3067
|
+
resizeObserver.observe(ctx.container);
|
|
3068
|
+
}
|
|
2505
3069
|
setTimeout(() => {
|
|
2506
|
-
|
|
2507
|
-
scale = calculateFitScale("width");
|
|
3070
|
+
scale = calculateFitScale("page");
|
|
2508
3071
|
applyTransform();
|
|
2509
|
-
},
|
|
3072
|
+
}, 40);
|
|
2510
3073
|
const cleanup = () => {
|
|
2511
|
-
|
|
3074
|
+
resizeObserver?.disconnect();
|
|
3075
|
+
resizeObserver = null;
|
|
2512
3076
|
for (const url of createdBlobUrls) {
|
|
2513
3077
|
URL.revokeObjectURL(url);
|
|
2514
3078
|
}
|
|
@@ -2525,21 +3089,24 @@ var DocxPlugin = class {
|
|
|
2525
3089
|
showPage(page);
|
|
2526
3090
|
},
|
|
2527
3091
|
zoomIn: () => {
|
|
2528
|
-
|
|
3092
|
+
isUserZoomed = true;
|
|
3093
|
+
scale = Math.min(3.5, scale + 0.15);
|
|
2529
3094
|
applyTransform();
|
|
2530
3095
|
},
|
|
2531
3096
|
zoomOut: () => {
|
|
3097
|
+
isUserZoomed = true;
|
|
2532
3098
|
scale = Math.max(0.2, scale - 0.15);
|
|
2533
3099
|
applyTransform();
|
|
2534
3100
|
},
|
|
2535
3101
|
getZoom: () => scale,
|
|
2536
3102
|
setZoom: (level) => {
|
|
3103
|
+
isUserZoomed = true;
|
|
2537
3104
|
scale = level;
|
|
2538
3105
|
applyTransform();
|
|
2539
3106
|
},
|
|
2540
3107
|
fitToPage: () => {
|
|
2541
|
-
|
|
2542
|
-
scale = calculateFitScale(
|
|
3108
|
+
isUserZoomed = false;
|
|
3109
|
+
scale = calculateFitScale("page");
|
|
2543
3110
|
rotation = 0;
|
|
2544
3111
|
applyTransform();
|
|
2545
3112
|
},
|
|
@@ -2929,7 +3496,7 @@ var ExcelPlugin = class {
|
|
|
2929
3496
|
"application/vnd.ms-excel.template.macroEnabled.12",
|
|
2930
3497
|
"application/vnd.oasis.opendocument.spreadsheet"
|
|
2931
3498
|
];
|
|
2932
|
-
weight =
|
|
3499
|
+
weight = 85;
|
|
2933
3500
|
supports(file) {
|
|
2934
3501
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2935
3502
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
@@ -2941,6 +3508,14 @@ var ExcelPlugin = class {
|
|
|
2941
3508
|
getToolbarActions(instance) {
|
|
2942
3509
|
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2943
3510
|
const actions = [];
|
|
3511
|
+
actions.push({
|
|
3512
|
+
id: "thumbnails",
|
|
3513
|
+
icon: "thumbnails",
|
|
3514
|
+
label: "Sheet Thumbnails",
|
|
3515
|
+
type: "button",
|
|
3516
|
+
group: "navigation",
|
|
3517
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3518
|
+
});
|
|
2944
3519
|
if (totalSheets > 1) {
|
|
2945
3520
|
actions.push({
|
|
2946
3521
|
id: "page-nav",
|
|
@@ -3023,6 +3598,16 @@ var ExcelPlugin = class {
|
|
|
3023
3598
|
execute: () => {
|
|
3024
3599
|
instance.print?.();
|
|
3025
3600
|
}
|
|
3601
|
+
},
|
|
3602
|
+
{
|
|
3603
|
+
id: "open-window",
|
|
3604
|
+
icon: "open-window",
|
|
3605
|
+
label: "Open in Separate Full Window",
|
|
3606
|
+
type: "button",
|
|
3607
|
+
group: "actions",
|
|
3608
|
+
execute: () => {
|
|
3609
|
+
instance.openInSeparateWindow?.();
|
|
3610
|
+
}
|
|
3026
3611
|
}
|
|
3027
3612
|
);
|
|
3028
3613
|
return actions;
|
|
@@ -3188,6 +3773,63 @@ var ExcelPlugin = class {
|
|
|
3188
3773
|
},
|
|
3189
3774
|
getPageCount: () => sheetNames.length,
|
|
3190
3775
|
getCurrentPage: () => currentSheetIndex,
|
|
3776
|
+
getThumbnails: () => {
|
|
3777
|
+
return sheetNames.map((name, idx) => ({
|
|
3778
|
+
index: idx,
|
|
3779
|
+
label: name,
|
|
3780
|
+
render: async (canvas) => {
|
|
3781
|
+
canvas.width = 140;
|
|
3782
|
+
canvas.height = 100;
|
|
3783
|
+
const c = canvas.getContext("2d");
|
|
3784
|
+
if (!c) return;
|
|
3785
|
+
c.fillStyle = "#ffffff";
|
|
3786
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
3787
|
+
c.fillStyle = "#107c41";
|
|
3788
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
3789
|
+
c.fillStyle = "#ffffff";
|
|
3790
|
+
c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
3791
|
+
c.fillText(`\u{1F4CA} ${name.slice(0, 16)}`, 6, 11);
|
|
3792
|
+
const startY = 17;
|
|
3793
|
+
const rowH = 13;
|
|
3794
|
+
const colW = 30;
|
|
3795
|
+
const colHeaders = ["A", "B", "C", "D"];
|
|
3796
|
+
c.fillStyle = "#f1f5f9";
|
|
3797
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
3798
|
+
c.strokeStyle = "#cbd5e1";
|
|
3799
|
+
c.lineWidth = 0.8;
|
|
3800
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
3801
|
+
c.fillStyle = "#64748b";
|
|
3802
|
+
c.font = "bold 7px sans-serif";
|
|
3803
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3804
|
+
c.fillText(colHeaders[ci], 14 + ci * colW, startY + 9);
|
|
3805
|
+
}
|
|
3806
|
+
const ws = wb?.Sheets[name];
|
|
3807
|
+
for (let ri = 1; ri <= 5; ri++) {
|
|
3808
|
+
const y = startY + ri * rowH;
|
|
3809
|
+
if (y > canvas.height - 2) break;
|
|
3810
|
+
c.fillStyle = "#f8fafc";
|
|
3811
|
+
c.fillRect(0, y, 12, rowH);
|
|
3812
|
+
c.fillStyle = "#94a3b8";
|
|
3813
|
+
c.font = "6px sans-serif";
|
|
3814
|
+
c.fillText(String(ri), 3, y + 9);
|
|
3815
|
+
c.strokeStyle = "#e2e8f0";
|
|
3816
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
3817
|
+
c.fillStyle = "#334155";
|
|
3818
|
+
c.font = "6px sans-serif";
|
|
3819
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3820
|
+
const cellRef = `${colHeaders[ci]}${ri}`;
|
|
3821
|
+
const cellVal = ws?.[cellRef]?.w || ws?.[cellRef]?.v;
|
|
3822
|
+
if (cellVal !== void 0) {
|
|
3823
|
+
c.fillText(String(cellVal).slice(0, 6), 14 + ci * colW, y + 9);
|
|
3824
|
+
}
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3827
|
+
c.strokeStyle = "#cbd5e1";
|
|
3828
|
+
c.lineWidth = 1;
|
|
3829
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
3830
|
+
}
|
|
3831
|
+
}));
|
|
3832
|
+
},
|
|
3191
3833
|
download: () => {
|
|
3192
3834
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
3193
3835
|
const url = URL.createObjectURL(blob);
|
|
@@ -3220,7 +3862,39 @@ var CsvPlugin = class {
|
|
|
3220
3862
|
return ext === ".csv" || ext === ".tsv" || mime === "text/csv" || mime === "text/tab-separated-values";
|
|
3221
3863
|
}
|
|
3222
3864
|
getToolbarActions(instance) {
|
|
3223
|
-
|
|
3865
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3866
|
+
const actions = [];
|
|
3867
|
+
actions.push({
|
|
3868
|
+
id: "thumbnails",
|
|
3869
|
+
icon: "thumbnails",
|
|
3870
|
+
label: "Page Thumbnails",
|
|
3871
|
+
type: "button",
|
|
3872
|
+
group: "navigation",
|
|
3873
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3874
|
+
});
|
|
3875
|
+
if (totalPages > 1) {
|
|
3876
|
+
actions.push({
|
|
3877
|
+
id: "page-nav",
|
|
3878
|
+
icon: "",
|
|
3879
|
+
label: "Page Navigation",
|
|
3880
|
+
type: "page-nav",
|
|
3881
|
+
group: "navigation",
|
|
3882
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3883
|
+
max: totalPages,
|
|
3884
|
+
execute: (action, page) => {
|
|
3885
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3886
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
3887
|
+
if (action === "prev") {
|
|
3888
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3889
|
+
} else if (action === "next") {
|
|
3890
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
3891
|
+
} else if (typeof page === "number") {
|
|
3892
|
+
instance.goToPage?.(page);
|
|
3893
|
+
}
|
|
3894
|
+
}
|
|
3895
|
+
});
|
|
3896
|
+
}
|
|
3897
|
+
actions.push(
|
|
3224
3898
|
{
|
|
3225
3899
|
id: "zoom-out",
|
|
3226
3900
|
icon: "zoom-out",
|
|
@@ -3241,6 +3915,16 @@ var CsvPlugin = class {
|
|
|
3241
3915
|
instance.zoomIn?.();
|
|
3242
3916
|
}
|
|
3243
3917
|
},
|
|
3918
|
+
{
|
|
3919
|
+
id: "fit-page",
|
|
3920
|
+
icon: "fit-page",
|
|
3921
|
+
label: "Fit to View",
|
|
3922
|
+
type: "button",
|
|
3923
|
+
group: "zoom",
|
|
3924
|
+
execute: () => {
|
|
3925
|
+
instance.fitToPage?.();
|
|
3926
|
+
}
|
|
3927
|
+
},
|
|
3244
3928
|
{
|
|
3245
3929
|
id: "download",
|
|
3246
3930
|
icon: "download",
|
|
@@ -3260,8 +3944,19 @@ var CsvPlugin = class {
|
|
|
3260
3944
|
execute: () => {
|
|
3261
3945
|
instance.print?.();
|
|
3262
3946
|
}
|
|
3947
|
+
},
|
|
3948
|
+
{
|
|
3949
|
+
id: "open-window",
|
|
3950
|
+
icon: "open-window",
|
|
3951
|
+
label: "Open in Separate Full Window",
|
|
3952
|
+
type: "button",
|
|
3953
|
+
group: "actions",
|
|
3954
|
+
execute: () => {
|
|
3955
|
+
instance.openInSeparateWindow?.();
|
|
3956
|
+
}
|
|
3263
3957
|
}
|
|
3264
|
-
|
|
3958
|
+
);
|
|
3959
|
+
return actions;
|
|
3265
3960
|
}
|
|
3266
3961
|
async render(ctx) {
|
|
3267
3962
|
const decoder = new TextDecoder("utf-8");
|
|
@@ -3273,33 +3968,62 @@ var CsvPlugin = class {
|
|
|
3273
3968
|
container.style.padding = "16px";
|
|
3274
3969
|
container.style.boxSizing = "border-box";
|
|
3275
3970
|
container.style.transformOrigin = "top left";
|
|
3971
|
+
const delimiter = ctx.metadata.extension === ".tsv" ? " " : ",";
|
|
3972
|
+
const allLines = text.split(/\r?\n/).filter((r) => r.trim().length > 0);
|
|
3973
|
+
const headerLine = allLines[0] || "";
|
|
3974
|
+
const headerCells = headerLine.split(delimiter);
|
|
3975
|
+
const dataLines = allLines.slice(1);
|
|
3976
|
+
const ROWS_PER_PAGE = 100;
|
|
3977
|
+
const totalPages = Math.max(1, Math.ceil(dataLines.length / ROWS_PER_PAGE));
|
|
3978
|
+
let currentPage = 1;
|
|
3276
3979
|
const table = document.createElement("table");
|
|
3277
3980
|
table.style.borderCollapse = "collapse";
|
|
3278
3981
|
table.style.width = "100%";
|
|
3279
|
-
table.style.fontFamily = "monospace
|
|
3982
|
+
table.style.fontFamily = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace';
|
|
3280
3983
|
table.style.fontSize = "13px";
|
|
3281
|
-
const
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
td.style.fontWeight = "bold";
|
|
3295
|
-
}
|
|
3296
|
-
tr.appendChild(td);
|
|
3984
|
+
const renderPage = (pageNum) => {
|
|
3985
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3986
|
+
table.innerHTML = "";
|
|
3987
|
+
const headerTr = document.createElement("tr");
|
|
3988
|
+
headerCells.forEach((cell) => {
|
|
3989
|
+
const th = document.createElement("th");
|
|
3990
|
+
th.textContent = cell.trim();
|
|
3991
|
+
th.style.border = "1px solid #d0d7de";
|
|
3992
|
+
th.style.padding = "8px 12px";
|
|
3993
|
+
th.style.backgroundColor = "#f6f8fa";
|
|
3994
|
+
th.style.fontWeight = "600";
|
|
3995
|
+
th.style.whiteSpace = "nowrap";
|
|
3996
|
+
headerTr.appendChild(th);
|
|
3297
3997
|
});
|
|
3298
|
-
table.appendChild(
|
|
3299
|
-
|
|
3998
|
+
table.appendChild(headerTr);
|
|
3999
|
+
const start = (currentPage - 1) * ROWS_PER_PAGE;
|
|
4000
|
+
const end = Math.min(dataLines.length, start + ROWS_PER_PAGE);
|
|
4001
|
+
const pageRows = dataLines.slice(start, end);
|
|
4002
|
+
pageRows.forEach((row, idx) => {
|
|
4003
|
+
const tr = document.createElement("tr");
|
|
4004
|
+
if (idx % 2 === 1) tr.style.backgroundColor = "#f8fafc";
|
|
4005
|
+
const cells = row.split(delimiter);
|
|
4006
|
+
cells.forEach((cell) => {
|
|
4007
|
+
const td = document.createElement("td");
|
|
4008
|
+
td.textContent = cell.trim();
|
|
4009
|
+
td.style.border = "1px solid #d0d7de";
|
|
4010
|
+
td.style.padding = "6px 12px";
|
|
4011
|
+
td.style.whiteSpace = "nowrap";
|
|
4012
|
+
tr.appendChild(td);
|
|
4013
|
+
});
|
|
4014
|
+
table.appendChild(tr);
|
|
4015
|
+
});
|
|
4016
|
+
container.scrollTop = 0;
|
|
4017
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4018
|
+
};
|
|
4019
|
+
renderPage(1);
|
|
3300
4020
|
container.appendChild(table);
|
|
3301
4021
|
ctx.container.appendChild(container);
|
|
3302
4022
|
let scale = 1;
|
|
4023
|
+
const applyScale = () => {
|
|
4024
|
+
container.style.transform = `scale(${scale})`;
|
|
4025
|
+
container.style.transformOrigin = "top left";
|
|
4026
|
+
};
|
|
3303
4027
|
const cleanup = () => {
|
|
3304
4028
|
container.remove();
|
|
3305
4029
|
ctx.container.innerHTML = "";
|
|
@@ -3307,22 +4031,86 @@ var CsvPlugin = class {
|
|
|
3307
4031
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3308
4032
|
return {
|
|
3309
4033
|
destroy: cleanup,
|
|
4034
|
+
getPageCount: () => totalPages,
|
|
4035
|
+
getCurrentPage: () => currentPage,
|
|
4036
|
+
goToPage: (page) => renderPage(page),
|
|
4037
|
+
getThumbnails: () => {
|
|
4038
|
+
const thumbnails = [];
|
|
4039
|
+
for (let i = 0; i < totalPages; i++) {
|
|
4040
|
+
const pageIdx = i;
|
|
4041
|
+
const startRow = pageIdx * ROWS_PER_PAGE + 1;
|
|
4042
|
+
const endRow = Math.min(dataLines.length, (pageIdx + 1) * ROWS_PER_PAGE);
|
|
4043
|
+
const label = totalPages === 1 ? "Table" : `Page ${pageIdx + 1} (${startRow}-${endRow})`;
|
|
4044
|
+
thumbnails.push({
|
|
4045
|
+
index: pageIdx,
|
|
4046
|
+
label,
|
|
4047
|
+
render: async (canvas) => {
|
|
4048
|
+
canvas.width = 140;
|
|
4049
|
+
canvas.height = 100;
|
|
4050
|
+
const c = canvas.getContext("2d");
|
|
4051
|
+
if (!c) return;
|
|
4052
|
+
c.fillStyle = "#ffffff";
|
|
4053
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4054
|
+
c.fillStyle = "#2563eb";
|
|
4055
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
4056
|
+
c.fillStyle = "#ffffff";
|
|
4057
|
+
c.font = "bold 8px sans-serif";
|
|
4058
|
+
c.fillText(`\u{1F4C8} ${label.slice(0, 18)}`, 6, 11);
|
|
4059
|
+
const startY = 17;
|
|
4060
|
+
const rowH = 13;
|
|
4061
|
+
const colW = 28;
|
|
4062
|
+
const cols = Math.min(4, headerCells.length || 4);
|
|
4063
|
+
c.fillStyle = "#f1f5f9";
|
|
4064
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
4065
|
+
c.strokeStyle = "#cbd5e1";
|
|
4066
|
+
c.lineWidth = 0.8;
|
|
4067
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
4068
|
+
c.fillStyle = "#64748b";
|
|
4069
|
+
c.font = "bold 7px sans-serif";
|
|
4070
|
+
for (let ci = 0; ci < cols; ci++) {
|
|
4071
|
+
const hName = headerCells[ci] || `Col ${ci + 1}`;
|
|
4072
|
+
c.fillText(hName.slice(0, 5), 8 + ci * colW, startY + 9);
|
|
4073
|
+
}
|
|
4074
|
+
const rowsToPreview = dataLines.slice(pageIdx * ROWS_PER_PAGE, pageIdx * ROWS_PER_PAGE + 5);
|
|
4075
|
+
for (let ri = 0; ri < rowsToPreview.length; ri++) {
|
|
4076
|
+
const y = startY + (ri + 1) * rowH;
|
|
4077
|
+
if (y > canvas.height - 2) break;
|
|
4078
|
+
c.strokeStyle = "#e2e8f0";
|
|
4079
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
4080
|
+
const cVals = rowsToPreview[ri].split(delimiter);
|
|
4081
|
+
c.fillStyle = "#334155";
|
|
4082
|
+
c.font = "6px sans-serif";
|
|
4083
|
+
for (let ci = 0; ci < cols; ci++) {
|
|
4084
|
+
const val = cVals[ci] || "";
|
|
4085
|
+
c.fillText(val.trim().slice(0, 6), 8 + ci * colW, y + 9);
|
|
4086
|
+
}
|
|
4087
|
+
}
|
|
4088
|
+
c.strokeStyle = "#cbd5e1";
|
|
4089
|
+
c.lineWidth = 1;
|
|
4090
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4091
|
+
}
|
|
4092
|
+
});
|
|
4093
|
+
}
|
|
4094
|
+
return thumbnails;
|
|
4095
|
+
},
|
|
3310
4096
|
zoomIn: () => {
|
|
3311
4097
|
scale += 0.1;
|
|
3312
|
-
|
|
4098
|
+
applyScale();
|
|
3313
4099
|
},
|
|
3314
4100
|
zoomOut: () => {
|
|
3315
4101
|
scale = Math.max(0.2, scale - 0.1);
|
|
3316
|
-
|
|
4102
|
+
applyScale();
|
|
3317
4103
|
},
|
|
3318
4104
|
getZoom: () => scale,
|
|
3319
4105
|
setZoom: (level) => {
|
|
3320
4106
|
scale = level;
|
|
3321
|
-
|
|
4107
|
+
applyScale();
|
|
3322
4108
|
},
|
|
3323
4109
|
fitToPage: () => {
|
|
3324
|
-
|
|
3325
|
-
|
|
4110
|
+
const availW = Math.max(280, (ctx.container.clientWidth || window.innerWidth) - 48);
|
|
4111
|
+
const tW = table.offsetWidth || 600;
|
|
4112
|
+
scale = Math.max(0.35, Math.min(1, availW / tW));
|
|
4113
|
+
applyScale();
|
|
3326
4114
|
},
|
|
3327
4115
|
download: () => {
|
|
3328
4116
|
const blob = new Blob([ctx.buffer], { type: "text/csv" });
|
|
@@ -3386,28 +4174,34 @@ var CodePlugin = class {
|
|
|
3386
4174
|
getToolbarActions(instance) {
|
|
3387
4175
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3388
4176
|
const actions = [];
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
4177
|
+
actions.push({
|
|
4178
|
+
id: "thumbnails",
|
|
4179
|
+
icon: "thumbnails",
|
|
4180
|
+
label: "Page Thumbnails",
|
|
4181
|
+
type: "button",
|
|
4182
|
+
group: "navigation",
|
|
4183
|
+
execute: () => instance.toggleThumbnails?.()
|
|
4184
|
+
});
|
|
4185
|
+
actions.push({
|
|
4186
|
+
id: "page-nav",
|
|
4187
|
+
icon: "",
|
|
4188
|
+
label: "Page Navigation",
|
|
4189
|
+
type: "page-nav",
|
|
4190
|
+
group: "navigation",
|
|
4191
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4192
|
+
max: totalPages,
|
|
4193
|
+
execute: (action, page) => {
|
|
4194
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4195
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4196
|
+
if (action === "prev") {
|
|
4197
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4198
|
+
} else if (action === "next") {
|
|
4199
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4200
|
+
} else if (typeof page === "number") {
|
|
4201
|
+
instance.goToPage?.(page);
|
|
3408
4202
|
}
|
|
3409
|
-
}
|
|
3410
|
-
}
|
|
4203
|
+
}
|
|
4204
|
+
});
|
|
3411
4205
|
actions.push(
|
|
3412
4206
|
{
|
|
3413
4207
|
id: "zoom-out",
|
|
@@ -3551,16 +4345,19 @@ var CodePlugin = class {
|
|
|
3551
4345
|
let fontSize = 13;
|
|
3552
4346
|
let rotation = 0;
|
|
3553
4347
|
let zoomLevel = 1;
|
|
4348
|
+
let isUserZoomed = false;
|
|
3554
4349
|
const pre = document.createElement("pre");
|
|
3555
4350
|
const code = document.createElement("code");
|
|
3556
4351
|
if (isTxt) {
|
|
4352
|
+
container.style.overflowX = "hidden";
|
|
4353
|
+
container.style.overflowY = "auto";
|
|
3557
4354
|
container.style.backgroundColor = "#f1f5f9";
|
|
3558
|
-
container.style.padding = "
|
|
4355
|
+
container.style.padding = "16px 8px";
|
|
3559
4356
|
container.style.boxSizing = "border-box";
|
|
3560
4357
|
container.style.display = "flex";
|
|
3561
4358
|
container.style.flexDirection = "column";
|
|
3562
4359
|
container.style.alignItems = "center";
|
|
3563
|
-
pre.style.margin = "0";
|
|
4360
|
+
pre.style.margin = "0 auto";
|
|
3564
4361
|
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3565
4362
|
pre.style.fontSize = "13px";
|
|
3566
4363
|
pre.style.color = "#1e293b";
|
|
@@ -3572,10 +4369,12 @@ var CodePlugin = class {
|
|
|
3572
4369
|
pre.style.minHeight = "1056px";
|
|
3573
4370
|
pre.style.padding = "72px 56px";
|
|
3574
4371
|
pre.style.boxSizing = "border-box";
|
|
3575
|
-
pre.style.boxShadow = "0 4px
|
|
4372
|
+
pre.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
3576
4373
|
pre.style.borderRadius = "4px";
|
|
3577
4374
|
pre.style.transformOrigin = "top center";
|
|
4375
|
+
pre.style.transition = "transform 0.15s ease";
|
|
3578
4376
|
} else {
|
|
4377
|
+
container.style.overflow = "auto";
|
|
3579
4378
|
container.style.backgroundColor = "#1e1e1e";
|
|
3580
4379
|
container.style.color = "#d4d4d4";
|
|
3581
4380
|
container.style.padding = "16px";
|
|
@@ -3607,42 +4406,9 @@ var CodePlugin = class {
|
|
|
3607
4406
|
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
3608
4407
|
pre.appendChild(code);
|
|
3609
4408
|
container.appendChild(pre);
|
|
3610
|
-
let indicator = null;
|
|
3611
|
-
if (totalPages > 1) {
|
|
3612
|
-
indicator = document.createElement("div");
|
|
3613
|
-
indicator.className = "fp-code-page-indicator";
|
|
3614
|
-
indicator.style.position = "sticky";
|
|
3615
|
-
indicator.style.bottom = "16px";
|
|
3616
|
-
if (isTxt) {
|
|
3617
|
-
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3618
|
-
indicator.style.color = "#334155";
|
|
3619
|
-
indicator.style.border = "1px solid #e2e8f0";
|
|
3620
|
-
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3621
|
-
} else {
|
|
3622
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3623
|
-
indicator.style.color = "#f8fafc";
|
|
3624
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3625
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3626
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
3627
|
-
}
|
|
3628
|
-
indicator.style.fontSize = "12px";
|
|
3629
|
-
indicator.style.fontWeight = "600";
|
|
3630
|
-
indicator.style.padding = "5px 14px";
|
|
3631
|
-
indicator.style.borderRadius = "20px";
|
|
3632
|
-
indicator.style.zIndex = "10";
|
|
3633
|
-
indicator.style.userSelect = "none";
|
|
3634
|
-
indicator.style.pointerEvents = "none";
|
|
3635
|
-
indicator.style.textAlign = "center";
|
|
3636
|
-
indicator.style.width = "fit-content";
|
|
3637
|
-
indicator.style.margin = "16px auto 0";
|
|
3638
|
-
container.appendChild(indicator);
|
|
3639
|
-
}
|
|
3640
4409
|
const showPage = (pageNum) => {
|
|
3641
4410
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3642
4411
|
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
3643
|
-
if (indicator) {
|
|
3644
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3645
|
-
}
|
|
3646
4412
|
container.scrollTop = 0;
|
|
3647
4413
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3648
4414
|
};
|
|
@@ -3650,36 +4416,90 @@ var CodePlugin = class {
|
|
|
3650
4416
|
showPage(1);
|
|
3651
4417
|
}
|
|
3652
4418
|
ctx.container.appendChild(container);
|
|
3653
|
-
const
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
ctx.container.innerHTML = "";
|
|
4419
|
+
const calculateTxtFit = () => {
|
|
4420
|
+
const availW = Math.max(280, container.clientWidth - 32);
|
|
4421
|
+
return Math.max(0.4, Math.min(3, availW / 816));
|
|
3657
4422
|
};
|
|
3658
|
-
ctx.signal.addEventListener("abort", cleanup);
|
|
3659
4423
|
const updateTransform = () => {
|
|
3660
4424
|
if (isTxt) {
|
|
3661
4425
|
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
4426
|
+
const scaledH = 1056 * zoomLevel;
|
|
4427
|
+
const extraH = Math.max(0, scaledH - 1056);
|
|
4428
|
+
pre.style.marginBottom = `${extraH + 32}px`;
|
|
3662
4429
|
} else {
|
|
3663
4430
|
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3664
4431
|
pre.style.fontSize = `${fontSize}px`;
|
|
3665
4432
|
}
|
|
3666
4433
|
};
|
|
4434
|
+
let resizeObserver = null;
|
|
4435
|
+
if (isTxt) {
|
|
4436
|
+
setTimeout(() => {
|
|
4437
|
+
zoomLevel = calculateTxtFit();
|
|
4438
|
+
updateTransform();
|
|
4439
|
+
}, 60);
|
|
4440
|
+
resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
4441
|
+
if (!isUserZoomed) {
|
|
4442
|
+
zoomLevel = calculateTxtFit();
|
|
4443
|
+
updateTransform();
|
|
4444
|
+
}
|
|
4445
|
+
}) : null;
|
|
4446
|
+
resizeObserver?.observe(container);
|
|
4447
|
+
}
|
|
4448
|
+
const cleanup = () => {
|
|
4449
|
+
resizeObserver?.disconnect();
|
|
4450
|
+
container.remove();
|
|
4451
|
+
ctx.container.innerHTML = "";
|
|
4452
|
+
};
|
|
4453
|
+
ctx.signal.addEventListener("abort", cleanup);
|
|
3667
4454
|
return {
|
|
3668
4455
|
destroy: cleanup,
|
|
3669
4456
|
getPageCount: () => totalPages,
|
|
3670
4457
|
getCurrentPage: () => currentPage,
|
|
3671
4458
|
goToPage: (page) => showPage(page),
|
|
4459
|
+
getThumbnails: () => {
|
|
4460
|
+
return rawPages.map((pageText, idx) => ({
|
|
4461
|
+
index: idx,
|
|
4462
|
+
label: `Page ${idx + 1}`,
|
|
4463
|
+
render: async (canvas) => {
|
|
4464
|
+
canvas.width = 140;
|
|
4465
|
+
canvas.height = 180;
|
|
4466
|
+
const c = canvas.getContext("2d");
|
|
4467
|
+
if (!c) return;
|
|
4468
|
+
c.fillStyle = "#ffffff";
|
|
4469
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4470
|
+
c.strokeStyle = "#cbd5e1";
|
|
4471
|
+
c.lineWidth = 1;
|
|
4472
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4473
|
+
c.fillStyle = "#64748b";
|
|
4474
|
+
const lines = (pageText || "").split("\n").slice(0, 24);
|
|
4475
|
+
const lineH = 6;
|
|
4476
|
+
const startY = 14;
|
|
4477
|
+
const startX = 12;
|
|
4478
|
+
const maxW = canvas.width - 24;
|
|
4479
|
+
c.font = "5px monospace";
|
|
4480
|
+
for (let li = 0; li < lines.length; li++) {
|
|
4481
|
+
const l = lines[li].trim();
|
|
4482
|
+
if (!l) continue;
|
|
4483
|
+
const y = startY + li * lineH;
|
|
4484
|
+
if (y > canvas.height - 12) break;
|
|
4485
|
+
c.fillText(l.slice(0, 30), startX, y, maxW);
|
|
4486
|
+
}
|
|
4487
|
+
}
|
|
4488
|
+
}));
|
|
4489
|
+
},
|
|
3672
4490
|
zoomIn: () => {
|
|
4491
|
+
isUserZoomed = true;
|
|
3673
4492
|
if (isTxt) {
|
|
3674
|
-
zoomLevel = Math.min(3, zoomLevel + 0.
|
|
4493
|
+
zoomLevel = Math.min(3.5, zoomLevel + 0.15);
|
|
3675
4494
|
} else {
|
|
3676
4495
|
fontSize = Math.min(32, fontSize + 2);
|
|
3677
4496
|
}
|
|
3678
4497
|
updateTransform();
|
|
3679
4498
|
},
|
|
3680
4499
|
zoomOut: () => {
|
|
4500
|
+
isUserZoomed = true;
|
|
3681
4501
|
if (isTxt) {
|
|
3682
|
-
zoomLevel = Math.max(0.1, zoomLevel - 0.
|
|
4502
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.15);
|
|
3683
4503
|
} else {
|
|
3684
4504
|
fontSize = Math.max(8, fontSize - 2);
|
|
3685
4505
|
}
|
|
@@ -3687,6 +4507,7 @@ var CodePlugin = class {
|
|
|
3687
4507
|
},
|
|
3688
4508
|
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
3689
4509
|
setZoom: (level) => {
|
|
4510
|
+
isUserZoomed = true;
|
|
3690
4511
|
if (isTxt) {
|
|
3691
4512
|
zoomLevel = level;
|
|
3692
4513
|
} else {
|
|
@@ -3695,9 +4516,10 @@ var CodePlugin = class {
|
|
|
3695
4516
|
updateTransform();
|
|
3696
4517
|
},
|
|
3697
4518
|
fitToPage: () => {
|
|
4519
|
+
isUserZoomed = false;
|
|
3698
4520
|
fontSize = 13;
|
|
3699
4521
|
rotation = 0;
|
|
3700
|
-
zoomLevel = isTxt ?
|
|
4522
|
+
zoomLevel = isTxt ? calculateTxtFit() : 1;
|
|
3701
4523
|
updateTransform();
|
|
3702
4524
|
},
|
|
3703
4525
|
rotateCW: () => {
|
|
@@ -4578,28 +5400,26 @@ var RtfPlugin = class {
|
|
|
4578
5400
|
getToolbarActions(instance) {
|
|
4579
5401
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4580
5402
|
const actions = [];
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
if (
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
instance.goToPage?.(page);
|
|
4599
|
-
}
|
|
5403
|
+
actions.push({
|
|
5404
|
+
id: "page-nav",
|
|
5405
|
+
icon: "",
|
|
5406
|
+
label: "Page Navigation",
|
|
5407
|
+
type: "page-nav",
|
|
5408
|
+
group: "navigation",
|
|
5409
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5410
|
+
max: totalPages,
|
|
5411
|
+
execute: (action, page) => {
|
|
5412
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5413
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5414
|
+
if (action === "prev") {
|
|
5415
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5416
|
+
} else if (action === "next") {
|
|
5417
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5418
|
+
} else if (typeof page === "number") {
|
|
5419
|
+
instance.goToPage?.(page);
|
|
4600
5420
|
}
|
|
4601
|
-
}
|
|
4602
|
-
}
|
|
5421
|
+
}
|
|
5422
|
+
});
|
|
4603
5423
|
actions.push(
|
|
4604
5424
|
{
|
|
4605
5425
|
id: "zoom-out",
|
|
@@ -4671,43 +5491,57 @@ var RtfPlugin = class {
|
|
|
4671
5491
|
async render(ctx) {
|
|
4672
5492
|
const wrapper = document.createElement("div");
|
|
4673
5493
|
wrapper.className = "fp-rtf-wrapper";
|
|
4674
|
-
wrapper.style.padding = "
|
|
4675
|
-
wrapper.style.
|
|
5494
|
+
wrapper.style.padding = "0";
|
|
5495
|
+
wrapper.style.width = "816px";
|
|
4676
5496
|
wrapper.style.margin = "0 auto";
|
|
4677
|
-
wrapper.style.
|
|
4678
|
-
wrapper.style.
|
|
4679
|
-
wrapper.style.
|
|
4680
|
-
wrapper.style.
|
|
5497
|
+
wrapper.style.boxSizing = "border-box";
|
|
5498
|
+
wrapper.style.display = "flex";
|
|
5499
|
+
wrapper.style.flexDirection = "column";
|
|
5500
|
+
wrapper.style.alignItems = "center";
|
|
5501
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4681
5502
|
wrapper.style.transformOrigin = "top center";
|
|
4682
|
-
wrapper.style.transition = "transform 0.
|
|
4683
|
-
ctx.container.style.
|
|
4684
|
-
ctx.container.style.
|
|
5503
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5504
|
+
ctx.container.style.overflowX = "hidden";
|
|
5505
|
+
ctx.container.style.overflowY = "auto";
|
|
5506
|
+
ctx.container.style.padding = "16px 8px";
|
|
4685
5507
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
4686
5508
|
ctx.container.appendChild(wrapper);
|
|
4687
5509
|
let scale = 1;
|
|
4688
5510
|
let rotation = 0;
|
|
4689
5511
|
let pageElements = [];
|
|
4690
|
-
let
|
|
5512
|
+
let isUserZoomed = false;
|
|
5513
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
4691
5514
|
const calculateFitScale = (mode = fitMode) => {
|
|
4692
5515
|
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4693
|
-
const elW =
|
|
4694
|
-
const singlePageH =
|
|
4695
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
4696
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
5516
|
+
const elW = 816;
|
|
5517
|
+
const singlePageH = activeEl?.offsetHeight || 1056;
|
|
5518
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
5519
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
4697
5520
|
const sW = availW / elW;
|
|
4698
5521
|
const sH = availH / singlePageH;
|
|
4699
5522
|
if (mode === "page") {
|
|
4700
|
-
return Math.max(0.
|
|
5523
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
4701
5524
|
}
|
|
4702
|
-
return Math.max(0.
|
|
5525
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
4703
5526
|
};
|
|
4704
5527
|
const applyTransform = () => {
|
|
4705
5528
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4706
5529
|
wrapper.style.transformOrigin = "top center";
|
|
5530
|
+
const activeEl = pageElements[currentPage - 1];
|
|
5531
|
+
const baseH = activeEl?.offsetHeight || 1056;
|
|
5532
|
+
const scaledH = baseH * scale;
|
|
5533
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
5534
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
4707
5535
|
};
|
|
5536
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
5537
|
+
if (!isUserZoomed) {
|
|
5538
|
+
scale = calculateFitScale(fitMode);
|
|
5539
|
+
applyTransform();
|
|
5540
|
+
}
|
|
5541
|
+
}) : null;
|
|
5542
|
+
resizeObserver?.observe(ctx.container);
|
|
4708
5543
|
setTimeout(() => {
|
|
4709
|
-
|
|
4710
|
-
scale = calculateFitScale("width");
|
|
5544
|
+
scale = calculateFitScale(fitMode);
|
|
4711
5545
|
applyTransform();
|
|
4712
5546
|
}, 60);
|
|
4713
5547
|
try {
|
|
@@ -4717,20 +5551,34 @@ var RtfPlugin = class {
|
|
|
4717
5551
|
const doc = new RTFJS.Document(ctx.buffer, {});
|
|
4718
5552
|
const htmlElements = await doc.render();
|
|
4719
5553
|
const contentNodes = [];
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
5554
|
+
const extractBlocks = (nodes) => {
|
|
5555
|
+
for (const item of nodes) {
|
|
5556
|
+
if (!item || !(item instanceof HTMLElement)) continue;
|
|
5557
|
+
const tag = item.tagName.toLowerCase();
|
|
5558
|
+
const hasChildBlocks = Array.from(item.children).some((c) => {
|
|
5559
|
+
const ct = c.tagName.toLowerCase();
|
|
5560
|
+
return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
|
|
5561
|
+
});
|
|
5562
|
+
if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
|
|
5563
|
+
extractBlocks(Array.from(item.children));
|
|
5564
|
+
} else {
|
|
5565
|
+
if (tag === "p" || tag === "div") {
|
|
5566
|
+
item.style.display = "block";
|
|
5567
|
+
item.style.marginBottom = "12px";
|
|
5568
|
+
item.style.lineHeight = "1.6";
|
|
5569
|
+
}
|
|
5570
|
+
contentNodes.push(item);
|
|
5571
|
+
}
|
|
4725
5572
|
}
|
|
4726
|
-
}
|
|
5573
|
+
};
|
|
5574
|
+
extractBlocks(htmlElements);
|
|
4727
5575
|
wrapper.innerHTML = "";
|
|
4728
5576
|
contentNodes.forEach((node) => wrapper.appendChild(node));
|
|
4729
5577
|
const childHeights = contentNodes.map((c) => {
|
|
4730
5578
|
const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
|
|
4731
5579
|
const offH = c.offsetHeight || 0;
|
|
4732
5580
|
const textLen = c.textContent?.trim().length || 0;
|
|
4733
|
-
const estH = Math.max(
|
|
5581
|
+
const estH = Math.max(28, Math.ceil(textLen / 75) * 24 + 16);
|
|
4734
5582
|
return Math.max(rectH, offH, estH);
|
|
4735
5583
|
});
|
|
4736
5584
|
wrapper.innerHTML = "";
|
|
@@ -4747,6 +5595,7 @@ var RtfPlugin = class {
|
|
|
4747
5595
|
card.style.marginBottom = "24px";
|
|
4748
5596
|
card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4749
5597
|
card.style.lineHeight = "1.6";
|
|
5598
|
+
card.style.color = "#1e293b";
|
|
4750
5599
|
return card;
|
|
4751
5600
|
};
|
|
4752
5601
|
let curCard = createRtfCard();
|
|
@@ -4782,9 +5631,8 @@ var RtfPlugin = class {
|
|
|
4782
5631
|
pageCard.style.padding = "72px 56px";
|
|
4783
5632
|
pageCard.style.width = "816px";
|
|
4784
5633
|
pageCard.style.minHeight = "1056px";
|
|
4785
|
-
pageCard.style.maxWidth = "100%";
|
|
4786
5634
|
pageCard.style.boxSizing = "border-box";
|
|
4787
|
-
pageCard.style.fontFamily = "serif
|
|
5635
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4788
5636
|
pageCard.style.fontSize = "12pt";
|
|
4789
5637
|
pageCard.style.lineHeight = "1.6";
|
|
4790
5638
|
pageCard.style.color = "#1e293b";
|
|
@@ -4797,29 +5645,6 @@ var RtfPlugin = class {
|
|
|
4797
5645
|
}
|
|
4798
5646
|
const totalPages = Math.max(1, pageElements.length);
|
|
4799
5647
|
let currentPage = 1;
|
|
4800
|
-
let indicator = null;
|
|
4801
|
-
if (totalPages > 1) {
|
|
4802
|
-
indicator = document.createElement("div");
|
|
4803
|
-
indicator.className = "fp-rtf-page-indicator";
|
|
4804
|
-
indicator.style.position = "sticky";
|
|
4805
|
-
indicator.style.bottom = "16px";
|
|
4806
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4807
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
4808
|
-
indicator.style.color = "#f8fafc";
|
|
4809
|
-
indicator.style.fontSize = "12px";
|
|
4810
|
-
indicator.style.fontWeight = "600";
|
|
4811
|
-
indicator.style.padding = "5px 14px";
|
|
4812
|
-
indicator.style.borderRadius = "20px";
|
|
4813
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4814
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4815
|
-
indicator.style.zIndex = "10";
|
|
4816
|
-
indicator.style.userSelect = "none";
|
|
4817
|
-
indicator.style.pointerEvents = "none";
|
|
4818
|
-
indicator.style.textAlign = "center";
|
|
4819
|
-
indicator.style.width = "fit-content";
|
|
4820
|
-
indicator.style.margin = "16px auto 0";
|
|
4821
|
-
ctx.container.appendChild(indicator);
|
|
4822
|
-
}
|
|
4823
5648
|
const showPage = (pageNum) => {
|
|
4824
5649
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4825
5650
|
if (totalPages > 1) {
|
|
@@ -4827,9 +5652,6 @@ var RtfPlugin = class {
|
|
|
4827
5652
|
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4828
5653
|
});
|
|
4829
5654
|
}
|
|
4830
|
-
if (indicator) {
|
|
4831
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4832
|
-
}
|
|
4833
5655
|
ctx.container.scrollTop = 0;
|
|
4834
5656
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4835
5657
|
};
|
|
@@ -4837,7 +5659,7 @@ var RtfPlugin = class {
|
|
|
4837
5659
|
showPage(1);
|
|
4838
5660
|
}
|
|
4839
5661
|
const cleanup = () => {
|
|
4840
|
-
|
|
5662
|
+
resizeObserver?.disconnect();
|
|
4841
5663
|
wrapper.remove();
|
|
4842
5664
|
ctx.container.innerHTML = "";
|
|
4843
5665
|
};
|
|
@@ -4848,21 +5670,25 @@ var RtfPlugin = class {
|
|
|
4848
5670
|
getCurrentPage: () => currentPage,
|
|
4849
5671
|
goToPage: (page) => showPage(page),
|
|
4850
5672
|
zoomIn: () => {
|
|
5673
|
+
isUserZoomed = true;
|
|
4851
5674
|
scale += 0.15;
|
|
4852
5675
|
applyTransform();
|
|
4853
5676
|
},
|
|
4854
5677
|
zoomOut: () => {
|
|
5678
|
+
isUserZoomed = true;
|
|
4855
5679
|
scale = Math.max(0.2, scale - 0.15);
|
|
4856
5680
|
applyTransform();
|
|
4857
5681
|
},
|
|
4858
5682
|
getZoom: () => scale,
|
|
4859
5683
|
setZoom: (level) => {
|
|
5684
|
+
isUserZoomed = true;
|
|
4860
5685
|
scale = level;
|
|
4861
5686
|
applyTransform();
|
|
4862
5687
|
},
|
|
4863
5688
|
fitToPage: () => {
|
|
4864
|
-
|
|
4865
|
-
|
|
5689
|
+
isUserZoomed = false;
|
|
5690
|
+
fitMode = "width";
|
|
5691
|
+
scale = calculateFitScale("width");
|
|
4866
5692
|
rotation = 0;
|
|
4867
5693
|
applyTransform();
|
|
4868
5694
|
},
|
|
@@ -5050,40 +5876,36 @@ var OpenDocumentPlugin = class {
|
|
|
5050
5876
|
const isPresentation = instance.isPresentation;
|
|
5051
5877
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5052
5878
|
const actions = [];
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
max
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
if (
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
instance.goToPage?.(page);
|
|
5081
|
-
} else if (typeof action === "number") {
|
|
5082
|
-
instance.goToPage?.(action);
|
|
5083
|
-
}
|
|
5879
|
+
actions.push({
|
|
5880
|
+
id: "thumbnails",
|
|
5881
|
+
icon: "thumbnails",
|
|
5882
|
+
label: isPresentation ? "Slide Thumbnails" : "Page Thumbnails",
|
|
5883
|
+
type: "button",
|
|
5884
|
+
group: "navigation",
|
|
5885
|
+
execute: () => instance.toggleThumbnails?.()
|
|
5886
|
+
});
|
|
5887
|
+
actions.push({
|
|
5888
|
+
id: "page-nav",
|
|
5889
|
+
icon: "",
|
|
5890
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
5891
|
+
type: "page-nav",
|
|
5892
|
+
group: "navigation",
|
|
5893
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5894
|
+
max: totalPages,
|
|
5895
|
+
execute: (action, page) => {
|
|
5896
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5897
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5898
|
+
if (action === "prev") {
|
|
5899
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5900
|
+
} else if (action === "next") {
|
|
5901
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5902
|
+
} else if (typeof page === "number") {
|
|
5903
|
+
instance.goToPage?.(page);
|
|
5904
|
+
} else if (typeof action === "number") {
|
|
5905
|
+
instance.goToPage?.(action);
|
|
5084
5906
|
}
|
|
5085
|
-
}
|
|
5086
|
-
}
|
|
5907
|
+
}
|
|
5908
|
+
});
|
|
5087
5909
|
actions.push(
|
|
5088
5910
|
{
|
|
5089
5911
|
id: "zoom-out",
|
|
@@ -5174,49 +5996,65 @@ var OpenDocumentPlugin = class {
|
|
|
5174
5996
|
container.className = "fp-odf-container";
|
|
5175
5997
|
container.style.width = "100%";
|
|
5176
5998
|
container.style.height = "100%";
|
|
5177
|
-
container.style.
|
|
5178
|
-
container.style.
|
|
5999
|
+
container.style.overflowX = "hidden";
|
|
6000
|
+
container.style.overflowY = "auto";
|
|
6001
|
+
container.style.padding = "16px 8px";
|
|
5179
6002
|
container.style.backgroundColor = "#f1f5f9";
|
|
5180
6003
|
const wrapper = document.createElement("div");
|
|
5181
6004
|
wrapper.className = "fp-odf-wrapper";
|
|
5182
6005
|
wrapper.style.margin = "0 auto";
|
|
6006
|
+
wrapper.style.width = isPresentation ? "960px" : "816px";
|
|
6007
|
+
wrapper.style.boxSizing = "border-box";
|
|
5183
6008
|
wrapper.style.backgroundColor = "#ffffff";
|
|
5184
6009
|
wrapper.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
5185
6010
|
wrapper.style.borderRadius = "4px";
|
|
5186
6011
|
wrapper.style.transformOrigin = "top center";
|
|
5187
|
-
wrapper.style.transition = "transform 0.
|
|
6012
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5188
6013
|
container.appendChild(wrapper);
|
|
5189
6014
|
ctx.container.appendChild(container);
|
|
5190
6015
|
let scale = 1;
|
|
5191
6016
|
let rotation = 0;
|
|
5192
|
-
let
|
|
6017
|
+
let isUserZoomed = false;
|
|
6018
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6019
|
+
let currentPage = 1;
|
|
6020
|
+
let totalPages = 1;
|
|
6021
|
+
let slides = [];
|
|
5193
6022
|
const calculateFitScale = (mode = fitMode) => {
|
|
5194
|
-
const
|
|
5195
|
-
const
|
|
5196
|
-
const
|
|
5197
|
-
const
|
|
6023
|
+
const activeSlide = slides[currentPage - 1];
|
|
6024
|
+
const elW = isPresentation ? 960 : 816;
|
|
6025
|
+
const singlePageH = Math.min(activeSlide?.offsetHeight || wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
6026
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6027
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5198
6028
|
const sW = availW / elW;
|
|
5199
6029
|
const sH = availH / (isPresentation ? 540 : singlePageH);
|
|
5200
6030
|
if (isPresentation) {
|
|
5201
|
-
return Math.min(
|
|
6031
|
+
return Math.min(2.5, Math.min(sW, sH));
|
|
5202
6032
|
}
|
|
5203
6033
|
if (mode === "page") {
|
|
5204
|
-
return Math.max(0.
|
|
6034
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5205
6035
|
}
|
|
5206
|
-
return Math.max(0.
|
|
6036
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5207
6037
|
};
|
|
5208
6038
|
const applyTransform = () => {
|
|
5209
6039
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5210
6040
|
wrapper.style.transformOrigin = "top center";
|
|
6041
|
+
const activeSlide = slides[currentPage - 1];
|
|
6042
|
+
const baseH = activeSlide?.offsetHeight || wrapper.offsetHeight || 1056;
|
|
6043
|
+
const scaledH = baseH * scale;
|
|
6044
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6045
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
5211
6046
|
};
|
|
6047
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6048
|
+
if (!isUserZoomed) {
|
|
6049
|
+
scale = calculateFitScale(fitMode);
|
|
6050
|
+
applyTransform();
|
|
6051
|
+
}
|
|
6052
|
+
}) : null;
|
|
6053
|
+
resizeObserver?.observe(ctx.container);
|
|
5212
6054
|
setTimeout(() => {
|
|
5213
|
-
|
|
5214
|
-
scale = calculateFitScale("width");
|
|
6055
|
+
scale = calculateFitScale(fitMode);
|
|
5215
6056
|
applyTransform();
|
|
5216
6057
|
}, 60);
|
|
5217
|
-
let currentPage = 1;
|
|
5218
|
-
let totalPages = 1;
|
|
5219
|
-
let slides = [];
|
|
5220
6058
|
if (isPresentation) {
|
|
5221
6059
|
wrapper.style.maxWidth = "960px";
|
|
5222
6060
|
wrapper.style.aspectRatio = "16 / 9";
|
|
@@ -5317,24 +6155,9 @@ var OpenDocumentPlugin = class {
|
|
|
5317
6155
|
wrapper.appendChild(page);
|
|
5318
6156
|
slides.push(page);
|
|
5319
6157
|
});
|
|
5320
|
-
const pageIndicator = document.createElement("div");
|
|
5321
|
-
pageIndicator.className = "fp-odt-page-indicator";
|
|
5322
|
-
pageIndicator.style.position = "sticky";
|
|
5323
|
-
pageIndicator.style.bottom = "16px";
|
|
5324
|
-
pageIndicator.style.left = "50%";
|
|
5325
|
-
pageIndicator.style.transform = "translateX(-50%)";
|
|
5326
|
-
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
5327
|
-
pageIndicator.style.color = "#fff";
|
|
5328
|
-
pageIndicator.style.padding = "6px 12px";
|
|
5329
|
-
pageIndicator.style.borderRadius = "16px";
|
|
5330
|
-
pageIndicator.style.fontSize = "12px";
|
|
5331
|
-
pageIndicator.style.zIndex = "100";
|
|
5332
|
-
pageIndicator.style.display = "inline-block";
|
|
5333
|
-
pageIndicator.style.width = "fit-content";
|
|
5334
|
-
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
5335
|
-
container.appendChild(pageIndicator);
|
|
5336
6158
|
}
|
|
5337
6159
|
const cleanup = () => {
|
|
6160
|
+
resizeObserver?.disconnect();
|
|
5338
6161
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
5339
6162
|
container.remove();
|
|
5340
6163
|
ctx.container.innerHTML = "";
|
|
@@ -5346,10 +6169,6 @@ var OpenDocumentPlugin = class {
|
|
|
5346
6169
|
slides.forEach((s, idx) => {
|
|
5347
6170
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
5348
6171
|
});
|
|
5349
|
-
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
5350
|
-
if (indicator) {
|
|
5351
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5352
|
-
}
|
|
5353
6172
|
container.scrollTop = 0;
|
|
5354
6173
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5355
6174
|
};
|
|
@@ -5357,21 +6176,25 @@ var OpenDocumentPlugin = class {
|
|
|
5357
6176
|
destroy: cleanup,
|
|
5358
6177
|
isPresentation,
|
|
5359
6178
|
zoomIn: () => {
|
|
6179
|
+
isUserZoomed = true;
|
|
5360
6180
|
scale += 0.15;
|
|
5361
6181
|
applyTransform();
|
|
5362
6182
|
},
|
|
5363
6183
|
zoomOut: () => {
|
|
6184
|
+
isUserZoomed = true;
|
|
5364
6185
|
scale = Math.max(0.2, scale - 0.15);
|
|
5365
6186
|
applyTransform();
|
|
5366
6187
|
},
|
|
5367
6188
|
getZoom: () => scale,
|
|
5368
6189
|
setZoom: (level) => {
|
|
6190
|
+
isUserZoomed = true;
|
|
5369
6191
|
scale = level;
|
|
5370
6192
|
applyTransform();
|
|
5371
6193
|
},
|
|
5372
6194
|
fitToPage: () => {
|
|
5373
|
-
|
|
5374
|
-
|
|
6195
|
+
isUserZoomed = false;
|
|
6196
|
+
fitMode = "width";
|
|
6197
|
+
scale = calculateFitScale("width");
|
|
5375
6198
|
rotation = 0;
|
|
5376
6199
|
applyTransform();
|
|
5377
6200
|
},
|
|
@@ -5387,23 +6210,45 @@ var OpenDocumentPlugin = class {
|
|
|
5387
6210
|
getPageCount: () => totalPages,
|
|
5388
6211
|
getCurrentPage: () => currentPage,
|
|
5389
6212
|
getThumbnails: async () => {
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
canvas
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
6213
|
+
const count = totalPages || slides.length || 1;
|
|
6214
|
+
const items = [];
|
|
6215
|
+
for (let idx = 0; idx < count; idx++) {
|
|
6216
|
+
const itemIdx = idx;
|
|
6217
|
+
items.push({
|
|
6218
|
+
index: itemIdx,
|
|
6219
|
+
label: isPresentation ? `Slide ${itemIdx + 1}` : `Page ${itemIdx + 1}`,
|
|
6220
|
+
render: async (canvas) => {
|
|
6221
|
+
const ctx2d = canvas.getContext("2d");
|
|
6222
|
+
if (!ctx2d) return;
|
|
6223
|
+
if (isPresentation) {
|
|
6224
|
+
canvas.width = 160;
|
|
6225
|
+
canvas.height = 90;
|
|
6226
|
+
ctx2d.fillStyle = "#f8fafc";
|
|
6227
|
+
ctx2d.fillRect(0, 0, 160, 90);
|
|
6228
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6229
|
+
ctx2d.lineWidth = 1;
|
|
6230
|
+
ctx2d.strokeRect(0.5, 0.5, 159, 89);
|
|
6231
|
+
ctx2d.fillStyle = "#334155";
|
|
6232
|
+
ctx2d.font = "bold 11px sans-serif";
|
|
6233
|
+
ctx2d.textAlign = "center";
|
|
6234
|
+
ctx2d.fillText(`Slide ${itemIdx + 1}`, 80, 50);
|
|
6235
|
+
} else {
|
|
6236
|
+
canvas.width = 140;
|
|
6237
|
+
canvas.height = 180;
|
|
6238
|
+
ctx2d.fillStyle = "#ffffff";
|
|
6239
|
+
ctx2d.fillRect(0, 0, 140, 180);
|
|
6240
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6241
|
+
ctx2d.lineWidth = 1;
|
|
6242
|
+
ctx2d.strokeRect(0.5, 0.5, 139, 179);
|
|
6243
|
+
ctx2d.fillStyle = "#64748b";
|
|
6244
|
+
ctx2d.font = "bold 10px sans-serif";
|
|
6245
|
+
ctx2d.textAlign = "center";
|
|
6246
|
+
ctx2d.fillText(`Page ${itemIdx + 1}`, 70, 90);
|
|
6247
|
+
}
|
|
6248
|
+
}
|
|
6249
|
+
});
|
|
6250
|
+
}
|
|
6251
|
+
return items;
|
|
5407
6252
|
},
|
|
5408
6253
|
download: () => {
|
|
5409
6254
|
const mimeType = this.mimeTypes.find((m) => m.includes(ext.replace(".", ""))) || "application/octet-stream";
|
|
@@ -5508,23 +6353,24 @@ var OpenDocumentPlugin = class {
|
|
|
5508
6353
|
case "h": {
|
|
5509
6354
|
const level = Math.min(6, Math.max(1, Number(node.getAttribute("text:outline-level") || 1)));
|
|
5510
6355
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5511
|
-
html += `<h${level} style="${style}; font-family:
|
|
6356
|
+
html += `<h${level} style="${style}; margin: 18px 0 8px; color: #1e3a8a; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${node.textContent || ""}</h${level}>`;
|
|
5512
6357
|
break;
|
|
5513
6358
|
}
|
|
5514
6359
|
case "p": {
|
|
5515
6360
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5516
6361
|
const inner = this.renderSpans(node, styles, images);
|
|
5517
|
-
|
|
6362
|
+
const isInsideLi = node.parentElement?.localName === "list-item" || node.parentElement?.tagName?.toLowerCase() === "list-item";
|
|
6363
|
+
html += `<p style="${style}; line-height: 1.5; margin: ${isInsideLi ? "0" : "8px 0 12px"}; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${inner}</p>`;
|
|
5518
6364
|
break;
|
|
5519
6365
|
}
|
|
5520
6366
|
case "list": {
|
|
5521
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
6367
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
5522
6368
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5523
6369
|
html += "</ul>";
|
|
5524
6370
|
break;
|
|
5525
6371
|
}
|
|
5526
6372
|
case "list-item": {
|
|
5527
|
-
html +=
|
|
6373
|
+
html += '<li style="margin: 4px 0; font-size: 11pt; line-height: 1.5; color: #1e293b;">';
|
|
5528
6374
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5529
6375
|
html += "</li>";
|
|
5530
6376
|
break;
|
|
@@ -5650,28 +6496,26 @@ var DocPlugin = class {
|
|
|
5650
6496
|
getToolbarActions(instance) {
|
|
5651
6497
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5652
6498
|
const actions = [];
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
if (
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
instance.goToPage?.(page);
|
|
5671
|
-
}
|
|
6499
|
+
actions.push({
|
|
6500
|
+
id: "page-nav",
|
|
6501
|
+
icon: "",
|
|
6502
|
+
label: "Page Navigation",
|
|
6503
|
+
type: "page-nav",
|
|
6504
|
+
group: "navigation",
|
|
6505
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
6506
|
+
max: totalPages,
|
|
6507
|
+
execute: (action, page) => {
|
|
6508
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
6509
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
6510
|
+
if (action === "prev") {
|
|
6511
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
6512
|
+
} else if (action === "next") {
|
|
6513
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
6514
|
+
} else if (typeof page === "number") {
|
|
6515
|
+
instance.goToPage?.(page);
|
|
5672
6516
|
}
|
|
5673
|
-
}
|
|
5674
|
-
}
|
|
6517
|
+
}
|
|
6518
|
+
});
|
|
5675
6519
|
actions.push(
|
|
5676
6520
|
{
|
|
5677
6521
|
id: "zoom-out",
|
|
@@ -5745,8 +6589,9 @@ var DocPlugin = class {
|
|
|
5745
6589
|
container.className = "fp-doc-container";
|
|
5746
6590
|
container.style.width = "100%";
|
|
5747
6591
|
container.style.height = "100%";
|
|
5748
|
-
container.style.
|
|
5749
|
-
container.style.
|
|
6592
|
+
container.style.overflowX = "hidden";
|
|
6593
|
+
container.style.overflowY = "auto";
|
|
6594
|
+
container.style.padding = "16px 8px";
|
|
5750
6595
|
container.style.backgroundColor = "#f1f5f9";
|
|
5751
6596
|
container.style.display = "flex";
|
|
5752
6597
|
container.style.justifyContent = "center";
|
|
@@ -5791,16 +6636,15 @@ var DocPlugin = class {
|
|
|
5791
6636
|
const pageCard = document.createElement("div");
|
|
5792
6637
|
pageCard.className = "fp-doc-page-card";
|
|
5793
6638
|
pageCard.style.width = "816px";
|
|
5794
|
-
pageCard.style.
|
|
6639
|
+
pageCard.style.minHeight = "1056px";
|
|
5795
6640
|
pageCard.style.backgroundColor = "#ffffff";
|
|
5796
|
-
pageCard.style.boxShadow = "0
|
|
6641
|
+
pageCard.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
5797
6642
|
pageCard.style.borderRadius = "4px";
|
|
5798
|
-
pageCard.style.padding = "
|
|
6643
|
+
pageCard.style.padding = "72px 56px";
|
|
5799
6644
|
pageCard.style.boxSizing = "border-box";
|
|
5800
|
-
pageCard.style.overflow = "hidden";
|
|
5801
6645
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5802
6646
|
pageCard.style.transformOrigin = "top center";
|
|
5803
|
-
pageCard.style.transition = "transform 0.
|
|
6647
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
5804
6648
|
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5805
6649
|
pageCard.style.color = "#1e293b";
|
|
5806
6650
|
if (isFallback && i === 0) {
|
|
@@ -5817,34 +6661,15 @@ var DocPlugin = class {
|
|
|
5817
6661
|
container.appendChild(pageCard);
|
|
5818
6662
|
pageCards.push(pageCard);
|
|
5819
6663
|
}
|
|
5820
|
-
let indicator = null;
|
|
5821
|
-
if (totalPages > 1) {
|
|
5822
|
-
indicator = document.createElement("div");
|
|
5823
|
-
indicator.className = "fp-doc-page-indicator";
|
|
5824
|
-
indicator.style.position = "fixed";
|
|
5825
|
-
indicator.style.bottom = "16px";
|
|
5826
|
-
indicator.style.left = "50%";
|
|
5827
|
-
indicator.style.transform = "translateX(-50%)";
|
|
5828
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
5829
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
5830
|
-
indicator.style.color = "#f8fafc";
|
|
5831
|
-
indicator.style.fontSize = "12px";
|
|
5832
|
-
indicator.style.fontWeight = "600";
|
|
5833
|
-
indicator.style.padding = "5px 14px";
|
|
5834
|
-
indicator.style.borderRadius = "20px";
|
|
5835
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
5836
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
5837
|
-
indicator.style.zIndex = "10";
|
|
5838
|
-
indicator.style.userSelect = "none";
|
|
5839
|
-
indicator.style.pointerEvents = "none";
|
|
5840
|
-
indicator.style.textAlign = "center";
|
|
5841
|
-
container.appendChild(indicator);
|
|
5842
|
-
}
|
|
5843
6664
|
let rotation = 0;
|
|
5844
6665
|
const applyTransform = () => {
|
|
5845
6666
|
const activeCard = pageCards[currentPage - 1];
|
|
5846
6667
|
if (activeCard) {
|
|
5847
6668
|
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
6669
|
+
const baseH = activeCard.offsetHeight || 1056;
|
|
6670
|
+
const scaledH = baseH * scale;
|
|
6671
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6672
|
+
activeCard.style.marginBottom = `${extraH + 32}px`;
|
|
5848
6673
|
}
|
|
5849
6674
|
};
|
|
5850
6675
|
const showPage = (pageNum) => {
|
|
@@ -5857,35 +6682,39 @@ var DocPlugin = class {
|
|
|
5857
6682
|
card.style.display = "none";
|
|
5858
6683
|
}
|
|
5859
6684
|
});
|
|
5860
|
-
if (indicator) {
|
|
5861
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5862
|
-
}
|
|
5863
6685
|
container.scrollTop = 0;
|
|
5864
6686
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5865
6687
|
};
|
|
5866
6688
|
if (totalPages > 1) {
|
|
5867
6689
|
showPage(1);
|
|
5868
6690
|
}
|
|
5869
|
-
let fitMode = "width";
|
|
6691
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6692
|
+
let isUserZoomed = false;
|
|
5870
6693
|
const calculateFitScale = (mode = fitMode) => {
|
|
5871
6694
|
const elW = 816;
|
|
5872
6695
|
const elH = 1056;
|
|
5873
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
5874
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
6696
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6697
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5875
6698
|
const sW = availW / elW;
|
|
5876
6699
|
const sH = availH / elH;
|
|
5877
6700
|
if (mode === "page") {
|
|
5878
|
-
return Math.max(0.
|
|
6701
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5879
6702
|
}
|
|
5880
|
-
return Math.max(0.
|
|
6703
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5881
6704
|
};
|
|
6705
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6706
|
+
if (!isUserZoomed) {
|
|
6707
|
+
scale = calculateFitScale(fitMode);
|
|
6708
|
+
applyTransform();
|
|
6709
|
+
}
|
|
6710
|
+
}) : null;
|
|
6711
|
+
resizeObserver?.observe(ctx.container);
|
|
5882
6712
|
setTimeout(() => {
|
|
5883
|
-
|
|
5884
|
-
scale = calculateFitScale("width");
|
|
6713
|
+
scale = calculateFitScale(fitMode);
|
|
5885
6714
|
applyTransform();
|
|
5886
6715
|
}, 60);
|
|
5887
6716
|
const cleanup = () => {
|
|
5888
|
-
|
|
6717
|
+
resizeObserver?.disconnect();
|
|
5889
6718
|
container.remove();
|
|
5890
6719
|
ctx.container.innerHTML = "";
|
|
5891
6720
|
};
|
|
@@ -5896,21 +6725,25 @@ var DocPlugin = class {
|
|
|
5896
6725
|
getCurrentPage: () => currentPage,
|
|
5897
6726
|
goToPage: (page) => showPage(page),
|
|
5898
6727
|
zoomIn: () => {
|
|
6728
|
+
isUserZoomed = true;
|
|
5899
6729
|
scale += 0.15;
|
|
5900
6730
|
applyTransform();
|
|
5901
6731
|
},
|
|
5902
6732
|
zoomOut: () => {
|
|
6733
|
+
isUserZoomed = true;
|
|
5903
6734
|
scale = Math.max(0.2, scale - 0.15);
|
|
5904
6735
|
applyTransform();
|
|
5905
6736
|
},
|
|
5906
6737
|
getZoom: () => scale,
|
|
5907
6738
|
setZoom: (level) => {
|
|
6739
|
+
isUserZoomed = true;
|
|
5908
6740
|
scale = level;
|
|
5909
6741
|
applyTransform();
|
|
5910
6742
|
},
|
|
5911
6743
|
fitToPage: () => {
|
|
5912
|
-
|
|
5913
|
-
|
|
6744
|
+
isUserZoomed = false;
|
|
6745
|
+
fitMode = "width";
|
|
6746
|
+
scale = calculateFitScale("width");
|
|
5914
6747
|
rotation = 0;
|
|
5915
6748
|
applyTransform();
|
|
5916
6749
|
},
|
|
@@ -6287,25 +7120,31 @@ ${chartSvg}
|
|
|
6287
7120
|
i++;
|
|
6288
7121
|
continue;
|
|
6289
7122
|
}
|
|
6290
|
-
if (
|
|
7123
|
+
if (/^\d{1,2}$/.test(line.trim())) {
|
|
7124
|
+
i++;
|
|
7125
|
+
continue;
|
|
7126
|
+
}
|
|
7127
|
+
const isShortLine = line.length < 60 && !line.endsWith(".") && !line.endsWith(",");
|
|
7128
|
+
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));
|
|
7129
|
+
if (isTitleLike) {
|
|
6291
7130
|
if (inList) {
|
|
6292
7131
|
html += "</ul>";
|
|
6293
7132
|
inList = false;
|
|
6294
7133
|
}
|
|
6295
|
-
html += `<h2 style="font-size:
|
|
7134
|
+
html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 18px 0 10px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6.sanitize(line, sanitizeOptions)}</h2>`;
|
|
6296
7135
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
6297
7136
|
if (!inList) {
|
|
6298
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
7137
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
6299
7138
|
inList = true;
|
|
6300
7139
|
}
|
|
6301
7140
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
6302
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
7141
|
+
html += `<li style="margin: 4px 0; line-height: 1.5; font-size: 11pt; color: #1e293b;">${DOMPurify6.sanitize(bulletText, sanitizeOptions)}</li>`;
|
|
6303
7142
|
} else {
|
|
6304
7143
|
if (inList) {
|
|
6305
7144
|
html += "</ul>";
|
|
6306
7145
|
inList = false;
|
|
6307
7146
|
}
|
|
6308
|
-
html += `<p style="line-height: 1.
|
|
7147
|
+
html += `<p style="line-height: 1.5; margin: 0 0 12px 0; font-size: 11pt; color: #1e293b; text-align: justify;">${DOMPurify6.sanitize(line, sanitizeOptions)}</p>`;
|
|
6309
7148
|
}
|
|
6310
7149
|
i++;
|
|
6311
7150
|
}
|