@files-preview-app/preview-file 1.3.1 → 1.3.3
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 +99 -3
- package/dist/angular.cjs +1552 -520
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.d.cts +6 -1
- package/dist/angular.d.ts +6 -1
- package/dist/angular.js +1552 -520
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +1535 -519
- 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 +1535 -519
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +1539 -519
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +5 -16
- package/dist/react.d.ts +5 -16
- package/dist/react.js +1539 -519
- package/dist/react.js.map +1 -1
- package/dist/styles.css +195 -14
- package/dist/vue.cjs +1538 -520
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.d.cts +4 -2
- package/dist/vue.d.ts +4 -2
- package/dist/vue.js +1538 -520
- package/dist/vue.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -609,8 +609,7 @@ var ICON_FULLSCREEN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="non
|
|
|
609
609
|
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>`;
|
|
610
610
|
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>`;
|
|
611
611
|
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>`;
|
|
612
|
-
var
|
|
613
|
-
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>`;
|
|
612
|
+
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>`;
|
|
614
613
|
var ICON_MAP = {
|
|
615
614
|
"zoom-in": ICON_ZOOM_IN,
|
|
616
615
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -637,28 +636,177 @@ var ICON_MAP = {
|
|
|
637
636
|
"forward-10": ICON_FAST_FORWARD,
|
|
638
637
|
"rewind": ICON_REWIND,
|
|
639
638
|
"replay-10": ICON_REWIND,
|
|
640
|
-
"speed": ICON_SPEED,
|
|
641
639
|
"open-window": ICON_EXTERNAL_WINDOW,
|
|
642
|
-
"external-window": ICON_EXTERNAL_WINDOW
|
|
640
|
+
"external-window": ICON_EXTERNAL_WINDOW,
|
|
641
|
+
"openWindow": ICON_EXTERNAL_WINDOW,
|
|
642
|
+
"openSeparateWindow": ICON_EXTERNAL_WINDOW
|
|
643
643
|
};
|
|
644
644
|
var ToolbarController = class {
|
|
645
645
|
el;
|
|
646
646
|
toolbarEl;
|
|
647
647
|
actions = [];
|
|
648
|
+
config = {};
|
|
648
649
|
pageInputEl = null;
|
|
649
650
|
pageLabelEl = null;
|
|
650
|
-
|
|
651
|
+
prevPageBtn = null;
|
|
652
|
+
nextPageBtn = null;
|
|
653
|
+
constructor(container, config) {
|
|
651
654
|
this.el = container;
|
|
655
|
+
if (config) this.config = { ...config };
|
|
652
656
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
653
657
|
this.el.appendChild(this.toolbarEl);
|
|
654
658
|
}
|
|
659
|
+
setConfig(config) {
|
|
660
|
+
this.config = { ...config };
|
|
661
|
+
this.render();
|
|
662
|
+
}
|
|
663
|
+
getConfig() {
|
|
664
|
+
return { ...this.config };
|
|
665
|
+
}
|
|
666
|
+
hideAction(actionId) {
|
|
667
|
+
this.config[actionId] = false;
|
|
668
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = false;
|
|
669
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = false;
|
|
670
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
671
|
+
this.config.fitPage = false;
|
|
672
|
+
this.config.fitToPage = false;
|
|
673
|
+
this.config.fitWidth = false;
|
|
674
|
+
}
|
|
675
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = false;
|
|
676
|
+
if (actionId === "fullscreen") this.config.fullscreen = false;
|
|
677
|
+
if (actionId === "download") this.config.download = false;
|
|
678
|
+
if (actionId === "print") this.config.print = false;
|
|
679
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
680
|
+
this.config.openWindow = false;
|
|
681
|
+
this.config.openSeparateWindow = false;
|
|
682
|
+
}
|
|
683
|
+
if (actionId === "copy") this.config.copy = false;
|
|
684
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
685
|
+
this.config.pageNav = false;
|
|
686
|
+
this.config.pagination = false;
|
|
687
|
+
}
|
|
688
|
+
this.render();
|
|
689
|
+
}
|
|
690
|
+
showAction(actionId) {
|
|
691
|
+
this.config[actionId] = true;
|
|
692
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = true;
|
|
693
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = true;
|
|
694
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
695
|
+
this.config.fitPage = true;
|
|
696
|
+
this.config.fitToPage = true;
|
|
697
|
+
this.config.fitWidth = true;
|
|
698
|
+
}
|
|
699
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = true;
|
|
700
|
+
if (actionId === "fullscreen") this.config.fullscreen = true;
|
|
701
|
+
if (actionId === "download") this.config.download = true;
|
|
702
|
+
if (actionId === "print") this.config.print = true;
|
|
703
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
704
|
+
this.config.openWindow = true;
|
|
705
|
+
this.config.openSeparateWindow = true;
|
|
706
|
+
}
|
|
707
|
+
if (actionId === "copy") this.config.copy = true;
|
|
708
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
709
|
+
this.config.pageNav = true;
|
|
710
|
+
this.config.pagination = true;
|
|
711
|
+
}
|
|
712
|
+
this.render();
|
|
713
|
+
}
|
|
714
|
+
normalizeActionId(actionId) {
|
|
715
|
+
if (actionId === "zoomIn") return "zoom-in";
|
|
716
|
+
if (actionId === "zoomOut") return "zoom-out";
|
|
717
|
+
if (actionId === "fitPage" || actionId === "fitToPage" || actionId === "fitWidth") return "fit-page";
|
|
718
|
+
if (actionId === "rotateCW") return "rotate-cw";
|
|
719
|
+
if (actionId === "rotateCCW") return "rotate-ccw";
|
|
720
|
+
if (actionId === "openWindow" || actionId === "openSeparateWindow") return "open-window";
|
|
721
|
+
if (actionId === "pageNav") return "page-nav";
|
|
722
|
+
return actionId;
|
|
723
|
+
}
|
|
724
|
+
enableAction(actionId) {
|
|
725
|
+
const norm = this.normalizeActionId(actionId);
|
|
726
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
727
|
+
if (btn) {
|
|
728
|
+
btn.disabled = false;
|
|
729
|
+
btn.classList.remove("disabled");
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
disableAction(actionId) {
|
|
733
|
+
const norm = this.normalizeActionId(actionId);
|
|
734
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
735
|
+
if (btn) {
|
|
736
|
+
btn.disabled = true;
|
|
737
|
+
btn.classList.add("disabled");
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
setActionActive(actionId, active) {
|
|
741
|
+
const norm = this.normalizeActionId(actionId);
|
|
742
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
743
|
+
if (btn) {
|
|
744
|
+
if (active) {
|
|
745
|
+
btn.classList.add("active");
|
|
746
|
+
} else {
|
|
747
|
+
btn.classList.remove("active");
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
isActionEnabled(action) {
|
|
752
|
+
const c = this.config;
|
|
753
|
+
const id = action.id;
|
|
754
|
+
if (c[id] === false) return false;
|
|
755
|
+
if (id === "zoom-in" && (c.zoomIn === false || c["zoom-in"] === false)) return false;
|
|
756
|
+
if (id === "zoom-out" && (c.zoomOut === false || c["zoom-out"] === false)) return false;
|
|
757
|
+
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)) {
|
|
758
|
+
return false;
|
|
759
|
+
}
|
|
760
|
+
if ((id === "rotate-cw" || id === "rotate-ccw" || id === "rotate") && (c.rotate === false || c.rotateCW === false || c.rotateCCW === false || c["rotate-cw"] === false)) {
|
|
761
|
+
return false;
|
|
762
|
+
}
|
|
763
|
+
if (id === "fullscreen" && c.fullscreen === false) return false;
|
|
764
|
+
if (id === "download" && c.download === false) return false;
|
|
765
|
+
if (id === "print" && c.print === false) return false;
|
|
766
|
+
if ((id === "open-window" || id === "external-window") && (c.openWindow === false || c.openSeparateWindow === false || c["open-window"] === false)) {
|
|
767
|
+
return false;
|
|
768
|
+
}
|
|
769
|
+
if (id === "copy" && c.copy === false) return false;
|
|
770
|
+
if (id === "thumbnails" && c.thumbnails === false) return false;
|
|
771
|
+
if (id === "page-nav" && (c.pageNav === false || c.pagination === false || c["page-nav"] === false)) {
|
|
772
|
+
return false;
|
|
773
|
+
}
|
|
774
|
+
if ((id === "prev" || id === "page-prev") && (c.prevPage === false || c.prev === false || c["prev"] === false || c.pageNav === false || c.pagination === false)) {
|
|
775
|
+
return false;
|
|
776
|
+
}
|
|
777
|
+
if ((id === "next" || id === "page-next") && (c.nextPage === false || c.next === false || c["next"] === false || c.pageNav === false || c.pagination === false)) {
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
780
|
+
if (id === "play" && c.play === false) return false;
|
|
781
|
+
if (id === "pause" && c.pause === false) return false;
|
|
782
|
+
if ((id === "fast-forward" || id === "forward-10") && (c.fastForward === false || c["fast-forward"] === false)) {
|
|
783
|
+
return false;
|
|
784
|
+
}
|
|
785
|
+
if ((id === "rewind" || id === "replay-10") && (c.rewind === false || c["rewind"] === false)) {
|
|
786
|
+
return false;
|
|
787
|
+
}
|
|
788
|
+
if (id === "speed" && c.speed === false) return false;
|
|
789
|
+
return true;
|
|
790
|
+
}
|
|
655
791
|
setPage(page, max) {
|
|
656
792
|
if (this.pageInputEl) {
|
|
657
793
|
this.pageInputEl.value = page.toString();
|
|
794
|
+
if (max !== void 0) {
|
|
795
|
+
this.pageInputEl.max = max.toString();
|
|
796
|
+
}
|
|
658
797
|
}
|
|
659
798
|
if (max !== void 0 && this.pageLabelEl) {
|
|
660
799
|
this.pageLabelEl.textContent = ` / ${max}`;
|
|
661
800
|
}
|
|
801
|
+
const currentMax = max !== void 0 ? max : parseInt(this.pageInputEl?.max || "1", 10) || 1;
|
|
802
|
+
if (this.prevPageBtn) {
|
|
803
|
+
this.prevPageBtn.disabled = page <= 1;
|
|
804
|
+
this.prevPageBtn.style.opacity = page <= 1 ? "0.4" : "1";
|
|
805
|
+
}
|
|
806
|
+
if (this.nextPageBtn) {
|
|
807
|
+
this.nextPageBtn.disabled = page >= currentMax;
|
|
808
|
+
this.nextPageBtn.style.opacity = page >= currentMax ? "0.4" : "1";
|
|
809
|
+
}
|
|
662
810
|
}
|
|
663
811
|
update(actions) {
|
|
664
812
|
this.actions = actions;
|
|
@@ -681,8 +829,9 @@ var ToolbarController = class {
|
|
|
681
829
|
view: [],
|
|
682
830
|
actions: []
|
|
683
831
|
};
|
|
684
|
-
const
|
|
685
|
-
const
|
|
832
|
+
const enabledActions = this.actions.filter((a) => this.isActionEnabled(a));
|
|
833
|
+
const hasPageNav = enabledActions.some((a) => a.type === "page-nav");
|
|
834
|
+
const effectiveActions = hasPageNav ? enabledActions.filter((a) => a.id !== "page-prev" && a.id !== "page-next" && a.id !== "prev" && a.id !== "next") : enabledActions;
|
|
686
835
|
for (const action of effectiveActions) {
|
|
687
836
|
if (groups[action.group]) {
|
|
688
837
|
groups[action.group].push(action);
|
|
@@ -742,6 +891,13 @@ var ToolbarController = class {
|
|
|
742
891
|
action.execute("go", val);
|
|
743
892
|
});
|
|
744
893
|
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
894
|
+
const curVal = action.value ?? 1;
|
|
895
|
+
prevBtn.disabled = curVal <= 1;
|
|
896
|
+
prevBtn.style.opacity = curVal <= 1 ? "0.4" : "1";
|
|
897
|
+
nextBtn.disabled = curVal >= max;
|
|
898
|
+
nextBtn.style.opacity = curVal >= max ? "0.4" : "1";
|
|
899
|
+
this.prevPageBtn = prevBtn;
|
|
900
|
+
this.nextPageBtn = nextBtn;
|
|
745
901
|
this.pageInputEl = input;
|
|
746
902
|
this.pageLabelEl = label;
|
|
747
903
|
groupEl.appendChild(prevBtn);
|
|
@@ -797,25 +953,63 @@ var ToolbarController = class {
|
|
|
797
953
|
var ThumbnailPanel = class {
|
|
798
954
|
el;
|
|
799
955
|
panelEl;
|
|
956
|
+
listEl;
|
|
957
|
+
headerEl;
|
|
800
958
|
thumbnails = [];
|
|
801
959
|
onSelect;
|
|
960
|
+
onToggleCallback;
|
|
802
961
|
activeIndex = 0;
|
|
803
|
-
|
|
962
|
+
observer;
|
|
963
|
+
renderedIndices = /* @__PURE__ */ new Set();
|
|
964
|
+
constructor(container, onToggle) {
|
|
804
965
|
this.el = container;
|
|
966
|
+
this.onToggleCallback = onToggle;
|
|
805
967
|
this.panelEl = createElement("div", { className: "fp-thumbnail-panel hidden" });
|
|
968
|
+
this.panelEl.style.width = "0px";
|
|
969
|
+
this.panelEl.style.minWidth = "0px";
|
|
970
|
+
this.panelEl.style.opacity = "0";
|
|
971
|
+
this.headerEl = createElement("div", { className: "fp-thumbnail-header" });
|
|
972
|
+
const title = createElement("span", { className: "fp-thumbnail-title" }, "Pages");
|
|
973
|
+
const closeBtn = createElement("button", {
|
|
974
|
+
className: "fp-thumbnail-close-btn",
|
|
975
|
+
title: "Close Thumbnails",
|
|
976
|
+
type: "button"
|
|
977
|
+
});
|
|
978
|
+
closeBtn.innerHTML = ICON_CLOSE;
|
|
979
|
+
closeBtn.addEventListener("click", (e) => {
|
|
980
|
+
e.stopPropagation();
|
|
981
|
+
this.hide();
|
|
982
|
+
});
|
|
983
|
+
this.headerEl.appendChild(title);
|
|
984
|
+
this.headerEl.appendChild(closeBtn);
|
|
985
|
+
this.listEl = createElement("div", { className: "fp-thumbnail-list" });
|
|
986
|
+
this.panelEl.appendChild(this.headerEl);
|
|
987
|
+
this.panelEl.appendChild(this.listEl);
|
|
806
988
|
this.el.appendChild(this.panelEl);
|
|
807
989
|
}
|
|
990
|
+
isOpen() {
|
|
991
|
+
return !this.panelEl.classList.contains("hidden") && this.panelEl.style.width !== "0px";
|
|
992
|
+
}
|
|
808
993
|
update(thumbnails, onSelect) {
|
|
809
994
|
this.thumbnails = thumbnails;
|
|
810
995
|
this.onSelect = onSelect;
|
|
996
|
+
this.renderedIndices.clear();
|
|
997
|
+
const titleEl = this.headerEl.querySelector(".fp-thumbnail-title");
|
|
998
|
+
if (titleEl) {
|
|
999
|
+
titleEl.textContent = `Pages (${thumbnails.length})`;
|
|
1000
|
+
}
|
|
811
1001
|
this.render();
|
|
1002
|
+
if (this.isOpen()) {
|
|
1003
|
+
this.renderAllVisible();
|
|
1004
|
+
}
|
|
812
1005
|
}
|
|
813
1006
|
setActive(index) {
|
|
814
1007
|
this.activeIndex = index;
|
|
815
|
-
const items = this.
|
|
1008
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
816
1009
|
items.forEach((item, i) => {
|
|
817
1010
|
if (i === index) {
|
|
818
1011
|
item.classList.add("active");
|
|
1012
|
+
item.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
819
1013
|
} else {
|
|
820
1014
|
item.classList.remove("active");
|
|
821
1015
|
}
|
|
@@ -823,37 +1017,102 @@ var ThumbnailPanel = class {
|
|
|
823
1017
|
}
|
|
824
1018
|
show() {
|
|
825
1019
|
this.panelEl.classList.remove("hidden");
|
|
1020
|
+
this.panelEl.style.width = "200px";
|
|
1021
|
+
this.panelEl.style.minWidth = "200px";
|
|
1022
|
+
this.panelEl.style.opacity = "1";
|
|
1023
|
+
this.panelEl.style.display = "flex";
|
|
1024
|
+
this.onToggleCallback?.(true);
|
|
1025
|
+
this.renderAllVisible();
|
|
826
1026
|
}
|
|
827
1027
|
hide() {
|
|
828
1028
|
this.panelEl.classList.add("hidden");
|
|
1029
|
+
this.panelEl.style.width = "0px";
|
|
1030
|
+
this.panelEl.style.minWidth = "0px";
|
|
1031
|
+
this.panelEl.style.opacity = "0";
|
|
1032
|
+
this.onToggleCallback?.(false);
|
|
829
1033
|
}
|
|
830
1034
|
toggle() {
|
|
831
|
-
this.
|
|
1035
|
+
if (this.isOpen()) {
|
|
1036
|
+
this.hide();
|
|
1037
|
+
} else {
|
|
1038
|
+
this.show();
|
|
1039
|
+
}
|
|
832
1040
|
}
|
|
833
1041
|
destroy() {
|
|
1042
|
+
if (this.observer) {
|
|
1043
|
+
this.observer.disconnect();
|
|
1044
|
+
this.observer = void 0;
|
|
1045
|
+
}
|
|
1046
|
+
this.renderedIndices.clear();
|
|
834
1047
|
this.el.innerHTML = "";
|
|
835
1048
|
}
|
|
836
|
-
|
|
837
|
-
this.
|
|
1049
|
+
renderAllVisible() {
|
|
1050
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
1051
|
+
items.forEach((item) => {
|
|
1052
|
+
const idx = parseInt(item.dataset.thumbIndex || "-1", 10);
|
|
1053
|
+
if (idx >= 0 && !this.renderedIndices.has(idx)) {
|
|
1054
|
+
this.renderThumbnailItem(idx, item);
|
|
1055
|
+
}
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
renderThumbnailItem(idx, itemEl) {
|
|
1059
|
+
if (this.renderedIndices.has(idx)) return;
|
|
1060
|
+
this.renderedIndices.add(idx);
|
|
1061
|
+
const canvas = itemEl.querySelector("canvas");
|
|
1062
|
+
const thumb = this.thumbnails[idx];
|
|
1063
|
+
if (canvas && thumb) {
|
|
1064
|
+
Promise.resolve(thumb.render(canvas)).catch((err) => {
|
|
1065
|
+
console.warn(`[FilePreview] Error rendering thumbnail ${idx}:`, err);
|
|
1066
|
+
});
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
render() {
|
|
1070
|
+
if (this.observer) {
|
|
1071
|
+
this.observer.disconnect();
|
|
1072
|
+
}
|
|
1073
|
+
this.listEl.innerHTML = "";
|
|
1074
|
+
const useObserver = typeof IntersectionObserver !== "undefined";
|
|
1075
|
+
if (useObserver) {
|
|
1076
|
+
this.observer = new IntersectionObserver(
|
|
1077
|
+
(entries) => {
|
|
1078
|
+
for (const entry of entries) {
|
|
1079
|
+
if (entry.isIntersecting) {
|
|
1080
|
+
const target = entry.target;
|
|
1081
|
+
const idx = parseInt(target.dataset.thumbIndex || "-1", 10);
|
|
1082
|
+
if (idx >= 0) {
|
|
1083
|
+
this.renderThumbnailItem(idx, target);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
},
|
|
1088
|
+
{
|
|
1089
|
+
root: this.listEl,
|
|
1090
|
+
rootMargin: "120px 0px 120px 0px"
|
|
1091
|
+
}
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
838
1094
|
for (let i = 0; i < this.thumbnails.length; i++) {
|
|
839
1095
|
const thumb = this.thumbnails[i];
|
|
840
|
-
const itemEl = createElement("div", {
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
1096
|
+
const itemEl = createElement("div", {
|
|
1097
|
+
className: "fp-thumbnail-item" + (i === this.activeIndex ? " active" : "")
|
|
1098
|
+
});
|
|
1099
|
+
itemEl.dataset.thumbIndex = i.toString();
|
|
844
1100
|
itemEl.addEventListener("click", () => {
|
|
845
1101
|
this.setActive(i);
|
|
846
1102
|
this.onSelect?.(i);
|
|
847
1103
|
});
|
|
848
|
-
const
|
|
849
|
-
const
|
|
850
|
-
|
|
1104
|
+
const canvasWrapper = createElement("div", { className: "fp-thumbnail-canvas-wrapper" });
|
|
1105
|
+
const canvas = createElement("canvas", { width: "130", height: "170" });
|
|
1106
|
+
canvasWrapper.appendChild(canvas);
|
|
1107
|
+
const label = createElement("span", { className: "fp-thumbnail-label" }, thumb.label || `Page ${i + 1}`);
|
|
1108
|
+
itemEl.appendChild(canvasWrapper);
|
|
851
1109
|
itemEl.appendChild(label);
|
|
852
|
-
this.
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
}
|
|
856
|
-
|
|
1110
|
+
this.listEl.appendChild(itemEl);
|
|
1111
|
+
if (this.observer) {
|
|
1112
|
+
this.observer.observe(itemEl);
|
|
1113
|
+
}
|
|
1114
|
+
if (i < 4) {
|
|
1115
|
+
this.renderThumbnailItem(i, itemEl);
|
|
857
1116
|
}
|
|
858
1117
|
}
|
|
859
1118
|
}
|
|
@@ -874,6 +1133,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
874
1133
|
currentOptions = {};
|
|
875
1134
|
resizeObserver = null;
|
|
876
1135
|
fullscreenHandler = null;
|
|
1136
|
+
titleBarEl = null;
|
|
877
1137
|
/**
|
|
878
1138
|
* Register a preview plugin.
|
|
879
1139
|
*/
|
|
@@ -910,6 +1170,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
910
1170
|
}
|
|
911
1171
|
this.currentBuffer = buffer.slice(0);
|
|
912
1172
|
this.currentMetadata = metadata;
|
|
1173
|
+
this.updateTitleBar(options, metadata);
|
|
913
1174
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
914
1175
|
const fileInfo = { metadata, buffer };
|
|
915
1176
|
const matchedPlugin = await this.findPlugin(fileInfo);
|
|
@@ -933,15 +1194,21 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
933
1194
|
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
934
1195
|
const total = payload.total ?? payload.totalPages;
|
|
935
1196
|
this.toolbar?.setPage(payload.page, total);
|
|
1197
|
+
this.thumbnailPanel?.setActive(payload.page - 1);
|
|
936
1198
|
}
|
|
937
1199
|
this.eventEmitter.emit(event, payload);
|
|
938
|
-
}
|
|
1200
|
+
},
|
|
1201
|
+
toggleThumbnails: () => this.toggleThumbnails()
|
|
939
1202
|
});
|
|
940
1203
|
this.activeInstance = instance;
|
|
941
1204
|
instance.openInSeparateWindow = () => this.openInSeparateWindow();
|
|
1205
|
+
instance.toggleThumbnails = () => this.toggleThumbnails();
|
|
942
1206
|
this.hideLoading();
|
|
943
1207
|
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
944
|
-
|
|
1208
|
+
const isToolbarVisible = options.showToolbar !== false && options.toolbar !== false;
|
|
1209
|
+
if (isToolbarVisible && this.toolbar) {
|
|
1210
|
+
const toolbarConfig = this.extractToolbarConfig(options);
|
|
1211
|
+
this.toolbar.setConfig(toolbarConfig);
|
|
945
1212
|
const actions = matchedPlugin.getToolbarActions(instance);
|
|
946
1213
|
const hasFullscreen = actions.some((a) => a.id === "fullscreen");
|
|
947
1214
|
if (!hasFullscreen && this.wrapperEl) {
|
|
@@ -991,6 +1258,12 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
991
1258
|
}
|
|
992
1259
|
});
|
|
993
1260
|
}
|
|
1261
|
+
const thumbAction = actions.find((a) => a.id === "thumbnails");
|
|
1262
|
+
if (thumbAction) {
|
|
1263
|
+
thumbAction.execute = () => {
|
|
1264
|
+
this.toggleThumbnails();
|
|
1265
|
+
};
|
|
1266
|
+
}
|
|
994
1267
|
this.toolbar.update(actions);
|
|
995
1268
|
this.toolbar.show();
|
|
996
1269
|
}
|
|
@@ -1075,7 +1348,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1075
1348
|
if (targetUrl) {
|
|
1076
1349
|
const newWin2 = window.open(targetUrl, "_blank");
|
|
1077
1350
|
if (!newWin2) {
|
|
1078
|
-
|
|
1351
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
1079
1352
|
return null;
|
|
1080
1353
|
}
|
|
1081
1354
|
return newWin2;
|
|
@@ -1083,7 +1356,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1083
1356
|
const title = (this.currentMetadata?.name || "Document Preview") + " - Full Preview";
|
|
1084
1357
|
const newWin = window.open("", "_blank");
|
|
1085
1358
|
if (!newWin) {
|
|
1086
|
-
|
|
1359
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
1087
1360
|
return null;
|
|
1088
1361
|
}
|
|
1089
1362
|
newWin.document.title = title;
|
|
@@ -1160,6 +1433,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1160
1433
|
this.currentBuffer = null;
|
|
1161
1434
|
this.currentMetadata = null;
|
|
1162
1435
|
this.currentContainer = null;
|
|
1436
|
+
this.titleBarEl = null;
|
|
1163
1437
|
}
|
|
1164
1438
|
/**
|
|
1165
1439
|
* Get the currently active preview instance.
|
|
@@ -1167,7 +1441,218 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1167
1441
|
getInstance() {
|
|
1168
1442
|
return this.activeInstance;
|
|
1169
1443
|
}
|
|
1444
|
+
// --- Toolbar Configuration & Feature Toggles ---
|
|
1445
|
+
/**
|
|
1446
|
+
* Configure toolbar features dynamically through options or methods.
|
|
1447
|
+
* e.g. viewer.setToolbarConfig({ zoomIn: false, print: false })
|
|
1448
|
+
*/
|
|
1449
|
+
setToolbarConfig(config) {
|
|
1450
|
+
this.toolbar?.setConfig(config);
|
|
1451
|
+
}
|
|
1452
|
+
/**
|
|
1453
|
+
* Get current toolbar configuration.
|
|
1454
|
+
*/
|
|
1455
|
+
getToolbarConfig() {
|
|
1456
|
+
return this.toolbar?.getConfig() ?? {};
|
|
1457
|
+
}
|
|
1458
|
+
/**
|
|
1459
|
+
* Hide a specific toolbar action by ID or alias (e.g. 'zoom-in', 'print', 'download').
|
|
1460
|
+
*/
|
|
1461
|
+
hideToolbarAction(actionId) {
|
|
1462
|
+
this.toolbar?.hideAction(actionId);
|
|
1463
|
+
}
|
|
1464
|
+
/**
|
|
1465
|
+
* Show a specific toolbar action by ID or alias.
|
|
1466
|
+
*/
|
|
1467
|
+
showToolbarAction(actionId) {
|
|
1468
|
+
this.toolbar?.showAction(actionId);
|
|
1469
|
+
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Enable a specific toolbar action button.
|
|
1472
|
+
*/
|
|
1473
|
+
enableToolbarAction(actionId) {
|
|
1474
|
+
this.toolbar?.enableAction(actionId);
|
|
1475
|
+
}
|
|
1476
|
+
/**
|
|
1477
|
+
* Disable a specific toolbar action button.
|
|
1478
|
+
*/
|
|
1479
|
+
disableToolbarAction(actionId) {
|
|
1480
|
+
this.toolbar?.disableAction(actionId);
|
|
1481
|
+
}
|
|
1482
|
+
// --- Programmatic Toolbar Action Methods ---
|
|
1483
|
+
/**
|
|
1484
|
+
* Fit document to page so it fills the frame width with minimal margins.
|
|
1485
|
+
*/
|
|
1486
|
+
fitToPage() {
|
|
1487
|
+
this.activeInstance?.fitToPage?.();
|
|
1488
|
+
}
|
|
1489
|
+
/**
|
|
1490
|
+
* Zoom in.
|
|
1491
|
+
*/
|
|
1492
|
+
zoomIn() {
|
|
1493
|
+
this.activeInstance?.zoomIn?.();
|
|
1494
|
+
}
|
|
1495
|
+
/**
|
|
1496
|
+
* Zoom out.
|
|
1497
|
+
*/
|
|
1498
|
+
zoomOut() {
|
|
1499
|
+
this.activeInstance?.zoomOut?.();
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* Set specific zoom level.
|
|
1503
|
+
*/
|
|
1504
|
+
setZoom(level) {
|
|
1505
|
+
this.activeInstance?.setZoom?.(level);
|
|
1506
|
+
}
|
|
1507
|
+
/**
|
|
1508
|
+
* Get current zoom level.
|
|
1509
|
+
*/
|
|
1510
|
+
getZoom() {
|
|
1511
|
+
return this.activeInstance?.getZoom?.() ?? 1;
|
|
1512
|
+
}
|
|
1513
|
+
/**
|
|
1514
|
+
* Rotate 90 degrees clockwise.
|
|
1515
|
+
*/
|
|
1516
|
+
rotateCW() {
|
|
1517
|
+
this.activeInstance?.rotateCW?.();
|
|
1518
|
+
}
|
|
1519
|
+
/**
|
|
1520
|
+
* Rotate 90 degrees counter-clockwise.
|
|
1521
|
+
*/
|
|
1522
|
+
rotateCCW() {
|
|
1523
|
+
this.activeInstance?.rotateCCW?.();
|
|
1524
|
+
}
|
|
1525
|
+
/**
|
|
1526
|
+
* Navigate to a specific page number.
|
|
1527
|
+
*/
|
|
1528
|
+
goToPage(page) {
|
|
1529
|
+
this.activeInstance?.goToPage?.(page);
|
|
1530
|
+
this.toolbar?.setPage(page);
|
|
1531
|
+
}
|
|
1532
|
+
/**
|
|
1533
|
+
* Navigate to next page.
|
|
1534
|
+
*/
|
|
1535
|
+
nextPage() {
|
|
1536
|
+
const cur = this.getCurrentPage();
|
|
1537
|
+
const max = this.getPageCount();
|
|
1538
|
+
if (cur < max) {
|
|
1539
|
+
this.goToPage(cur + 1);
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
/**
|
|
1543
|
+
* Navigate to previous page.
|
|
1544
|
+
*/
|
|
1545
|
+
prevPage() {
|
|
1546
|
+
const cur = this.getCurrentPage();
|
|
1547
|
+
if (cur > 1) {
|
|
1548
|
+
this.goToPage(cur - 1);
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
/**
|
|
1552
|
+
* Get total page count.
|
|
1553
|
+
*/
|
|
1554
|
+
getPageCount() {
|
|
1555
|
+
return this.activeInstance?.getPageCount?.() ?? 1;
|
|
1556
|
+
}
|
|
1557
|
+
/**
|
|
1558
|
+
* Get current page number.
|
|
1559
|
+
*/
|
|
1560
|
+
getCurrentPage() {
|
|
1561
|
+
return this.activeInstance?.getCurrentPage?.() ?? 1;
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* Download the current document.
|
|
1565
|
+
*/
|
|
1566
|
+
download() {
|
|
1567
|
+
this.activeInstance?.download?.();
|
|
1568
|
+
}
|
|
1569
|
+
/**
|
|
1570
|
+
* Print the current document.
|
|
1571
|
+
*/
|
|
1572
|
+
print() {
|
|
1573
|
+
this.activeInstance?.print?.();
|
|
1574
|
+
}
|
|
1575
|
+
/**
|
|
1576
|
+
* Toggle fullscreen mode.
|
|
1577
|
+
*/
|
|
1578
|
+
toggleFullscreen() {
|
|
1579
|
+
try {
|
|
1580
|
+
if (!document.fullscreenElement) {
|
|
1581
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
1582
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
1583
|
+
} else {
|
|
1584
|
+
document.exitFullscreen?.();
|
|
1585
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
1586
|
+
}
|
|
1587
|
+
} catch {
|
|
1588
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
1589
|
+
}
|
|
1590
|
+
setTimeout(() => {
|
|
1591
|
+
this.activeInstance?.fitToPage?.();
|
|
1592
|
+
}, 120);
|
|
1593
|
+
}
|
|
1594
|
+
/**
|
|
1595
|
+
* Toggle thumbnails sidebar panel.
|
|
1596
|
+
*/
|
|
1597
|
+
toggleThumbnails() {
|
|
1598
|
+
if (!this.thumbnailPanel) return;
|
|
1599
|
+
this.thumbnailPanel.toggle();
|
|
1600
|
+
const isOpen = this.thumbnailPanel.isOpen();
|
|
1601
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1602
|
+
setTimeout(() => {
|
|
1603
|
+
this.activeInstance?.fitToPage?.();
|
|
1604
|
+
}, 260);
|
|
1605
|
+
}
|
|
1606
|
+
/**
|
|
1607
|
+
* Set whether to display the file name / title bar above the toolbar.
|
|
1608
|
+
*/
|
|
1609
|
+
setShowFileName(show) {
|
|
1610
|
+
if (this.currentOptions) {
|
|
1611
|
+
this.currentOptions.showFileName = show;
|
|
1612
|
+
}
|
|
1613
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1614
|
+
}
|
|
1615
|
+
/**
|
|
1616
|
+
* Set or override the displayed file name in the preview panel.
|
|
1617
|
+
*/
|
|
1618
|
+
setFileName(name) {
|
|
1619
|
+
if (this.currentOptions) {
|
|
1620
|
+
this.currentOptions.fileName = name;
|
|
1621
|
+
}
|
|
1622
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1623
|
+
}
|
|
1170
1624
|
// --- Private methods ---
|
|
1625
|
+
updateTitleBar(options, metadata) {
|
|
1626
|
+
if (!this.titleBarEl) return;
|
|
1627
|
+
const show = options?.showFileName !== false;
|
|
1628
|
+
if (!show) {
|
|
1629
|
+
this.titleBarEl.style.display = "none";
|
|
1630
|
+
return;
|
|
1631
|
+
}
|
|
1632
|
+
const name = options?.fileName || metadata?.name || this.currentMetadata?.name || "";
|
|
1633
|
+
if (!name) {
|
|
1634
|
+
this.titleBarEl.style.display = "none";
|
|
1635
|
+
return;
|
|
1636
|
+
}
|
|
1637
|
+
this.titleBarEl.style.display = "flex";
|
|
1638
|
+
const ext = metadata?.extension || (name.includes(".") ? "." + name.split(".").pop() : "");
|
|
1639
|
+
const badge = ext ? ext.replace(".", "").toUpperCase() : "";
|
|
1640
|
+
this.titleBarEl.innerHTML = `
|
|
1641
|
+
<div class="fp-titlebar-info">
|
|
1642
|
+
<span class="fp-titlebar-icon">\u{1F4C4}</span>
|
|
1643
|
+
<span class="fp-titlebar-name" title="${name}">${name}</span>
|
|
1644
|
+
${badge ? `<span class="fp-titlebar-badge">${badge}</span>` : ""}
|
|
1645
|
+
</div>
|
|
1646
|
+
`;
|
|
1647
|
+
}
|
|
1648
|
+
extractToolbarConfig(options) {
|
|
1649
|
+
if (!options) return {};
|
|
1650
|
+
const nested = typeof options.toolbar === "object" ? options.toolbar : {};
|
|
1651
|
+
return {
|
|
1652
|
+
...options,
|
|
1653
|
+
...nested
|
|
1654
|
+
};
|
|
1655
|
+
}
|
|
1171
1656
|
abort() {
|
|
1172
1657
|
if (this.abortController) {
|
|
1173
1658
|
this.abortController.abort();
|
|
@@ -1210,17 +1695,29 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1210
1695
|
bodyEl.className = "fp-body";
|
|
1211
1696
|
bodyEl.appendChild(thumbnailEl);
|
|
1212
1697
|
bodyEl.appendChild(this.contentEl);
|
|
1698
|
+
const titleBarEl = document.createElement("div");
|
|
1699
|
+
titleBarEl.className = "fp-titlebar";
|
|
1700
|
+
this.titleBarEl = titleBarEl;
|
|
1701
|
+
this.updateTitleBar(options, this.currentMetadata);
|
|
1213
1702
|
if (toolbarPos === "top") {
|
|
1703
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1214
1704
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1215
1705
|
this.wrapperEl.appendChild(bodyEl);
|
|
1216
1706
|
} else {
|
|
1707
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1217
1708
|
this.wrapperEl.appendChild(bodyEl);
|
|
1218
1709
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1219
1710
|
}
|
|
1220
1711
|
container.innerHTML = "";
|
|
1221
1712
|
container.appendChild(this.wrapperEl);
|
|
1222
|
-
|
|
1223
|
-
this.
|
|
1713
|
+
const initialToolbarConfig = this.extractToolbarConfig(options);
|
|
1714
|
+
this.toolbar = new ToolbarController(toolbarEl, initialToolbarConfig);
|
|
1715
|
+
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl, (isOpen) => {
|
|
1716
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1717
|
+
setTimeout(() => {
|
|
1718
|
+
this.activeInstance?.fitToPage?.();
|
|
1719
|
+
}, 260);
|
|
1720
|
+
});
|
|
1224
1721
|
this.setupKeyboardShortcuts();
|
|
1225
1722
|
this.setupDragAndDrop(container, options);
|
|
1226
1723
|
this.setupResizeAndFullscreenListeners();
|
|
@@ -1610,6 +2107,14 @@ var PdfPlugin = class {
|
|
|
1610
2107
|
group: "zoom",
|
|
1611
2108
|
execute: () => instance.fitToPage?.()
|
|
1612
2109
|
},
|
|
2110
|
+
{
|
|
2111
|
+
id: "fit-width",
|
|
2112
|
+
icon: "fit-width",
|
|
2113
|
+
label: "Fit to Width",
|
|
2114
|
+
type: "button",
|
|
2115
|
+
group: "zoom",
|
|
2116
|
+
execute: () => instance.fitToWidth?.()
|
|
2117
|
+
},
|
|
1613
2118
|
{
|
|
1614
2119
|
id: "rotate-cw",
|
|
1615
2120
|
icon: "rotate-cw",
|
|
@@ -1618,6 +2123,14 @@ var PdfPlugin = class {
|
|
|
1618
2123
|
group: "view",
|
|
1619
2124
|
execute: () => instance.rotateCW?.()
|
|
1620
2125
|
},
|
|
2126
|
+
{
|
|
2127
|
+
id: "rotate-ccw",
|
|
2128
|
+
icon: "rotate-ccw",
|
|
2129
|
+
label: "Rotate Counter-Clockwise",
|
|
2130
|
+
type: "button",
|
|
2131
|
+
group: "view",
|
|
2132
|
+
execute: () => instance.rotateCCW?.()
|
|
2133
|
+
},
|
|
1621
2134
|
{
|
|
1622
2135
|
id: "download",
|
|
1623
2136
|
icon: "download",
|
|
@@ -1649,12 +2162,13 @@ var PdfPlugin = class {
|
|
|
1649
2162
|
container.className = "fp-pdf-container";
|
|
1650
2163
|
container.style.width = "100%";
|
|
1651
2164
|
container.style.height = "100%";
|
|
1652
|
-
container.style.
|
|
2165
|
+
container.style.overflowX = "hidden";
|
|
2166
|
+
container.style.overflowY = "auto";
|
|
1653
2167
|
container.style.display = "flex";
|
|
1654
2168
|
container.style.flexDirection = "column";
|
|
1655
2169
|
container.style.alignItems = "center";
|
|
1656
2170
|
container.style.justifyContent = "flex-start";
|
|
1657
|
-
container.style.padding = "
|
|
2171
|
+
container.style.padding = "16px 8px";
|
|
1658
2172
|
container.style.backgroundColor = "#0f172a";
|
|
1659
2173
|
container.style.boxSizing = "border-box";
|
|
1660
2174
|
container.style.position = "relative";
|
|
@@ -1665,30 +2179,12 @@ var PdfPlugin = class {
|
|
|
1665
2179
|
pageCard.style.borderRadius = "4px";
|
|
1666
2180
|
pageCard.style.overflow = "hidden";
|
|
1667
2181
|
pageCard.style.lineHeight = "0";
|
|
1668
|
-
pageCard.style.transition = "transform 0.15s ease";
|
|
1669
2182
|
pageCard.style.position = "relative";
|
|
1670
2183
|
pageCard.style.flexShrink = "0";
|
|
2184
|
+
pageCard.style.transition = "box-shadow 0.2s ease";
|
|
1671
2185
|
let canvas = document.createElement("canvas");
|
|
1672
2186
|
pageCard.appendChild(canvas);
|
|
1673
2187
|
container.appendChild(pageCard);
|
|
1674
|
-
const indicator = document.createElement("div");
|
|
1675
|
-
indicator.className = "fp-pdf-page-indicator";
|
|
1676
|
-
indicator.style.position = "sticky";
|
|
1677
|
-
indicator.style.bottom = "16px";
|
|
1678
|
-
indicator.style.marginTop = "16px";
|
|
1679
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1680
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
1681
|
-
indicator.style.color = "#f8fafc";
|
|
1682
|
-
indicator.style.fontSize = "12px";
|
|
1683
|
-
indicator.style.fontWeight = "600";
|
|
1684
|
-
indicator.style.padding = "5px 14px";
|
|
1685
|
-
indicator.style.borderRadius = "20px";
|
|
1686
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1687
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1688
|
-
indicator.style.zIndex = "10";
|
|
1689
|
-
indicator.style.userSelect = "none";
|
|
1690
|
-
indicator.style.pointerEvents = "none";
|
|
1691
|
-
container.appendChild(indicator);
|
|
1692
2188
|
ctx.container.appendChild(container);
|
|
1693
2189
|
const standardFontsUrl = typeof window !== "undefined" && window.__PDF_STANDARD_FONTS_URL__ || "./standard_fonts/";
|
|
1694
2190
|
const cmapsUrl = typeof window !== "undefined" && window.__PDF_CMAPS_URL__ || "./cmaps/";
|
|
@@ -1704,8 +2200,9 @@ var PdfPlugin = class {
|
|
|
1704
2200
|
let currentPage = 1;
|
|
1705
2201
|
let zoomScale = 1;
|
|
1706
2202
|
let rotation = 0;
|
|
1707
|
-
let fitMode = "
|
|
2203
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
1708
2204
|
let currentRenderTask = null;
|
|
2205
|
+
let textLayerDiv = null;
|
|
1709
2206
|
const renderPage = async (pageNum) => {
|
|
1710
2207
|
if (currentRenderTask) {
|
|
1711
2208
|
try {
|
|
@@ -1717,30 +2214,37 @@ var PdfPlugin = class {
|
|
|
1717
2214
|
const newCanvas = document.createElement("canvas");
|
|
1718
2215
|
pageCard.replaceChild(newCanvas, canvas);
|
|
1719
2216
|
canvas = newCanvas;
|
|
2217
|
+
if (textLayerDiv) {
|
|
2218
|
+
textLayerDiv.remove();
|
|
2219
|
+
textLayerDiv = null;
|
|
2220
|
+
}
|
|
1720
2221
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1721
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1722
2222
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1723
2223
|
const page = await pdfDoc.getPage(currentPage);
|
|
1724
2224
|
const containerWidth = container.clientWidth || 900;
|
|
1725
2225
|
const containerHeight = container.clientHeight || 700;
|
|
1726
2226
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1727
|
-
const availWidth = Math.max(
|
|
1728
|
-
const availHeight = Math.max(
|
|
2227
|
+
const availWidth = Math.max(280, containerWidth - 36);
|
|
2228
|
+
const availHeight = Math.max(280, containerHeight - 32);
|
|
1729
2229
|
const scaleW = availWidth / unscaledVp.width;
|
|
1730
2230
|
const scaleH = availHeight / unscaledVp.height;
|
|
1731
2231
|
let fitScale;
|
|
1732
2232
|
if (fitMode === "page") {
|
|
1733
|
-
fitScale = Math.max(0.4, Math.min(scaleW, scaleH));
|
|
2233
|
+
fitScale = Math.max(0.2, Math.min(4, Math.min(scaleW, scaleH)));
|
|
1734
2234
|
} else {
|
|
1735
|
-
fitScale = Math.max(0.
|
|
2235
|
+
fitScale = Math.max(0.2, Math.min(4, scaleW));
|
|
1736
2236
|
}
|
|
1737
2237
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1738
2238
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1739
2239
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
2240
|
+
const displayWidth = Math.floor(viewport.width);
|
|
2241
|
+
const displayHeight = Math.floor(viewport.height);
|
|
1740
2242
|
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1741
2243
|
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1742
|
-
canvas.style.width = `${
|
|
1743
|
-
canvas.style.height = `${
|
|
2244
|
+
canvas.style.width = `${displayWidth}px`;
|
|
2245
|
+
canvas.style.height = `${displayHeight}px`;
|
|
2246
|
+
pageCard.style.width = `${displayWidth}px`;
|
|
2247
|
+
pageCard.style.height = `${displayHeight}px`;
|
|
1744
2248
|
const canvasCtx = canvas.getContext("2d");
|
|
1745
2249
|
if (!canvasCtx) return;
|
|
1746
2250
|
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
@@ -1754,9 +2258,31 @@ var PdfPlugin = class {
|
|
|
1754
2258
|
if (err?.name !== "RenderingCancelledException") {
|
|
1755
2259
|
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1756
2260
|
}
|
|
2261
|
+
return;
|
|
1757
2262
|
} finally {
|
|
1758
2263
|
currentRenderTask = null;
|
|
1759
2264
|
}
|
|
2265
|
+
try {
|
|
2266
|
+
textLayerDiv = document.createElement("div");
|
|
2267
|
+
textLayerDiv.className = "textLayer";
|
|
2268
|
+
textLayerDiv.style.width = `${displayWidth}px`;
|
|
2269
|
+
textLayerDiv.style.height = `${displayHeight}px`;
|
|
2270
|
+
textLayerDiv.style.position = "absolute";
|
|
2271
|
+
textLayerDiv.style.top = "0";
|
|
2272
|
+
textLayerDiv.style.left = "0";
|
|
2273
|
+
textLayerDiv.style.lineHeight = "1";
|
|
2274
|
+
pageCard.appendChild(textLayerDiv);
|
|
2275
|
+
if (pdfjsLib__namespace.TextLayer) {
|
|
2276
|
+
const textLayer = new pdfjsLib__namespace.TextLayer({
|
|
2277
|
+
textContentSource: page.streamTextContent(),
|
|
2278
|
+
container: textLayerDiv,
|
|
2279
|
+
viewport
|
|
2280
|
+
});
|
|
2281
|
+
await textLayer.render();
|
|
2282
|
+
}
|
|
2283
|
+
} catch (err) {
|
|
2284
|
+
console.debug("[PdfPlugin] TextLayer notice:", err);
|
|
2285
|
+
}
|
|
1760
2286
|
};
|
|
1761
2287
|
renderPage(1);
|
|
1762
2288
|
let resizeTimer = null;
|
|
@@ -1766,11 +2292,48 @@ var PdfPlugin = class {
|
|
|
1766
2292
|
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1767
2293
|
renderPage(currentPage);
|
|
1768
2294
|
}
|
|
1769
|
-
},
|
|
2295
|
+
}, 120);
|
|
1770
2296
|
});
|
|
1771
2297
|
resizeObserver.observe(container);
|
|
2298
|
+
const onWheel = (e) => {
|
|
2299
|
+
if (e.ctrlKey || e.metaKey) {
|
|
2300
|
+
e.preventDefault();
|
|
2301
|
+
const delta = e.deltaY > 0 ? -0.15 : 0.15;
|
|
2302
|
+
zoomScale = Math.max(0.25, Math.min(4, Math.round((zoomScale + delta) * 100) / 100));
|
|
2303
|
+
renderPage(currentPage);
|
|
2304
|
+
}
|
|
2305
|
+
};
|
|
2306
|
+
container.addEventListener("wheel", onWheel, { passive: false });
|
|
2307
|
+
const onKeyDown = (e) => {
|
|
2308
|
+
const tag = e.target?.tagName?.toLowerCase();
|
|
2309
|
+
if (tag === "input" || tag === "textarea" || tag === "select") return;
|
|
2310
|
+
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
2311
|
+
if (currentPage < totalPages) {
|
|
2312
|
+
e.preventDefault();
|
|
2313
|
+
container.scrollTop = 0;
|
|
2314
|
+
renderPage(currentPage + 1);
|
|
2315
|
+
}
|
|
2316
|
+
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
2317
|
+
if (currentPage > 1) {
|
|
2318
|
+
e.preventDefault();
|
|
2319
|
+
container.scrollTop = 0;
|
|
2320
|
+
renderPage(currentPage - 1);
|
|
2321
|
+
}
|
|
2322
|
+
} else if (e.key === "Home") {
|
|
2323
|
+
e.preventDefault();
|
|
2324
|
+
container.scrollTop = 0;
|
|
2325
|
+
renderPage(1);
|
|
2326
|
+
} else if (e.key === "End") {
|
|
2327
|
+
e.preventDefault();
|
|
2328
|
+
container.scrollTop = 0;
|
|
2329
|
+
renderPage(totalPages);
|
|
2330
|
+
}
|
|
2331
|
+
};
|
|
2332
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1772
2333
|
const cleanup = () => {
|
|
1773
2334
|
resizeObserver.disconnect();
|
|
2335
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
2336
|
+
container.removeEventListener("wheel", onWheel);
|
|
1774
2337
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1775
2338
|
if (currentRenderTask) {
|
|
1776
2339
|
try {
|
|
@@ -1789,22 +2352,26 @@ var PdfPlugin = class {
|
|
|
1789
2352
|
const instance = {
|
|
1790
2353
|
destroy: cleanup,
|
|
1791
2354
|
zoomIn: () => {
|
|
1792
|
-
zoomScale = Math.min(
|
|
2355
|
+
zoomScale = Math.min(4, Math.round((zoomScale + 0.2) * 10) / 10);
|
|
1793
2356
|
renderPage(currentPage);
|
|
1794
2357
|
},
|
|
1795
2358
|
zoomOut: () => {
|
|
1796
|
-
zoomScale = Math.max(0.
|
|
2359
|
+
zoomScale = Math.max(0.25, Math.round((zoomScale - 0.2) * 10) / 10);
|
|
1797
2360
|
renderPage(currentPage);
|
|
1798
2361
|
},
|
|
1799
2362
|
getZoom: () => zoomScale,
|
|
1800
2363
|
setZoom: (level) => {
|
|
1801
|
-
zoomScale = Math.max(0.
|
|
2364
|
+
zoomScale = Math.max(0.25, Math.min(4, level));
|
|
1802
2365
|
renderPage(currentPage);
|
|
1803
2366
|
},
|
|
1804
2367
|
fitToPage: () => {
|
|
1805
|
-
fitMode =
|
|
2368
|
+
fitMode = "page";
|
|
2369
|
+
zoomScale = 1;
|
|
2370
|
+
renderPage(currentPage);
|
|
2371
|
+
},
|
|
2372
|
+
fitToWidth: () => {
|
|
2373
|
+
fitMode = "width";
|
|
1806
2374
|
zoomScale = 1;
|
|
1807
|
-
rotation = 0;
|
|
1808
2375
|
renderPage(currentPage);
|
|
1809
2376
|
},
|
|
1810
2377
|
rotateCW: () => {
|
|
@@ -1822,6 +2389,9 @@ var PdfPlugin = class {
|
|
|
1822
2389
|
container.scrollTop = 0;
|
|
1823
2390
|
renderPage(page);
|
|
1824
2391
|
},
|
|
2392
|
+
toggleThumbnails: () => {
|
|
2393
|
+
ctx?.toggleThumbnails?.();
|
|
2394
|
+
},
|
|
1825
2395
|
download: () => {
|
|
1826
2396
|
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1827
2397
|
const url = URL.createObjectURL(blob);
|
|
@@ -1855,7 +2425,7 @@ var PdfPlugin = class {
|
|
|
1855
2425
|
},
|
|
1856
2426
|
getThumbnails: async () => {
|
|
1857
2427
|
const thumbnails = [];
|
|
1858
|
-
const count =
|
|
2428
|
+
const count = totalPages;
|
|
1859
2429
|
for (let i = 1; i <= count; i++) {
|
|
1860
2430
|
thumbnails.push({
|
|
1861
2431
|
index: i,
|
|
@@ -1863,9 +2433,10 @@ var PdfPlugin = class {
|
|
|
1863
2433
|
render: async (thumbCanvas) => {
|
|
1864
2434
|
try {
|
|
1865
2435
|
const p = await pdfDoc.getPage(i);
|
|
1866
|
-
const baseVp = p.getViewport({ scale: 1 });
|
|
1867
|
-
const
|
|
1868
|
-
const
|
|
2436
|
+
const baseVp = p.getViewport({ scale: 1, rotation });
|
|
2437
|
+
const targetW = thumbCanvas.width || 130;
|
|
2438
|
+
const thumbScale = targetW / baseVp.width;
|
|
2439
|
+
const thumbVp = p.getViewport({ scale: thumbScale, rotation });
|
|
1869
2440
|
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1870
2441
|
const tCtx = thumbCanvas.getContext("2d");
|
|
1871
2442
|
if (tCtx) {
|
|
@@ -2209,28 +2780,26 @@ var DocxPlugin = class {
|
|
|
2209
2780
|
getToolbarActions(instance) {
|
|
2210
2781
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2211
2782
|
const actions = [];
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
if (
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
instance.goToPage?.(page);
|
|
2230
|
-
}
|
|
2783
|
+
actions.push({
|
|
2784
|
+
id: "page-nav",
|
|
2785
|
+
icon: "",
|
|
2786
|
+
label: "Page Navigation",
|
|
2787
|
+
type: "page-nav",
|
|
2788
|
+
group: "navigation",
|
|
2789
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2790
|
+
max: totalPages,
|
|
2791
|
+
execute: (action, page) => {
|
|
2792
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2793
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2794
|
+
if (action === "prev") {
|
|
2795
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2796
|
+
} else if (action === "next") {
|
|
2797
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2798
|
+
} else if (typeof page === "number") {
|
|
2799
|
+
instance.goToPage?.(page);
|
|
2231
2800
|
}
|
|
2232
|
-
}
|
|
2233
|
-
}
|
|
2801
|
+
}
|
|
2802
|
+
});
|
|
2234
2803
|
actions.push(
|
|
2235
2804
|
{
|
|
2236
2805
|
id: "zoom-out",
|
|
@@ -2296,11 +2865,17 @@ var DocxPlugin = class {
|
|
|
2296
2865
|
wrapper.className = "fp-docx-wrapper";
|
|
2297
2866
|
wrapper.style.transformOrigin = "top center";
|
|
2298
2867
|
wrapper.style.transition = "transform 0.2s ease";
|
|
2299
|
-
wrapper.style.padding = "
|
|
2300
|
-
wrapper.style.maxWidth = "
|
|
2868
|
+
wrapper.style.padding = "0";
|
|
2869
|
+
wrapper.style.maxWidth = "none";
|
|
2870
|
+
wrapper.style.width = "816px";
|
|
2301
2871
|
wrapper.style.margin = "0 auto";
|
|
2872
|
+
wrapper.style.display = "flex";
|
|
2873
|
+
wrapper.style.flexDirection = "column";
|
|
2874
|
+
wrapper.style.alignItems = "center";
|
|
2302
2875
|
wrapper.style.boxSizing = "border-box";
|
|
2303
|
-
ctx.container.style.
|
|
2876
|
+
ctx.container.style.overflowX = "hidden";
|
|
2877
|
+
ctx.container.style.overflowY = "auto";
|
|
2878
|
+
ctx.container.style.padding = "16px 8px";
|
|
2304
2879
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
2305
2880
|
ctx.container.appendChild(wrapper);
|
|
2306
2881
|
const styleOverride = document.createElement("style");
|
|
@@ -2474,39 +3049,13 @@ var DocxPlugin = class {
|
|
|
2474
3049
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2475
3050
|
const totalPages = Math.max(1, pageElements.length);
|
|
2476
3051
|
let currentPage = 1;
|
|
2477
|
-
let indicator = null;
|
|
2478
|
-
if (totalPages > 1) {
|
|
2479
|
-
indicator = document.createElement("div");
|
|
2480
|
-
indicator.className = "fp-docx-page-indicator";
|
|
2481
|
-
indicator.style.position = "sticky";
|
|
2482
|
-
indicator.style.bottom = "16px";
|
|
2483
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2484
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
2485
|
-
indicator.style.color = "#f8fafc";
|
|
2486
|
-
indicator.style.fontSize = "12px";
|
|
2487
|
-
indicator.style.fontWeight = "600";
|
|
2488
|
-
indicator.style.padding = "5px 14px";
|
|
2489
|
-
indicator.style.borderRadius = "20px";
|
|
2490
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2491
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2492
|
-
indicator.style.zIndex = "10";
|
|
2493
|
-
indicator.style.userSelect = "none";
|
|
2494
|
-
indicator.style.pointerEvents = "none";
|
|
2495
|
-
indicator.style.textAlign = "center";
|
|
2496
|
-
indicator.style.width = "fit-content";
|
|
2497
|
-
indicator.style.margin = "16px auto 0";
|
|
2498
|
-
ctx.container.appendChild(indicator);
|
|
2499
|
-
}
|
|
2500
3052
|
const showPage = (pageNum) => {
|
|
2501
3053
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2502
3054
|
if (pageElements.length > 1) {
|
|
2503
3055
|
pageElements.forEach((sec, idx) => {
|
|
2504
|
-
sec.style.display = idx + 1 === currentPage ? "
|
|
3056
|
+
sec.style.display = idx + 1 === currentPage ? "" : "none";
|
|
2505
3057
|
});
|
|
2506
3058
|
}
|
|
2507
|
-
if (indicator) {
|
|
2508
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2509
|
-
}
|
|
2510
3059
|
ctx.container.scrollTop = 0;
|
|
2511
3060
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2512
3061
|
};
|
|
@@ -2515,31 +3064,46 @@ var DocxPlugin = class {
|
|
|
2515
3064
|
}
|
|
2516
3065
|
scale = 1;
|
|
2517
3066
|
let rotation = 0;
|
|
2518
|
-
let fitMode = "
|
|
2519
|
-
|
|
2520
|
-
|
|
3067
|
+
let fitMode = "page";
|
|
3068
|
+
let isUserZoomed = false;
|
|
3069
|
+
const calculateFitScale = (_mode = fitMode) => {
|
|
3070
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
2521
3071
|
const elW = activeEl.offsetWidth || 816;
|
|
2522
|
-
const
|
|
2523
|
-
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
2524
|
-
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
3072
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
2525
3073
|
const sW = availW / elW;
|
|
2526
|
-
|
|
2527
|
-
if (mode === "page") {
|
|
2528
|
-
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
2529
|
-
}
|
|
2530
|
-
return Math.max(0.65, Math.min(1.05, sW));
|
|
3074
|
+
return Math.max(0.35, Math.min(3, sW));
|
|
2531
3075
|
};
|
|
2532
3076
|
const applyTransform = () => {
|
|
2533
3077
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2534
3078
|
wrapper.style.transformOrigin = "top center";
|
|
3079
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
3080
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
3081
|
+
if (scale > 1) {
|
|
3082
|
+
wrapper.style.marginBottom = `${Math.round(elH * scale - elH + 32)}px`;
|
|
3083
|
+
} else {
|
|
3084
|
+
wrapper.style.marginBottom = "32px";
|
|
3085
|
+
}
|
|
2535
3086
|
};
|
|
3087
|
+
let resizeObserver = null;
|
|
3088
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
3089
|
+
resizeObserver = new ResizeObserver(() => {
|
|
3090
|
+
if (!isUserZoomed) {
|
|
3091
|
+
const newFit = calculateFitScale("page");
|
|
3092
|
+
if (Math.abs(scale - newFit) > 0.015) {
|
|
3093
|
+
scale = newFit;
|
|
3094
|
+
applyTransform();
|
|
3095
|
+
}
|
|
3096
|
+
}
|
|
3097
|
+
});
|
|
3098
|
+
resizeObserver.observe(ctx.container);
|
|
3099
|
+
}
|
|
2536
3100
|
setTimeout(() => {
|
|
2537
|
-
|
|
2538
|
-
scale = calculateFitScale("width");
|
|
3101
|
+
scale = calculateFitScale("page");
|
|
2539
3102
|
applyTransform();
|
|
2540
|
-
},
|
|
3103
|
+
}, 40);
|
|
2541
3104
|
const cleanup = () => {
|
|
2542
|
-
|
|
3105
|
+
resizeObserver?.disconnect();
|
|
3106
|
+
resizeObserver = null;
|
|
2543
3107
|
for (const url of createdBlobUrls) {
|
|
2544
3108
|
URL.revokeObjectURL(url);
|
|
2545
3109
|
}
|
|
@@ -2556,21 +3120,24 @@ var DocxPlugin = class {
|
|
|
2556
3120
|
showPage(page);
|
|
2557
3121
|
},
|
|
2558
3122
|
zoomIn: () => {
|
|
2559
|
-
|
|
3123
|
+
isUserZoomed = true;
|
|
3124
|
+
scale = Math.min(3.5, scale + 0.15);
|
|
2560
3125
|
applyTransform();
|
|
2561
3126
|
},
|
|
2562
3127
|
zoomOut: () => {
|
|
3128
|
+
isUserZoomed = true;
|
|
2563
3129
|
scale = Math.max(0.2, scale - 0.15);
|
|
2564
3130
|
applyTransform();
|
|
2565
3131
|
},
|
|
2566
3132
|
getZoom: () => scale,
|
|
2567
3133
|
setZoom: (level) => {
|
|
3134
|
+
isUserZoomed = true;
|
|
2568
3135
|
scale = level;
|
|
2569
3136
|
applyTransform();
|
|
2570
3137
|
},
|
|
2571
3138
|
fitToPage: () => {
|
|
2572
|
-
|
|
2573
|
-
scale = calculateFitScale(
|
|
3139
|
+
isUserZoomed = false;
|
|
3140
|
+
scale = calculateFitScale("page");
|
|
2574
3141
|
rotation = 0;
|
|
2575
3142
|
applyTransform();
|
|
2576
3143
|
},
|
|
@@ -2960,7 +3527,7 @@ var ExcelPlugin = class {
|
|
|
2960
3527
|
"application/vnd.ms-excel.template.macroEnabled.12",
|
|
2961
3528
|
"application/vnd.oasis.opendocument.spreadsheet"
|
|
2962
3529
|
];
|
|
2963
|
-
weight =
|
|
3530
|
+
weight = 85;
|
|
2964
3531
|
supports(file) {
|
|
2965
3532
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2966
3533
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
@@ -2972,6 +3539,14 @@ var ExcelPlugin = class {
|
|
|
2972
3539
|
getToolbarActions(instance) {
|
|
2973
3540
|
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2974
3541
|
const actions = [];
|
|
3542
|
+
actions.push({
|
|
3543
|
+
id: "thumbnails",
|
|
3544
|
+
icon: "thumbnails",
|
|
3545
|
+
label: "Sheet Thumbnails",
|
|
3546
|
+
type: "button",
|
|
3547
|
+
group: "navigation",
|
|
3548
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3549
|
+
});
|
|
2975
3550
|
if (totalSheets > 1) {
|
|
2976
3551
|
actions.push({
|
|
2977
3552
|
id: "page-nav",
|
|
@@ -3015,26 +3590,6 @@ var ExcelPlugin = class {
|
|
|
3015
3590
|
instance.zoomIn?.();
|
|
3016
3591
|
}
|
|
3017
3592
|
},
|
|
3018
|
-
{
|
|
3019
|
-
id: "fit-page",
|
|
3020
|
-
icon: "fit-page",
|
|
3021
|
-
label: "Fit to View",
|
|
3022
|
-
type: "button",
|
|
3023
|
-
group: "zoom",
|
|
3024
|
-
execute: () => {
|
|
3025
|
-
instance.fitToPage?.();
|
|
3026
|
-
}
|
|
3027
|
-
},
|
|
3028
|
-
{
|
|
3029
|
-
id: "rotate-cw",
|
|
3030
|
-
icon: "rotate-cw",
|
|
3031
|
-
label: "Rotate",
|
|
3032
|
-
type: "button",
|
|
3033
|
-
group: "view",
|
|
3034
|
-
execute: () => {
|
|
3035
|
-
instance.rotateCW?.();
|
|
3036
|
-
}
|
|
3037
|
-
},
|
|
3038
3593
|
{
|
|
3039
3594
|
id: "download",
|
|
3040
3595
|
icon: "download",
|
|
@@ -3054,6 +3609,16 @@ var ExcelPlugin = class {
|
|
|
3054
3609
|
execute: () => {
|
|
3055
3610
|
instance.print?.();
|
|
3056
3611
|
}
|
|
3612
|
+
},
|
|
3613
|
+
{
|
|
3614
|
+
id: "open-window",
|
|
3615
|
+
icon: "open-window",
|
|
3616
|
+
label: "Open in Separate Full Window",
|
|
3617
|
+
type: "button",
|
|
3618
|
+
group: "actions",
|
|
3619
|
+
execute: () => {
|
|
3620
|
+
instance.openInSeparateWindow?.();
|
|
3621
|
+
}
|
|
3057
3622
|
}
|
|
3058
3623
|
);
|
|
3059
3624
|
return actions;
|
|
@@ -3085,12 +3650,11 @@ var ExcelPlugin = class {
|
|
|
3085
3650
|
container.appendChild(tabsArea);
|
|
3086
3651
|
ctx.container.appendChild(container);
|
|
3087
3652
|
let scale = 1;
|
|
3088
|
-
let rotation = 0;
|
|
3089
3653
|
let currentSheetIndex = 1;
|
|
3090
3654
|
let sheetNames = [];
|
|
3091
3655
|
let wb = null;
|
|
3092
3656
|
const applyTransform = () => {
|
|
3093
|
-
contentArea.style.transform = `scale(${scale})
|
|
3657
|
+
contentArea.style.transform = `scale(${scale})`;
|
|
3094
3658
|
contentArea.style.transformOrigin = "top left";
|
|
3095
3659
|
};
|
|
3096
3660
|
const calculateFitScale = () => {
|
|
@@ -3098,7 +3662,7 @@ var ExcelPlugin = class {
|
|
|
3098
3662
|
if (!table) return 1;
|
|
3099
3663
|
const availW = Math.max(280, container.clientWidth - 48);
|
|
3100
3664
|
const tW = table.offsetWidth || 800;
|
|
3101
|
-
return Math.max(0.
|
|
3665
|
+
return Math.max(0.4, Math.min(1, availW / tW));
|
|
3102
3666
|
};
|
|
3103
3667
|
try {
|
|
3104
3668
|
wb = XLSX__namespace.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
|
|
@@ -3153,7 +3717,16 @@ var ExcelPlugin = class {
|
|
|
3153
3717
|
}
|
|
3154
3718
|
});
|
|
3155
3719
|
ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
|
|
3720
|
+
requestAnimationFrame(() => {
|
|
3721
|
+
scale = calculateFitScale();
|
|
3722
|
+
applyTransform();
|
|
3723
|
+
});
|
|
3156
3724
|
};
|
|
3725
|
+
const ro = new ResizeObserver(() => {
|
|
3726
|
+
scale = calculateFitScale();
|
|
3727
|
+
applyTransform();
|
|
3728
|
+
});
|
|
3729
|
+
ro.observe(container);
|
|
3157
3730
|
if (sheetNames.length > 0) {
|
|
3158
3731
|
sheetNames.forEach((name, idx) => {
|
|
3159
3732
|
const btn = document.createElement("button");
|
|
@@ -3180,6 +3753,7 @@ var ExcelPlugin = class {
|
|
|
3180
3753
|
`;
|
|
3181
3754
|
}
|
|
3182
3755
|
const cleanup = () => {
|
|
3756
|
+
ro.disconnect();
|
|
3183
3757
|
container.remove();
|
|
3184
3758
|
ctx.container.innerHTML = "";
|
|
3185
3759
|
};
|
|
@@ -3201,16 +3775,11 @@ var ExcelPlugin = class {
|
|
|
3201
3775
|
},
|
|
3202
3776
|
fitToPage: () => {
|
|
3203
3777
|
scale = calculateFitScale();
|
|
3204
|
-
rotation = 0;
|
|
3205
3778
|
applyTransform();
|
|
3206
3779
|
},
|
|
3207
3780
|
rotateCW: () => {
|
|
3208
|
-
rotation = (rotation + 90) % 360;
|
|
3209
|
-
applyTransform();
|
|
3210
3781
|
},
|
|
3211
3782
|
rotateCCW: () => {
|
|
3212
|
-
rotation = (rotation - 90 + 360) % 360;
|
|
3213
|
-
applyTransform();
|
|
3214
3783
|
},
|
|
3215
3784
|
goToPage: (page) => {
|
|
3216
3785
|
if (page > 0 && page <= sheetNames.length) {
|
|
@@ -3219,6 +3788,63 @@ var ExcelPlugin = class {
|
|
|
3219
3788
|
},
|
|
3220
3789
|
getPageCount: () => sheetNames.length,
|
|
3221
3790
|
getCurrentPage: () => currentSheetIndex,
|
|
3791
|
+
getThumbnails: () => {
|
|
3792
|
+
return sheetNames.map((name, idx) => ({
|
|
3793
|
+
index: idx,
|
|
3794
|
+
label: name,
|
|
3795
|
+
render: async (canvas) => {
|
|
3796
|
+
canvas.width = 140;
|
|
3797
|
+
canvas.height = 100;
|
|
3798
|
+
const c = canvas.getContext("2d");
|
|
3799
|
+
if (!c) return;
|
|
3800
|
+
c.fillStyle = "#ffffff";
|
|
3801
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
3802
|
+
c.fillStyle = "#107c41";
|
|
3803
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
3804
|
+
c.fillStyle = "#ffffff";
|
|
3805
|
+
c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
3806
|
+
c.fillText(`\u{1F4CA} ${name.slice(0, 16)}`, 6, 11);
|
|
3807
|
+
const startY = 17;
|
|
3808
|
+
const rowH = 13;
|
|
3809
|
+
const colW = 30;
|
|
3810
|
+
const colHeaders = ["A", "B", "C", "D"];
|
|
3811
|
+
c.fillStyle = "#f1f5f9";
|
|
3812
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
3813
|
+
c.strokeStyle = "#cbd5e1";
|
|
3814
|
+
c.lineWidth = 0.8;
|
|
3815
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
3816
|
+
c.fillStyle = "#64748b";
|
|
3817
|
+
c.font = "bold 7px sans-serif";
|
|
3818
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3819
|
+
c.fillText(colHeaders[ci], 14 + ci * colW, startY + 9);
|
|
3820
|
+
}
|
|
3821
|
+
const ws = wb?.Sheets[name];
|
|
3822
|
+
for (let ri = 1; ri <= 5; ri++) {
|
|
3823
|
+
const y = startY + ri * rowH;
|
|
3824
|
+
if (y > canvas.height - 2) break;
|
|
3825
|
+
c.fillStyle = "#f8fafc";
|
|
3826
|
+
c.fillRect(0, y, 12, rowH);
|
|
3827
|
+
c.fillStyle = "#94a3b8";
|
|
3828
|
+
c.font = "6px sans-serif";
|
|
3829
|
+
c.fillText(String(ri), 3, y + 9);
|
|
3830
|
+
c.strokeStyle = "#e2e8f0";
|
|
3831
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
3832
|
+
c.fillStyle = "#334155";
|
|
3833
|
+
c.font = "6px sans-serif";
|
|
3834
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3835
|
+
const cellRef = `${colHeaders[ci]}${ri}`;
|
|
3836
|
+
const cellVal = ws?.[cellRef]?.w || ws?.[cellRef]?.v;
|
|
3837
|
+
if (cellVal !== void 0) {
|
|
3838
|
+
c.fillText(String(cellVal).slice(0, 6), 14 + ci * colW, y + 9);
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3841
|
+
}
|
|
3842
|
+
c.strokeStyle = "#cbd5e1";
|
|
3843
|
+
c.lineWidth = 1;
|
|
3844
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
3845
|
+
}
|
|
3846
|
+
}));
|
|
3847
|
+
},
|
|
3222
3848
|
download: () => {
|
|
3223
3849
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
3224
3850
|
const url = URL.createObjectURL(blob);
|
|
@@ -3251,7 +3877,16 @@ var CsvPlugin = class {
|
|
|
3251
3877
|
return ext === ".csv" || ext === ".tsv" || mime === "text/csv" || mime === "text/tab-separated-values";
|
|
3252
3878
|
}
|
|
3253
3879
|
getToolbarActions(instance) {
|
|
3254
|
-
|
|
3880
|
+
const actions = [];
|
|
3881
|
+
actions.push({
|
|
3882
|
+
id: "thumbnails",
|
|
3883
|
+
icon: "thumbnails",
|
|
3884
|
+
label: "Sheet Thumbnails",
|
|
3885
|
+
type: "button",
|
|
3886
|
+
group: "navigation",
|
|
3887
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3888
|
+
});
|
|
3889
|
+
actions.push(
|
|
3255
3890
|
{
|
|
3256
3891
|
id: "zoom-out",
|
|
3257
3892
|
icon: "zoom-out",
|
|
@@ -3291,8 +3926,19 @@ var CsvPlugin = class {
|
|
|
3291
3926
|
execute: () => {
|
|
3292
3927
|
instance.print?.();
|
|
3293
3928
|
}
|
|
3929
|
+
},
|
|
3930
|
+
{
|
|
3931
|
+
id: "open-window",
|
|
3932
|
+
icon: "open-window",
|
|
3933
|
+
label: "Open in Separate Full Window",
|
|
3934
|
+
type: "button",
|
|
3935
|
+
group: "actions",
|
|
3936
|
+
execute: () => {
|
|
3937
|
+
instance.openInSeparateWindow?.();
|
|
3938
|
+
}
|
|
3294
3939
|
}
|
|
3295
|
-
|
|
3940
|
+
);
|
|
3941
|
+
return actions;
|
|
3296
3942
|
}
|
|
3297
3943
|
async render(ctx) {
|
|
3298
3944
|
const decoder = new TextDecoder("utf-8");
|
|
@@ -3303,57 +3949,156 @@ var CsvPlugin = class {
|
|
|
3303
3949
|
container.style.overflow = "auto";
|
|
3304
3950
|
container.style.padding = "16px";
|
|
3305
3951
|
container.style.boxSizing = "border-box";
|
|
3306
|
-
|
|
3952
|
+
const tableWrapper = document.createElement("div");
|
|
3953
|
+
tableWrapper.style.transformOrigin = "top left";
|
|
3954
|
+
const delimiter = ctx.metadata.extension === ".tsv" ? " " : ",";
|
|
3955
|
+
const allLines = text.split(/\r?\n/).filter((r) => r.trim().length > 0);
|
|
3956
|
+
const headerLine = allLines[0] || "";
|
|
3957
|
+
const headerCells = headerLine.split(delimiter);
|
|
3958
|
+
const dataLines = allLines.slice(1);
|
|
3307
3959
|
const table = document.createElement("table");
|
|
3308
3960
|
table.style.borderCollapse = "collapse";
|
|
3309
|
-
table.style.
|
|
3310
|
-
table.style.fontFamily = "monospace
|
|
3961
|
+
table.style.minWidth = "100%";
|
|
3962
|
+
table.style.fontFamily = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace';
|
|
3311
3963
|
table.style.fontSize = "13px";
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3964
|
+
table.style.background = "#ffffff";
|
|
3965
|
+
table.style.border = "1px solid #d0d7de";
|
|
3966
|
+
const headerTr = document.createElement("tr");
|
|
3967
|
+
headerCells.forEach((cell) => {
|
|
3968
|
+
const th = document.createElement("th");
|
|
3969
|
+
th.textContent = cell.trim();
|
|
3970
|
+
th.style.border = "1px solid #d0d7de";
|
|
3971
|
+
th.style.padding = "8px 12px";
|
|
3972
|
+
th.style.backgroundColor = "#f6f8fa";
|
|
3973
|
+
th.style.fontWeight = "600";
|
|
3974
|
+
th.style.whiteSpace = "nowrap";
|
|
3975
|
+
headerTr.appendChild(th);
|
|
3976
|
+
});
|
|
3977
|
+
table.appendChild(headerTr);
|
|
3978
|
+
dataLines.forEach((row, idx) => {
|
|
3316
3979
|
const tr = document.createElement("tr");
|
|
3980
|
+
if (idx % 2 === 1) tr.style.backgroundColor = "#f8fafc";
|
|
3317
3981
|
const cells = row.split(delimiter);
|
|
3318
3982
|
cells.forEach((cell) => {
|
|
3319
|
-
const td = document.createElement(
|
|
3983
|
+
const td = document.createElement("td");
|
|
3320
3984
|
td.textContent = cell.trim();
|
|
3321
3985
|
td.style.border = "1px solid #d0d7de";
|
|
3322
3986
|
td.style.padding = "6px 12px";
|
|
3323
|
-
|
|
3324
|
-
td.style.backgroundColor = "#f6f8fa";
|
|
3325
|
-
td.style.fontWeight = "bold";
|
|
3326
|
-
}
|
|
3987
|
+
td.style.whiteSpace = "nowrap";
|
|
3327
3988
|
tr.appendChild(td);
|
|
3328
3989
|
});
|
|
3329
3990
|
table.appendChild(tr);
|
|
3330
3991
|
});
|
|
3331
|
-
|
|
3992
|
+
tableWrapper.appendChild(table);
|
|
3993
|
+
container.appendChild(tableWrapper);
|
|
3332
3994
|
ctx.container.appendChild(container);
|
|
3333
3995
|
let scale = 1;
|
|
3996
|
+
const calculateFitScale = () => {
|
|
3997
|
+
const availW = Math.max(280, container.clientWidth - 48);
|
|
3998
|
+
const tW = table.offsetWidth || 800;
|
|
3999
|
+
return Math.max(0.4, Math.min(1, availW / tW));
|
|
4000
|
+
};
|
|
4001
|
+
const applyScale = () => {
|
|
4002
|
+
tableWrapper.style.transform = `scale(${scale})`;
|
|
4003
|
+
};
|
|
4004
|
+
requestAnimationFrame(() => {
|
|
4005
|
+
scale = calculateFitScale();
|
|
4006
|
+
applyScale();
|
|
4007
|
+
});
|
|
4008
|
+
const ro = new ResizeObserver(() => {
|
|
4009
|
+
scale = calculateFitScale();
|
|
4010
|
+
applyScale();
|
|
4011
|
+
});
|
|
4012
|
+
ro.observe(container);
|
|
3334
4013
|
const cleanup = () => {
|
|
4014
|
+
ro.disconnect();
|
|
3335
4015
|
container.remove();
|
|
3336
4016
|
ctx.container.innerHTML = "";
|
|
3337
4017
|
};
|
|
3338
4018
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3339
4019
|
return {
|
|
3340
4020
|
destroy: cleanup,
|
|
4021
|
+
getPageCount: () => 1,
|
|
4022
|
+
getCurrentPage: () => 1,
|
|
4023
|
+
goToPage: () => {
|
|
4024
|
+
},
|
|
4025
|
+
getThumbnails: () => {
|
|
4026
|
+
const sheetName = ctx.metadata.name?.replace(/\.[^/.]+$/, "") || "Sheet1";
|
|
4027
|
+
return [{
|
|
4028
|
+
index: 0,
|
|
4029
|
+
label: sheetName,
|
|
4030
|
+
render: async (canvas) => {
|
|
4031
|
+
canvas.width = 140;
|
|
4032
|
+
canvas.height = 100;
|
|
4033
|
+
const c = canvas.getContext("2d");
|
|
4034
|
+
if (!c) return;
|
|
4035
|
+
c.fillStyle = "#ffffff";
|
|
4036
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4037
|
+
c.fillStyle = "#107c41";
|
|
4038
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
4039
|
+
c.fillStyle = "#ffffff";
|
|
4040
|
+
c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
4041
|
+
c.fillText(`\u{1F4CA} ${sheetName.slice(0, 16)}`, 6, 11);
|
|
4042
|
+
const startY = 17;
|
|
4043
|
+
const rowH = 13;
|
|
4044
|
+
const colW = 30;
|
|
4045
|
+
const cols = headerCells.slice(0, 4).map((h) => h.trim() || "Col");
|
|
4046
|
+
c.fillStyle = "#f1f5f9";
|
|
4047
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
4048
|
+
c.strokeStyle = "#cbd5e1";
|
|
4049
|
+
c.lineWidth = 0.8;
|
|
4050
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
4051
|
+
c.fillStyle = "#64748b";
|
|
4052
|
+
c.font = "bold 7px sans-serif";
|
|
4053
|
+
for (let ci = 0; ci < cols.length; ci++) {
|
|
4054
|
+
c.fillText(cols[ci].slice(0, 5), 14 + ci * colW, startY + 9);
|
|
4055
|
+
}
|
|
4056
|
+
for (let ri = 0; ri < Math.min(5, dataLines.length); ri++) {
|
|
4057
|
+
const y = startY + (ri + 1) * rowH;
|
|
4058
|
+
if (y > canvas.height - 2) break;
|
|
4059
|
+
c.fillStyle = "#f8fafc";
|
|
4060
|
+
c.fillRect(0, y, 12, rowH);
|
|
4061
|
+
c.fillStyle = "#94a3b8";
|
|
4062
|
+
c.font = "6px sans-serif";
|
|
4063
|
+
c.fillText(String(ri + 1), 3, y + 9);
|
|
4064
|
+
c.strokeStyle = "#e2e8f0";
|
|
4065
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
4066
|
+
const rowCells = dataLines[ri].split(delimiter);
|
|
4067
|
+
c.fillStyle = "#334155";
|
|
4068
|
+
c.font = "6px sans-serif";
|
|
4069
|
+
for (let ci = 0; ci < cols.length; ci++) {
|
|
4070
|
+
const val = (rowCells[ci] || "").trim();
|
|
4071
|
+
if (val) {
|
|
4072
|
+
c.fillText(val.slice(0, 6), 14 + ci * colW, y + 9);
|
|
4073
|
+
}
|
|
4074
|
+
}
|
|
4075
|
+
}
|
|
4076
|
+
c.strokeStyle = "#cbd5e1";
|
|
4077
|
+
c.lineWidth = 1;
|
|
4078
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4079
|
+
}
|
|
4080
|
+
}];
|
|
4081
|
+
},
|
|
3341
4082
|
zoomIn: () => {
|
|
3342
4083
|
scale += 0.1;
|
|
3343
|
-
|
|
4084
|
+
applyScale();
|
|
3344
4085
|
},
|
|
3345
4086
|
zoomOut: () => {
|
|
3346
4087
|
scale = Math.max(0.2, scale - 0.1);
|
|
3347
|
-
|
|
4088
|
+
applyScale();
|
|
3348
4089
|
},
|
|
3349
4090
|
getZoom: () => scale,
|
|
3350
4091
|
setZoom: (level) => {
|
|
3351
4092
|
scale = level;
|
|
3352
|
-
|
|
4093
|
+
applyScale();
|
|
3353
4094
|
},
|
|
3354
4095
|
fitToPage: () => {
|
|
3355
|
-
scale =
|
|
3356
|
-
|
|
4096
|
+
scale = calculateFitScale();
|
|
4097
|
+
applyScale();
|
|
4098
|
+
},
|
|
4099
|
+
rotateCW: () => {
|
|
4100
|
+
},
|
|
4101
|
+
rotateCCW: () => {
|
|
3357
4102
|
},
|
|
3358
4103
|
download: () => {
|
|
3359
4104
|
const blob = new Blob([ctx.buffer], { type: "text/csv" });
|
|
@@ -3415,30 +4160,36 @@ var CodePlugin = class {
|
|
|
3415
4160
|
return false;
|
|
3416
4161
|
}
|
|
3417
4162
|
getToolbarActions(instance) {
|
|
3418
|
-
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3419
|
-
const actions = [];
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
4163
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4164
|
+
const actions = [];
|
|
4165
|
+
actions.push({
|
|
4166
|
+
id: "thumbnails",
|
|
4167
|
+
icon: "thumbnails",
|
|
4168
|
+
label: "Page Thumbnails",
|
|
4169
|
+
type: "button",
|
|
4170
|
+
group: "navigation",
|
|
4171
|
+
execute: () => instance.toggleThumbnails?.()
|
|
4172
|
+
});
|
|
4173
|
+
actions.push({
|
|
4174
|
+
id: "page-nav",
|
|
4175
|
+
icon: "",
|
|
4176
|
+
label: "Page Navigation",
|
|
4177
|
+
type: "page-nav",
|
|
4178
|
+
group: "navigation",
|
|
4179
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4180
|
+
max: totalPages,
|
|
4181
|
+
execute: (action, page) => {
|
|
4182
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4183
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4184
|
+
if (action === "prev") {
|
|
4185
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4186
|
+
} else if (action === "next") {
|
|
4187
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4188
|
+
} else if (typeof page === "number") {
|
|
4189
|
+
instance.goToPage?.(page);
|
|
3439
4190
|
}
|
|
3440
|
-
}
|
|
3441
|
-
}
|
|
4191
|
+
}
|
|
4192
|
+
});
|
|
3442
4193
|
actions.push(
|
|
3443
4194
|
{
|
|
3444
4195
|
id: "zoom-out",
|
|
@@ -3460,26 +4211,6 @@ var CodePlugin = class {
|
|
|
3460
4211
|
instance.zoomIn?.();
|
|
3461
4212
|
}
|
|
3462
4213
|
},
|
|
3463
|
-
{
|
|
3464
|
-
id: "fit-page",
|
|
3465
|
-
icon: "fit-page",
|
|
3466
|
-
label: "Fit to View",
|
|
3467
|
-
type: "button",
|
|
3468
|
-
group: "zoom",
|
|
3469
|
-
execute: () => {
|
|
3470
|
-
instance.fitToPage?.();
|
|
3471
|
-
}
|
|
3472
|
-
},
|
|
3473
|
-
{
|
|
3474
|
-
id: "rotate-cw",
|
|
3475
|
-
icon: "rotate-cw",
|
|
3476
|
-
label: "Rotate",
|
|
3477
|
-
type: "button",
|
|
3478
|
-
group: "view",
|
|
3479
|
-
execute: () => {
|
|
3480
|
-
instance.rotateCW?.();
|
|
3481
|
-
}
|
|
3482
|
-
},
|
|
3483
4214
|
{
|
|
3484
4215
|
id: "copy",
|
|
3485
4216
|
icon: "copy",
|
|
@@ -3582,16 +4313,19 @@ var CodePlugin = class {
|
|
|
3582
4313
|
let fontSize = 13;
|
|
3583
4314
|
let rotation = 0;
|
|
3584
4315
|
let zoomLevel = 1;
|
|
4316
|
+
let isUserZoomed = false;
|
|
3585
4317
|
const pre = document.createElement("pre");
|
|
3586
4318
|
const code = document.createElement("code");
|
|
3587
4319
|
if (isTxt) {
|
|
4320
|
+
container.style.overflowX = "hidden";
|
|
4321
|
+
container.style.overflowY = "auto";
|
|
3588
4322
|
container.style.backgroundColor = "#f1f5f9";
|
|
3589
|
-
container.style.padding = "
|
|
4323
|
+
container.style.padding = "16px 8px";
|
|
3590
4324
|
container.style.boxSizing = "border-box";
|
|
3591
4325
|
container.style.display = "flex";
|
|
3592
4326
|
container.style.flexDirection = "column";
|
|
3593
4327
|
container.style.alignItems = "center";
|
|
3594
|
-
pre.style.margin = "0";
|
|
4328
|
+
pre.style.margin = "0 auto";
|
|
3595
4329
|
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3596
4330
|
pre.style.fontSize = "13px";
|
|
3597
4331
|
pre.style.color = "#1e293b";
|
|
@@ -3603,10 +4337,12 @@ var CodePlugin = class {
|
|
|
3603
4337
|
pre.style.minHeight = "1056px";
|
|
3604
4338
|
pre.style.padding = "72px 56px";
|
|
3605
4339
|
pre.style.boxSizing = "border-box";
|
|
3606
|
-
pre.style.boxShadow = "0 4px
|
|
4340
|
+
pre.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
3607
4341
|
pre.style.borderRadius = "4px";
|
|
3608
4342
|
pre.style.transformOrigin = "top center";
|
|
4343
|
+
pre.style.transition = "transform 0.15s ease";
|
|
3609
4344
|
} else {
|
|
4345
|
+
container.style.overflow = "auto";
|
|
3610
4346
|
container.style.backgroundColor = "#1e1e1e";
|
|
3611
4347
|
container.style.color = "#d4d4d4";
|
|
3612
4348
|
container.style.padding = "16px";
|
|
@@ -3638,42 +4374,9 @@ var CodePlugin = class {
|
|
|
3638
4374
|
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
3639
4375
|
pre.appendChild(code);
|
|
3640
4376
|
container.appendChild(pre);
|
|
3641
|
-
let indicator = null;
|
|
3642
|
-
if (totalPages > 1) {
|
|
3643
|
-
indicator = document.createElement("div");
|
|
3644
|
-
indicator.className = "fp-code-page-indicator";
|
|
3645
|
-
indicator.style.position = "sticky";
|
|
3646
|
-
indicator.style.bottom = "16px";
|
|
3647
|
-
if (isTxt) {
|
|
3648
|
-
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3649
|
-
indicator.style.color = "#334155";
|
|
3650
|
-
indicator.style.border = "1px solid #e2e8f0";
|
|
3651
|
-
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3652
|
-
} else {
|
|
3653
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3654
|
-
indicator.style.color = "#f8fafc";
|
|
3655
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3656
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3657
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
3658
|
-
}
|
|
3659
|
-
indicator.style.fontSize = "12px";
|
|
3660
|
-
indicator.style.fontWeight = "600";
|
|
3661
|
-
indicator.style.padding = "5px 14px";
|
|
3662
|
-
indicator.style.borderRadius = "20px";
|
|
3663
|
-
indicator.style.zIndex = "10";
|
|
3664
|
-
indicator.style.userSelect = "none";
|
|
3665
|
-
indicator.style.pointerEvents = "none";
|
|
3666
|
-
indicator.style.textAlign = "center";
|
|
3667
|
-
indicator.style.width = "fit-content";
|
|
3668
|
-
indicator.style.margin = "16px auto 0";
|
|
3669
|
-
container.appendChild(indicator);
|
|
3670
|
-
}
|
|
3671
4377
|
const showPage = (pageNum) => {
|
|
3672
4378
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3673
4379
|
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
3674
|
-
if (indicator) {
|
|
3675
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3676
|
-
}
|
|
3677
4380
|
container.scrollTop = 0;
|
|
3678
4381
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3679
4382
|
};
|
|
@@ -3681,36 +4384,90 @@ var CodePlugin = class {
|
|
|
3681
4384
|
showPage(1);
|
|
3682
4385
|
}
|
|
3683
4386
|
ctx.container.appendChild(container);
|
|
3684
|
-
const
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
ctx.container.innerHTML = "";
|
|
4387
|
+
const calculateTxtFit = () => {
|
|
4388
|
+
const availW = Math.max(280, container.clientWidth - 32);
|
|
4389
|
+
return Math.max(0.4, Math.min(3, availW / 816));
|
|
3688
4390
|
};
|
|
3689
|
-
ctx.signal.addEventListener("abort", cleanup);
|
|
3690
4391
|
const updateTransform = () => {
|
|
3691
4392
|
if (isTxt) {
|
|
3692
4393
|
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
4394
|
+
const scaledH = 1056 * zoomLevel;
|
|
4395
|
+
const extraH = Math.max(0, scaledH - 1056);
|
|
4396
|
+
pre.style.marginBottom = `${extraH + 32}px`;
|
|
3693
4397
|
} else {
|
|
3694
4398
|
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3695
4399
|
pre.style.fontSize = `${fontSize}px`;
|
|
3696
4400
|
}
|
|
3697
4401
|
};
|
|
4402
|
+
let resizeObserver = null;
|
|
4403
|
+
if (isTxt) {
|
|
4404
|
+
setTimeout(() => {
|
|
4405
|
+
zoomLevel = calculateTxtFit();
|
|
4406
|
+
updateTransform();
|
|
4407
|
+
}, 60);
|
|
4408
|
+
resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
4409
|
+
if (!isUserZoomed) {
|
|
4410
|
+
zoomLevel = calculateTxtFit();
|
|
4411
|
+
updateTransform();
|
|
4412
|
+
}
|
|
4413
|
+
}) : null;
|
|
4414
|
+
resizeObserver?.observe(container);
|
|
4415
|
+
}
|
|
4416
|
+
const cleanup = () => {
|
|
4417
|
+
resizeObserver?.disconnect();
|
|
4418
|
+
container.remove();
|
|
4419
|
+
ctx.container.innerHTML = "";
|
|
4420
|
+
};
|
|
4421
|
+
ctx.signal.addEventListener("abort", cleanup);
|
|
3698
4422
|
return {
|
|
3699
4423
|
destroy: cleanup,
|
|
3700
4424
|
getPageCount: () => totalPages,
|
|
3701
4425
|
getCurrentPage: () => currentPage,
|
|
3702
4426
|
goToPage: (page) => showPage(page),
|
|
4427
|
+
getThumbnails: () => {
|
|
4428
|
+
return rawPages.map((pageText, idx) => ({
|
|
4429
|
+
index: idx,
|
|
4430
|
+
label: `Page ${idx + 1}`,
|
|
4431
|
+
render: async (canvas) => {
|
|
4432
|
+
canvas.width = 140;
|
|
4433
|
+
canvas.height = 180;
|
|
4434
|
+
const c = canvas.getContext("2d");
|
|
4435
|
+
if (!c) return;
|
|
4436
|
+
c.fillStyle = "#ffffff";
|
|
4437
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4438
|
+
c.strokeStyle = "#cbd5e1";
|
|
4439
|
+
c.lineWidth = 1;
|
|
4440
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4441
|
+
c.fillStyle = "#64748b";
|
|
4442
|
+
const lines = (pageText || "").split("\n").slice(0, 24);
|
|
4443
|
+
const lineH = 6;
|
|
4444
|
+
const startY = 14;
|
|
4445
|
+
const startX = 12;
|
|
4446
|
+
const maxW = canvas.width - 24;
|
|
4447
|
+
c.font = "5px monospace";
|
|
4448
|
+
for (let li = 0; li < lines.length; li++) {
|
|
4449
|
+
const l = lines[li].trim();
|
|
4450
|
+
if (!l) continue;
|
|
4451
|
+
const y = startY + li * lineH;
|
|
4452
|
+
if (y > canvas.height - 12) break;
|
|
4453
|
+
c.fillText(l.slice(0, 30), startX, y, maxW);
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
}));
|
|
4457
|
+
},
|
|
3703
4458
|
zoomIn: () => {
|
|
4459
|
+
isUserZoomed = true;
|
|
3704
4460
|
if (isTxt) {
|
|
3705
|
-
zoomLevel = Math.min(3, zoomLevel + 0.
|
|
4461
|
+
zoomLevel = Math.min(3.5, zoomLevel + 0.15);
|
|
3706
4462
|
} else {
|
|
3707
4463
|
fontSize = Math.min(32, fontSize + 2);
|
|
3708
4464
|
}
|
|
3709
4465
|
updateTransform();
|
|
3710
4466
|
},
|
|
3711
4467
|
zoomOut: () => {
|
|
4468
|
+
isUserZoomed = true;
|
|
3712
4469
|
if (isTxt) {
|
|
3713
|
-
zoomLevel = Math.max(0.1, zoomLevel - 0.
|
|
4470
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.15);
|
|
3714
4471
|
} else {
|
|
3715
4472
|
fontSize = Math.max(8, fontSize - 2);
|
|
3716
4473
|
}
|
|
@@ -3718,6 +4475,7 @@ var CodePlugin = class {
|
|
|
3718
4475
|
},
|
|
3719
4476
|
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
3720
4477
|
setZoom: (level) => {
|
|
4478
|
+
isUserZoomed = true;
|
|
3721
4479
|
if (isTxt) {
|
|
3722
4480
|
zoomLevel = level;
|
|
3723
4481
|
} else {
|
|
@@ -3726,9 +4484,10 @@ var CodePlugin = class {
|
|
|
3726
4484
|
updateTransform();
|
|
3727
4485
|
},
|
|
3728
4486
|
fitToPage: () => {
|
|
4487
|
+
isUserZoomed = false;
|
|
3729
4488
|
fontSize = 13;
|
|
3730
4489
|
rotation = 0;
|
|
3731
|
-
zoomLevel = isTxt ?
|
|
4490
|
+
zoomLevel = isTxt ? calculateTxtFit() : 1;
|
|
3732
4491
|
updateTransform();
|
|
3733
4492
|
},
|
|
3734
4493
|
rotateCW: () => {
|
|
@@ -4595,6 +5354,148 @@ var ThreeDPlugin = class {
|
|
|
4595
5354
|
function threeDPlugin() {
|
|
4596
5355
|
return new ThreeDPlugin();
|
|
4597
5356
|
}
|
|
5357
|
+
function cleanRtfText(raw) {
|
|
5358
|
+
return raw.replace(/\\bin\d+\s/g, "").replace(/{\\\*[^}]+}/g, "").replace(/\\u(-?\d+)\??/g, (_, code) => {
|
|
5359
|
+
let num = parseInt(code, 10);
|
|
5360
|
+
if (num < 0) num += 65536;
|
|
5361
|
+
return String.fromCharCode(num);
|
|
5362
|
+
}).replace(/\\'([0-9a-fA-F]{2})/g, (_, hex) => {
|
|
5363
|
+
return String.fromCharCode(parseInt(hex, 16));
|
|
5364
|
+
}).replace(/\\tab\b/g, " ").replace(/\\emdash\b/g, "\u2014").replace(/\\endash\b/g, "\u2013").replace(/\\bullet\b/g, "\u2022").replace(/\\lquote\b/g, "\u2018").replace(/\\rquote\b/g, "\u2019").replace(/\\ldblquote\b/g, "\u201C").replace(/\\rdblquote\b/g, "\u201D").replace(/\\\w+(?:-?\d+)?\s?/g, " ").replace(/[{}\r\n]/g, " ").replace(/\s+/g, " ").trim();
|
|
5365
|
+
}
|
|
5366
|
+
function parseRtfTables(rtfText) {
|
|
5367
|
+
const rowSegments = rtfText.split(/\\row\b/);
|
|
5368
|
+
if (rowSegments.length <= 1) return [];
|
|
5369
|
+
const rawTables = [];
|
|
5370
|
+
let currentTable = null;
|
|
5371
|
+
let charOffset = 0;
|
|
5372
|
+
for (let i = 0; i < rowSegments.length - 1; i++) {
|
|
5373
|
+
const segment = rowSegments[i];
|
|
5374
|
+
const segmentStart = charOffset;
|
|
5375
|
+
const segmentEnd = charOffset + segment.length + 4;
|
|
5376
|
+
const cellParts = segment.split(/\\cell\b/);
|
|
5377
|
+
if (cellParts.length > 1) {
|
|
5378
|
+
const cellxMatches = [...segment.matchAll(/\\cellx(\d+)/g)].map((m) => parseInt(m[1], 10));
|
|
5379
|
+
let cellWidths = [];
|
|
5380
|
+
if (cellxMatches.length > 0) {
|
|
5381
|
+
let seq = [cellxMatches[0]];
|
|
5382
|
+
for (let k = 1; k < cellxMatches.length; k++) {
|
|
5383
|
+
if (cellxMatches[k] > cellxMatches[k - 1]) seq.push(cellxMatches[k]);
|
|
5384
|
+
else break;
|
|
5385
|
+
}
|
|
5386
|
+
let prev = 0;
|
|
5387
|
+
cellWidths = seq.map((x) => {
|
|
5388
|
+
const w = x - prev;
|
|
5389
|
+
prev = x;
|
|
5390
|
+
return w;
|
|
5391
|
+
});
|
|
5392
|
+
}
|
|
5393
|
+
const cells = [];
|
|
5394
|
+
for (let c = 0; c < cellParts.length - 1; c++) {
|
|
5395
|
+
let rawCell = cellParts[c];
|
|
5396
|
+
if (c === 0) {
|
|
5397
|
+
const lastTrowd = rawCell.lastIndexOf("\\trowd");
|
|
5398
|
+
if (lastTrowd !== -1) rawCell = rawCell.slice(lastTrowd);
|
|
5399
|
+
}
|
|
5400
|
+
cells.push(cleanRtfText(rawCell));
|
|
5401
|
+
}
|
|
5402
|
+
const isNewTable = !currentTable || segmentStart - currentTable.lastEnd > 2500;
|
|
5403
|
+
if (isNewTable) {
|
|
5404
|
+
const prevTextSlice = rtfText.slice(Math.max(0, segmentStart - 4e3), segmentStart);
|
|
5405
|
+
const cleanPrev = cleanRtfText(prevTextSlice);
|
|
5406
|
+
const anchorBefore = cleanPrev.slice(-80).trim();
|
|
5407
|
+
currentTable = {
|
|
5408
|
+
id: `RTF_TABLE_${rawTables.length}`,
|
|
5409
|
+
startPos: segmentStart,
|
|
5410
|
+
lastEnd: segmentEnd,
|
|
5411
|
+
rows: [],
|
|
5412
|
+
columnWidths: cellWidths,
|
|
5413
|
+
anchorBefore,
|
|
5414
|
+
anchorAfter: ""
|
|
5415
|
+
};
|
|
5416
|
+
rawTables.push(currentTable);
|
|
5417
|
+
}
|
|
5418
|
+
if (currentTable) {
|
|
5419
|
+
currentTable.rows.push({
|
|
5420
|
+
cells,
|
|
5421
|
+
widths: cellWidths.length === cells.length ? cellWidths : currentTable.columnWidths
|
|
5422
|
+
});
|
|
5423
|
+
currentTable.lastEnd = segmentEnd;
|
|
5424
|
+
}
|
|
5425
|
+
}
|
|
5426
|
+
charOffset += segment.length + 4;
|
|
5427
|
+
}
|
|
5428
|
+
rawTables.forEach((tbl) => {
|
|
5429
|
+
const afterSlice = rtfText.slice(tbl.lastEnd, Math.min(rtfText.length, tbl.lastEnd + 2e3));
|
|
5430
|
+
const cleanAfter = cleanRtfText(afterSlice);
|
|
5431
|
+
tbl.anchorAfter = cleanAfter.slice(0, 80).trim();
|
|
5432
|
+
});
|
|
5433
|
+
return rawTables.map((tbl) => {
|
|
5434
|
+
const totalW = (tbl.columnWidths || []).reduce((a, b) => a + b, 0);
|
|
5435
|
+
const colPercents = totalW > 0 ? tbl.columnWidths.map((w) => Math.round(w / totalW * 100)) : [];
|
|
5436
|
+
return {
|
|
5437
|
+
id: tbl.id,
|
|
5438
|
+
rows: tbl.rows.map((r) => r.cells),
|
|
5439
|
+
colPercents,
|
|
5440
|
+
anchorBefore: tbl.anchorBefore,
|
|
5441
|
+
anchorAfter: tbl.anchorAfter
|
|
5442
|
+
};
|
|
5443
|
+
});
|
|
5444
|
+
}
|
|
5445
|
+
function renderRtfTableElement(table) {
|
|
5446
|
+
const tableEl = document.createElement("table");
|
|
5447
|
+
tableEl.className = "fp-rtf-table";
|
|
5448
|
+
tableEl.style.width = "100%";
|
|
5449
|
+
tableEl.style.borderCollapse = "collapse";
|
|
5450
|
+
tableEl.style.margin = "16px 0 20px";
|
|
5451
|
+
tableEl.style.fontSize = "10pt";
|
|
5452
|
+
tableEl.style.lineHeight = "1.5";
|
|
5453
|
+
tableEl.style.border = "1px solid #cbd5e1";
|
|
5454
|
+
tableEl.style.borderRadius = "4px";
|
|
5455
|
+
tableEl.style.boxSizing = "border-box";
|
|
5456
|
+
tableEl.style.backgroundColor = "#ffffff";
|
|
5457
|
+
const thead = document.createElement("thead");
|
|
5458
|
+
const tbody = document.createElement("tbody");
|
|
5459
|
+
table.rows.forEach((rowCells, rIdx) => {
|
|
5460
|
+
const tr = document.createElement("tr");
|
|
5461
|
+
const isHeader = rIdx === 0;
|
|
5462
|
+
if (isHeader) {
|
|
5463
|
+
tr.style.backgroundColor = "#f8fafc";
|
|
5464
|
+
tr.style.borderBottom = "2px solid #cbd5e1";
|
|
5465
|
+
} else {
|
|
5466
|
+
tr.style.borderBottom = "1px solid #e2e8f0";
|
|
5467
|
+
if (rIdx % 2 === 0) {
|
|
5468
|
+
tr.style.backgroundColor = "#fcfdfe";
|
|
5469
|
+
}
|
|
5470
|
+
}
|
|
5471
|
+
rowCells.forEach((cellText, cIdx) => {
|
|
5472
|
+
const cellEl = document.createElement(isHeader ? "th" : "td");
|
|
5473
|
+
cellEl.style.padding = "8px 12px";
|
|
5474
|
+
cellEl.style.border = "1px solid #cbd5e1";
|
|
5475
|
+
cellEl.style.verticalAlign = "top";
|
|
5476
|
+
cellEl.style.color = isHeader ? "#0f172a" : "#1e293b";
|
|
5477
|
+
cellEl.style.fontWeight = isHeader ? "600" : "normal";
|
|
5478
|
+
if (table.colPercents && table.colPercents[cIdx]) {
|
|
5479
|
+
cellEl.style.width = `${table.colPercents[cIdx]}%`;
|
|
5480
|
+
}
|
|
5481
|
+
if (/^\d+$/.test(cellText.trim()) || cellText.trim() === "#") {
|
|
5482
|
+
cellEl.style.textAlign = "center";
|
|
5483
|
+
} else {
|
|
5484
|
+
cellEl.style.textAlign = "left";
|
|
5485
|
+
}
|
|
5486
|
+
cellEl.textContent = cellText;
|
|
5487
|
+
tr.appendChild(cellEl);
|
|
5488
|
+
});
|
|
5489
|
+
if (isHeader) {
|
|
5490
|
+
thead.appendChild(tr);
|
|
5491
|
+
} else {
|
|
5492
|
+
tbody.appendChild(tr);
|
|
5493
|
+
}
|
|
5494
|
+
});
|
|
5495
|
+
tableEl.appendChild(thead);
|
|
5496
|
+
tableEl.appendChild(tbody);
|
|
5497
|
+
return tableEl;
|
|
5498
|
+
}
|
|
4598
5499
|
var RtfPlugin = class {
|
|
4599
5500
|
id = "rtf";
|
|
4600
5501
|
name = "Rich Text Format (RTF)";
|
|
@@ -4609,29 +5510,35 @@ var RtfPlugin = class {
|
|
|
4609
5510
|
getToolbarActions(instance) {
|
|
4610
5511
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4611
5512
|
const actions = [];
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
if (
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
instance.goToPage?.(page);
|
|
4630
|
-
}
|
|
5513
|
+
actions.push({
|
|
5514
|
+
id: "page-nav",
|
|
5515
|
+
icon: "",
|
|
5516
|
+
label: "Page Navigation",
|
|
5517
|
+
type: "page-nav",
|
|
5518
|
+
group: "navigation",
|
|
5519
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5520
|
+
max: totalPages,
|
|
5521
|
+
execute: (action, page) => {
|
|
5522
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5523
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5524
|
+
if (action === "prev") {
|
|
5525
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5526
|
+
} else if (action === "next") {
|
|
5527
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5528
|
+
} else if (typeof page === "number") {
|
|
5529
|
+
instance.goToPage?.(page);
|
|
4631
5530
|
}
|
|
4632
|
-
}
|
|
4633
|
-
}
|
|
5531
|
+
}
|
|
5532
|
+
});
|
|
4634
5533
|
actions.push(
|
|
5534
|
+
{
|
|
5535
|
+
id: "thumbnails",
|
|
5536
|
+
icon: "thumbnails",
|
|
5537
|
+
label: "Thumbnails",
|
|
5538
|
+
type: "button",
|
|
5539
|
+
group: "view",
|
|
5540
|
+
execute: () => instance.toggleThumbnails?.()
|
|
5541
|
+
},
|
|
4635
5542
|
{
|
|
4636
5543
|
id: "zoom-out",
|
|
4637
5544
|
icon: "zoom-out",
|
|
@@ -4702,67 +5609,143 @@ var RtfPlugin = class {
|
|
|
4702
5609
|
async render(ctx) {
|
|
4703
5610
|
const wrapper = document.createElement("div");
|
|
4704
5611
|
wrapper.className = "fp-rtf-wrapper";
|
|
4705
|
-
wrapper.style.padding = "
|
|
4706
|
-
wrapper.style.
|
|
5612
|
+
wrapper.style.padding = "0";
|
|
5613
|
+
wrapper.style.width = "816px";
|
|
4707
5614
|
wrapper.style.margin = "0 auto";
|
|
4708
|
-
wrapper.style.
|
|
4709
|
-
wrapper.style.
|
|
4710
|
-
wrapper.style.
|
|
4711
|
-
wrapper.style.
|
|
5615
|
+
wrapper.style.boxSizing = "border-box";
|
|
5616
|
+
wrapper.style.display = "flex";
|
|
5617
|
+
wrapper.style.flexDirection = "column";
|
|
5618
|
+
wrapper.style.alignItems = "center";
|
|
5619
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4712
5620
|
wrapper.style.transformOrigin = "top center";
|
|
4713
|
-
wrapper.style.transition = "transform 0.
|
|
4714
|
-
ctx.container.style.
|
|
4715
|
-
ctx.container.style.
|
|
5621
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5622
|
+
ctx.container.style.overflowX = "hidden";
|
|
5623
|
+
ctx.container.style.overflowY = "auto";
|
|
5624
|
+
ctx.container.style.padding = "16px 8px";
|
|
4716
5625
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
4717
5626
|
ctx.container.appendChild(wrapper);
|
|
4718
5627
|
let scale = 1;
|
|
4719
5628
|
let rotation = 0;
|
|
4720
5629
|
let pageElements = [];
|
|
4721
|
-
let
|
|
5630
|
+
let isUserZoomed = false;
|
|
5631
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
4722
5632
|
const calculateFitScale = (mode = fitMode) => {
|
|
4723
5633
|
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4724
|
-
const elW =
|
|
4725
|
-
const singlePageH =
|
|
4726
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
4727
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
5634
|
+
const elW = 816;
|
|
5635
|
+
const singlePageH = activeEl?.offsetHeight || 1056;
|
|
5636
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
5637
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
4728
5638
|
const sW = availW / elW;
|
|
4729
5639
|
const sH = availH / singlePageH;
|
|
4730
5640
|
if (mode === "page") {
|
|
4731
|
-
return Math.max(0.
|
|
5641
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
4732
5642
|
}
|
|
4733
|
-
return Math.max(0.
|
|
5643
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
4734
5644
|
};
|
|
4735
5645
|
const applyTransform = () => {
|
|
4736
5646
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4737
5647
|
wrapper.style.transformOrigin = "top center";
|
|
5648
|
+
const activeEl = pageElements[currentPage - 1];
|
|
5649
|
+
const baseH = activeEl?.offsetHeight || 1056;
|
|
5650
|
+
const scaledH = baseH * scale;
|
|
5651
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
5652
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
4738
5653
|
};
|
|
5654
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
5655
|
+
if (!isUserZoomed) {
|
|
5656
|
+
scale = calculateFitScale(fitMode);
|
|
5657
|
+
applyTransform();
|
|
5658
|
+
}
|
|
5659
|
+
}) : null;
|
|
5660
|
+
resizeObserver?.observe(ctx.container);
|
|
4739
5661
|
setTimeout(() => {
|
|
4740
|
-
|
|
4741
|
-
scale = calculateFitScale("width");
|
|
5662
|
+
scale = calculateFitScale(fitMode);
|
|
4742
5663
|
applyTransform();
|
|
4743
5664
|
}, 60);
|
|
4744
5665
|
try {
|
|
4745
5666
|
if (typeof RTFJS__namespace.loggingEnabled === "function") {
|
|
4746
5667
|
RTFJS__namespace.loggingEnabled(false);
|
|
4747
5668
|
}
|
|
5669
|
+
const rawText = new TextDecoder("latin1").decode(ctx.buffer);
|
|
5670
|
+
const tables = parseRtfTables(rawText);
|
|
4748
5671
|
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
4749
5672
|
const htmlElements = await doc.render();
|
|
4750
5673
|
const contentNodes = [];
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
5674
|
+
const extractBlocks = (nodes) => {
|
|
5675
|
+
for (const item of nodes) {
|
|
5676
|
+
if (!item || !(item instanceof HTMLElement)) continue;
|
|
5677
|
+
const tag = item.tagName.toLowerCase();
|
|
5678
|
+
const hasChildBlocks = Array.from(item.children).some((c) => {
|
|
5679
|
+
const ct = c.tagName.toLowerCase();
|
|
5680
|
+
return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
|
|
5681
|
+
});
|
|
5682
|
+
if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
|
|
5683
|
+
extractBlocks(Array.from(item.children));
|
|
5684
|
+
} else {
|
|
5685
|
+
const svgs = item.querySelectorAll("svg, img");
|
|
5686
|
+
svgs.forEach((s) => {
|
|
5687
|
+
const el = s;
|
|
5688
|
+
el.style.maxWidth = "100%";
|
|
5689
|
+
el.style.maxHeight = "360px";
|
|
5690
|
+
el.style.display = "block";
|
|
5691
|
+
el.style.margin = "12px auto";
|
|
5692
|
+
if (s.tagName.toLowerCase() === "svg") {
|
|
5693
|
+
s.removeAttribute("width");
|
|
5694
|
+
s.removeAttribute("height");
|
|
5695
|
+
el.style.width = "100%";
|
|
5696
|
+
el.style.maxHeight = "360px";
|
|
5697
|
+
}
|
|
5698
|
+
});
|
|
5699
|
+
if (tag === "p" || tag === "div") {
|
|
5700
|
+
item.style.display = "block";
|
|
5701
|
+
item.style.marginBottom = "12px";
|
|
5702
|
+
item.style.lineHeight = "1.6";
|
|
5703
|
+
}
|
|
5704
|
+
contentNodes.push(item);
|
|
5705
|
+
}
|
|
4756
5706
|
}
|
|
4757
|
-
}
|
|
5707
|
+
};
|
|
5708
|
+
extractBlocks(htmlElements);
|
|
5709
|
+
tables.forEach((table) => {
|
|
5710
|
+
const tableEl = renderRtfTableElement(table);
|
|
5711
|
+
let inserted = false;
|
|
5712
|
+
if (table.anchorBefore && table.anchorBefore.length > 10) {
|
|
5713
|
+
const keyword = table.anchorBefore.slice(-35).trim();
|
|
5714
|
+
for (let i = 0; i < contentNodes.length; i++) {
|
|
5715
|
+
if (contentNodes[i].textContent?.includes(keyword)) {
|
|
5716
|
+
contentNodes.splice(i + 1, 0, tableEl);
|
|
5717
|
+
inserted = true;
|
|
5718
|
+
break;
|
|
5719
|
+
}
|
|
5720
|
+
}
|
|
5721
|
+
}
|
|
5722
|
+
if (!inserted && table.anchorAfter && table.anchorAfter.length > 10) {
|
|
5723
|
+
const keyword = table.anchorAfter.slice(0, 35).trim();
|
|
5724
|
+
for (let i = 0; i < contentNodes.length; i++) {
|
|
5725
|
+
if (contentNodes[i].textContent?.includes(keyword)) {
|
|
5726
|
+
contentNodes.splice(i, 0, tableEl);
|
|
5727
|
+
inserted = true;
|
|
5728
|
+
break;
|
|
5729
|
+
}
|
|
5730
|
+
}
|
|
5731
|
+
}
|
|
5732
|
+
if (!inserted) {
|
|
5733
|
+
if (contentNodes.length > 2) {
|
|
5734
|
+
contentNodes.splice(2, 0, tableEl);
|
|
5735
|
+
} else {
|
|
5736
|
+
contentNodes.push(tableEl);
|
|
5737
|
+
}
|
|
5738
|
+
}
|
|
5739
|
+
});
|
|
4758
5740
|
wrapper.innerHTML = "";
|
|
4759
5741
|
contentNodes.forEach((node) => wrapper.appendChild(node));
|
|
4760
5742
|
const childHeights = contentNodes.map((c) => {
|
|
4761
5743
|
const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
|
|
4762
5744
|
const offH = c.offsetHeight || 0;
|
|
5745
|
+
const realH = Math.max(rectH, offH);
|
|
5746
|
+
if (realH > 0) return realH;
|
|
4763
5747
|
const textLen = c.textContent?.trim().length || 0;
|
|
4764
|
-
|
|
4765
|
-
return Math.max(rectH, offH, estH);
|
|
5748
|
+
return Math.max(24, Math.ceil(textLen / 95) * 22 + 12);
|
|
4766
5749
|
});
|
|
4767
5750
|
wrapper.innerHTML = "";
|
|
4768
5751
|
const createRtfCard = () => {
|
|
@@ -4771,35 +5754,49 @@ var RtfPlugin = class {
|
|
|
4771
5754
|
card.style.backgroundColor = "#ffffff";
|
|
4772
5755
|
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
4773
5756
|
card.style.borderRadius = "4px";
|
|
4774
|
-
card.style.padding = "
|
|
5757
|
+
card.style.padding = "64px 56px";
|
|
4775
5758
|
card.style.width = "816px";
|
|
4776
5759
|
card.style.minHeight = "1056px";
|
|
4777
5760
|
card.style.boxSizing = "border-box";
|
|
4778
5761
|
card.style.marginBottom = "24px";
|
|
4779
5762
|
card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4780
5763
|
card.style.lineHeight = "1.6";
|
|
5764
|
+
card.style.color = "#1e293b";
|
|
4781
5765
|
return card;
|
|
4782
5766
|
};
|
|
4783
5767
|
let curCard = createRtfCard();
|
|
4784
5768
|
wrapper.appendChild(curCard);
|
|
4785
5769
|
pageElements = [curCard];
|
|
4786
5770
|
let curH = 0;
|
|
4787
|
-
const maxH =
|
|
5771
|
+
const maxH = 928;
|
|
4788
5772
|
for (let i = 0; i < contentNodes.length; i++) {
|
|
4789
5773
|
const child = contentNodes[i];
|
|
4790
5774
|
const chH = childHeights[i];
|
|
4791
|
-
|
|
4792
|
-
curH
|
|
4793
|
-
|
|
5775
|
+
const isChildEmpty = (child.textContent || "").trim().length === 0 && !child.querySelector("table, img, svg, canvas");
|
|
5776
|
+
if (curH === 0 && isChildEmpty) {
|
|
5777
|
+
continue;
|
|
5778
|
+
}
|
|
5779
|
+
if (curH + chH > maxH && curCard.childNodes.length > 0) {
|
|
4794
5780
|
curCard = createRtfCard();
|
|
4795
5781
|
wrapper.appendChild(curCard);
|
|
4796
5782
|
pageElements.push(curCard);
|
|
4797
5783
|
curH = 0;
|
|
4798
5784
|
}
|
|
5785
|
+
curCard.appendChild(child);
|
|
5786
|
+
curH += chH;
|
|
5787
|
+
}
|
|
5788
|
+
pageElements = pageElements.filter((card) => {
|
|
5789
|
+
const hasText = (card.textContent || "").trim().length > 0;
|
|
5790
|
+
const hasMedia = card.querySelector("table, img, svg, canvas") !== null;
|
|
5791
|
+
return hasText || hasMedia;
|
|
5792
|
+
});
|
|
5793
|
+
if (pageElements.length === 0) {
|
|
5794
|
+
pageElements = [curCard];
|
|
4799
5795
|
}
|
|
4800
5796
|
} catch (err) {
|
|
4801
5797
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
4802
5798
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
5799
|
+
const tables = parseRtfTables(text);
|
|
4803
5800
|
const rawPages = text.split(/\\page\b/).map((segment) => {
|
|
4804
5801
|
return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
|
|
4805
5802
|
}).filter((p) => p.length > 0);
|
|
@@ -4810,47 +5807,26 @@ var RtfPlugin = class {
|
|
|
4810
5807
|
pageCard.style.backgroundColor = "#ffffff";
|
|
4811
5808
|
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4812
5809
|
pageCard.style.borderRadius = "4px";
|
|
4813
|
-
pageCard.style.padding = "
|
|
5810
|
+
pageCard.style.padding = "64px 56px";
|
|
4814
5811
|
pageCard.style.width = "816px";
|
|
4815
5812
|
pageCard.style.minHeight = "1056px";
|
|
4816
|
-
pageCard.style.maxWidth = "100%";
|
|
4817
5813
|
pageCard.style.boxSizing = "border-box";
|
|
4818
|
-
pageCard.style.fontFamily = "serif
|
|
5814
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4819
5815
|
pageCard.style.fontSize = "12pt";
|
|
4820
5816
|
pageCard.style.lineHeight = "1.6";
|
|
4821
5817
|
pageCard.style.color = "#1e293b";
|
|
4822
5818
|
pageCard.style.whiteSpace = "pre-wrap";
|
|
4823
5819
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4824
5820
|
pageCard.textContent = pages[i];
|
|
5821
|
+
if (i === 1 && tables.length > 0) {
|
|
5822
|
+
tables.forEach((tbl) => pageCard.appendChild(renderRtfTableElement(tbl)));
|
|
5823
|
+
}
|
|
4825
5824
|
wrapper.appendChild(pageCard);
|
|
4826
5825
|
pageElements.push(pageCard);
|
|
4827
5826
|
}
|
|
4828
5827
|
}
|
|
4829
5828
|
const totalPages = Math.max(1, pageElements.length);
|
|
4830
5829
|
let currentPage = 1;
|
|
4831
|
-
let indicator = null;
|
|
4832
|
-
if (totalPages > 1) {
|
|
4833
|
-
indicator = document.createElement("div");
|
|
4834
|
-
indicator.className = "fp-rtf-page-indicator";
|
|
4835
|
-
indicator.style.position = "sticky";
|
|
4836
|
-
indicator.style.bottom = "16px";
|
|
4837
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4838
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
4839
|
-
indicator.style.color = "#f8fafc";
|
|
4840
|
-
indicator.style.fontSize = "12px";
|
|
4841
|
-
indicator.style.fontWeight = "600";
|
|
4842
|
-
indicator.style.padding = "5px 14px";
|
|
4843
|
-
indicator.style.borderRadius = "20px";
|
|
4844
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4845
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4846
|
-
indicator.style.zIndex = "10";
|
|
4847
|
-
indicator.style.userSelect = "none";
|
|
4848
|
-
indicator.style.pointerEvents = "none";
|
|
4849
|
-
indicator.style.textAlign = "center";
|
|
4850
|
-
indicator.style.width = "fit-content";
|
|
4851
|
-
indicator.style.margin = "16px auto 0";
|
|
4852
|
-
ctx.container.appendChild(indicator);
|
|
4853
|
-
}
|
|
4854
5830
|
const showPage = (pageNum) => {
|
|
4855
5831
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4856
5832
|
if (totalPages > 1) {
|
|
@@ -4858,9 +5834,6 @@ var RtfPlugin = class {
|
|
|
4858
5834
|
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4859
5835
|
});
|
|
4860
5836
|
}
|
|
4861
|
-
if (indicator) {
|
|
4862
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4863
|
-
}
|
|
4864
5837
|
ctx.container.scrollTop = 0;
|
|
4865
5838
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4866
5839
|
};
|
|
@@ -4868,7 +5841,7 @@ var RtfPlugin = class {
|
|
|
4868
5841
|
showPage(1);
|
|
4869
5842
|
}
|
|
4870
5843
|
const cleanup = () => {
|
|
4871
|
-
|
|
5844
|
+
resizeObserver?.disconnect();
|
|
4872
5845
|
wrapper.remove();
|
|
4873
5846
|
ctx.container.innerHTML = "";
|
|
4874
5847
|
};
|
|
@@ -4878,22 +5851,52 @@ var RtfPlugin = class {
|
|
|
4878
5851
|
getPageCount: () => totalPages,
|
|
4879
5852
|
getCurrentPage: () => currentPage,
|
|
4880
5853
|
goToPage: (page) => showPage(page),
|
|
5854
|
+
getThumbnails: async () => {
|
|
5855
|
+
const items = [];
|
|
5856
|
+
for (let idx = 0; idx < totalPages; idx++) {
|
|
5857
|
+
const pageIdx = idx;
|
|
5858
|
+
items.push({
|
|
5859
|
+
index: pageIdx,
|
|
5860
|
+
label: `Page ${pageIdx + 1}`,
|
|
5861
|
+
render: async (canvas) => {
|
|
5862
|
+
const ctx2d = canvas.getContext("2d");
|
|
5863
|
+
if (!ctx2d) return;
|
|
5864
|
+
canvas.width = 140;
|
|
5865
|
+
canvas.height = 180;
|
|
5866
|
+
ctx2d.fillStyle = "#ffffff";
|
|
5867
|
+
ctx2d.fillRect(0, 0, 140, 180);
|
|
5868
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
5869
|
+
ctx2d.lineWidth = 1;
|
|
5870
|
+
ctx2d.strokeRect(0.5, 0.5, 139, 179);
|
|
5871
|
+
ctx2d.fillStyle = "#334155";
|
|
5872
|
+
ctx2d.font = 'bold 11px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
5873
|
+
ctx2d.textAlign = "center";
|
|
5874
|
+
ctx2d.fillText(`Page ${pageIdx + 1}`, 70, 95);
|
|
5875
|
+
}
|
|
5876
|
+
});
|
|
5877
|
+
}
|
|
5878
|
+
return items;
|
|
5879
|
+
},
|
|
4881
5880
|
zoomIn: () => {
|
|
5881
|
+
isUserZoomed = true;
|
|
4882
5882
|
scale += 0.15;
|
|
4883
5883
|
applyTransform();
|
|
4884
5884
|
},
|
|
4885
5885
|
zoomOut: () => {
|
|
5886
|
+
isUserZoomed = true;
|
|
4886
5887
|
scale = Math.max(0.2, scale - 0.15);
|
|
4887
5888
|
applyTransform();
|
|
4888
5889
|
},
|
|
4889
5890
|
getZoom: () => scale,
|
|
4890
5891
|
setZoom: (level) => {
|
|
5892
|
+
isUserZoomed = true;
|
|
4891
5893
|
scale = level;
|
|
4892
5894
|
applyTransform();
|
|
4893
5895
|
},
|
|
4894
5896
|
fitToPage: () => {
|
|
4895
|
-
|
|
4896
|
-
|
|
5897
|
+
isUserZoomed = false;
|
|
5898
|
+
fitMode = "width";
|
|
5899
|
+
scale = calculateFitScale("width");
|
|
4897
5900
|
rotation = 0;
|
|
4898
5901
|
applyTransform();
|
|
4899
5902
|
},
|
|
@@ -5081,40 +6084,36 @@ var OpenDocumentPlugin = class {
|
|
|
5081
6084
|
const isPresentation = instance.isPresentation;
|
|
5082
6085
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5083
6086
|
const actions = [];
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
max
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
if (
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
instance.goToPage?.(page);
|
|
5112
|
-
} else if (typeof action === "number") {
|
|
5113
|
-
instance.goToPage?.(action);
|
|
5114
|
-
}
|
|
6087
|
+
actions.push({
|
|
6088
|
+
id: "thumbnails",
|
|
6089
|
+
icon: "thumbnails",
|
|
6090
|
+
label: isPresentation ? "Slide Thumbnails" : "Page Thumbnails",
|
|
6091
|
+
type: "button",
|
|
6092
|
+
group: "navigation",
|
|
6093
|
+
execute: () => instance.toggleThumbnails?.()
|
|
6094
|
+
});
|
|
6095
|
+
actions.push({
|
|
6096
|
+
id: "page-nav",
|
|
6097
|
+
icon: "",
|
|
6098
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
6099
|
+
type: "page-nav",
|
|
6100
|
+
group: "navigation",
|
|
6101
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
6102
|
+
max: totalPages,
|
|
6103
|
+
execute: (action, page) => {
|
|
6104
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
6105
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
6106
|
+
if (action === "prev") {
|
|
6107
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
6108
|
+
} else if (action === "next") {
|
|
6109
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
6110
|
+
} else if (typeof page === "number") {
|
|
6111
|
+
instance.goToPage?.(page);
|
|
6112
|
+
} else if (typeof action === "number") {
|
|
6113
|
+
instance.goToPage?.(action);
|
|
5115
6114
|
}
|
|
5116
|
-
}
|
|
5117
|
-
}
|
|
6115
|
+
}
|
|
6116
|
+
});
|
|
5118
6117
|
actions.push(
|
|
5119
6118
|
{
|
|
5120
6119
|
id: "zoom-out",
|
|
@@ -5205,49 +6204,65 @@ var OpenDocumentPlugin = class {
|
|
|
5205
6204
|
container.className = "fp-odf-container";
|
|
5206
6205
|
container.style.width = "100%";
|
|
5207
6206
|
container.style.height = "100%";
|
|
5208
|
-
container.style.
|
|
5209
|
-
container.style.
|
|
6207
|
+
container.style.overflowX = "hidden";
|
|
6208
|
+
container.style.overflowY = "auto";
|
|
6209
|
+
container.style.padding = "16px 8px";
|
|
5210
6210
|
container.style.backgroundColor = "#f1f5f9";
|
|
5211
6211
|
const wrapper = document.createElement("div");
|
|
5212
6212
|
wrapper.className = "fp-odf-wrapper";
|
|
5213
6213
|
wrapper.style.margin = "0 auto";
|
|
6214
|
+
wrapper.style.width = isPresentation ? "960px" : "816px";
|
|
6215
|
+
wrapper.style.boxSizing = "border-box";
|
|
5214
6216
|
wrapper.style.backgroundColor = "#ffffff";
|
|
5215
6217
|
wrapper.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
5216
6218
|
wrapper.style.borderRadius = "4px";
|
|
5217
6219
|
wrapper.style.transformOrigin = "top center";
|
|
5218
|
-
wrapper.style.transition = "transform 0.
|
|
6220
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5219
6221
|
container.appendChild(wrapper);
|
|
5220
6222
|
ctx.container.appendChild(container);
|
|
5221
6223
|
let scale = 1;
|
|
5222
6224
|
let rotation = 0;
|
|
5223
|
-
let
|
|
6225
|
+
let isUserZoomed = false;
|
|
6226
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6227
|
+
let currentPage = 1;
|
|
6228
|
+
let totalPages = 1;
|
|
6229
|
+
let slides = [];
|
|
5224
6230
|
const calculateFitScale = (mode = fitMode) => {
|
|
5225
|
-
const
|
|
5226
|
-
const
|
|
5227
|
-
const
|
|
5228
|
-
const
|
|
6231
|
+
const activeSlide = slides[currentPage - 1];
|
|
6232
|
+
const elW = isPresentation ? 960 : 816;
|
|
6233
|
+
const singlePageH = Math.min(activeSlide?.offsetHeight || wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
6234
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6235
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5229
6236
|
const sW = availW / elW;
|
|
5230
6237
|
const sH = availH / (isPresentation ? 540 : singlePageH);
|
|
5231
6238
|
if (isPresentation) {
|
|
5232
|
-
return Math.min(
|
|
6239
|
+
return Math.min(2.5, Math.min(sW, sH));
|
|
5233
6240
|
}
|
|
5234
6241
|
if (mode === "page") {
|
|
5235
|
-
return Math.max(0.
|
|
6242
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5236
6243
|
}
|
|
5237
|
-
return Math.max(0.
|
|
6244
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5238
6245
|
};
|
|
5239
6246
|
const applyTransform = () => {
|
|
5240
6247
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5241
6248
|
wrapper.style.transformOrigin = "top center";
|
|
6249
|
+
const activeSlide = slides[currentPage - 1];
|
|
6250
|
+
const baseH = activeSlide?.offsetHeight || wrapper.offsetHeight || 1056;
|
|
6251
|
+
const scaledH = baseH * scale;
|
|
6252
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6253
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
5242
6254
|
};
|
|
6255
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6256
|
+
if (!isUserZoomed) {
|
|
6257
|
+
scale = calculateFitScale(fitMode);
|
|
6258
|
+
applyTransform();
|
|
6259
|
+
}
|
|
6260
|
+
}) : null;
|
|
6261
|
+
resizeObserver?.observe(ctx.container);
|
|
5243
6262
|
setTimeout(() => {
|
|
5244
|
-
|
|
5245
|
-
scale = calculateFitScale("width");
|
|
6263
|
+
scale = calculateFitScale(fitMode);
|
|
5246
6264
|
applyTransform();
|
|
5247
6265
|
}, 60);
|
|
5248
|
-
let currentPage = 1;
|
|
5249
|
-
let totalPages = 1;
|
|
5250
|
-
let slides = [];
|
|
5251
6266
|
if (isPresentation) {
|
|
5252
6267
|
wrapper.style.maxWidth = "960px";
|
|
5253
6268
|
wrapper.style.aspectRatio = "16 / 9";
|
|
@@ -5348,24 +6363,9 @@ var OpenDocumentPlugin = class {
|
|
|
5348
6363
|
wrapper.appendChild(page);
|
|
5349
6364
|
slides.push(page);
|
|
5350
6365
|
});
|
|
5351
|
-
const pageIndicator = document.createElement("div");
|
|
5352
|
-
pageIndicator.className = "fp-odt-page-indicator";
|
|
5353
|
-
pageIndicator.style.position = "sticky";
|
|
5354
|
-
pageIndicator.style.bottom = "16px";
|
|
5355
|
-
pageIndicator.style.left = "50%";
|
|
5356
|
-
pageIndicator.style.transform = "translateX(-50%)";
|
|
5357
|
-
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
5358
|
-
pageIndicator.style.color = "#fff";
|
|
5359
|
-
pageIndicator.style.padding = "6px 12px";
|
|
5360
|
-
pageIndicator.style.borderRadius = "16px";
|
|
5361
|
-
pageIndicator.style.fontSize = "12px";
|
|
5362
|
-
pageIndicator.style.zIndex = "100";
|
|
5363
|
-
pageIndicator.style.display = "inline-block";
|
|
5364
|
-
pageIndicator.style.width = "fit-content";
|
|
5365
|
-
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
5366
|
-
container.appendChild(pageIndicator);
|
|
5367
6366
|
}
|
|
5368
6367
|
const cleanup = () => {
|
|
6368
|
+
resizeObserver?.disconnect();
|
|
5369
6369
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
5370
6370
|
container.remove();
|
|
5371
6371
|
ctx.container.innerHTML = "";
|
|
@@ -5377,10 +6377,6 @@ var OpenDocumentPlugin = class {
|
|
|
5377
6377
|
slides.forEach((s, idx) => {
|
|
5378
6378
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
5379
6379
|
});
|
|
5380
|
-
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
5381
|
-
if (indicator) {
|
|
5382
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5383
|
-
}
|
|
5384
6380
|
container.scrollTop = 0;
|
|
5385
6381
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5386
6382
|
};
|
|
@@ -5388,21 +6384,25 @@ var OpenDocumentPlugin = class {
|
|
|
5388
6384
|
destroy: cleanup,
|
|
5389
6385
|
isPresentation,
|
|
5390
6386
|
zoomIn: () => {
|
|
6387
|
+
isUserZoomed = true;
|
|
5391
6388
|
scale += 0.15;
|
|
5392
6389
|
applyTransform();
|
|
5393
6390
|
},
|
|
5394
6391
|
zoomOut: () => {
|
|
6392
|
+
isUserZoomed = true;
|
|
5395
6393
|
scale = Math.max(0.2, scale - 0.15);
|
|
5396
6394
|
applyTransform();
|
|
5397
6395
|
},
|
|
5398
6396
|
getZoom: () => scale,
|
|
5399
6397
|
setZoom: (level) => {
|
|
6398
|
+
isUserZoomed = true;
|
|
5400
6399
|
scale = level;
|
|
5401
6400
|
applyTransform();
|
|
5402
6401
|
},
|
|
5403
6402
|
fitToPage: () => {
|
|
5404
|
-
|
|
5405
|
-
|
|
6403
|
+
isUserZoomed = false;
|
|
6404
|
+
fitMode = "width";
|
|
6405
|
+
scale = calculateFitScale("width");
|
|
5406
6406
|
rotation = 0;
|
|
5407
6407
|
applyTransform();
|
|
5408
6408
|
},
|
|
@@ -5418,23 +6418,45 @@ var OpenDocumentPlugin = class {
|
|
|
5418
6418
|
getPageCount: () => totalPages,
|
|
5419
6419
|
getCurrentPage: () => currentPage,
|
|
5420
6420
|
getThumbnails: async () => {
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
canvas
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
6421
|
+
const count = totalPages || slides.length || 1;
|
|
6422
|
+
const items = [];
|
|
6423
|
+
for (let idx = 0; idx < count; idx++) {
|
|
6424
|
+
const itemIdx = idx;
|
|
6425
|
+
items.push({
|
|
6426
|
+
index: itemIdx,
|
|
6427
|
+
label: isPresentation ? `Slide ${itemIdx + 1}` : `Page ${itemIdx + 1}`,
|
|
6428
|
+
render: async (canvas) => {
|
|
6429
|
+
const ctx2d = canvas.getContext("2d");
|
|
6430
|
+
if (!ctx2d) return;
|
|
6431
|
+
if (isPresentation) {
|
|
6432
|
+
canvas.width = 160;
|
|
6433
|
+
canvas.height = 90;
|
|
6434
|
+
ctx2d.fillStyle = "#f8fafc";
|
|
6435
|
+
ctx2d.fillRect(0, 0, 160, 90);
|
|
6436
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6437
|
+
ctx2d.lineWidth = 1;
|
|
6438
|
+
ctx2d.strokeRect(0.5, 0.5, 159, 89);
|
|
6439
|
+
ctx2d.fillStyle = "#334155";
|
|
6440
|
+
ctx2d.font = "bold 11px sans-serif";
|
|
6441
|
+
ctx2d.textAlign = "center";
|
|
6442
|
+
ctx2d.fillText(`Slide ${itemIdx + 1}`, 80, 50);
|
|
6443
|
+
} else {
|
|
6444
|
+
canvas.width = 140;
|
|
6445
|
+
canvas.height = 180;
|
|
6446
|
+
ctx2d.fillStyle = "#ffffff";
|
|
6447
|
+
ctx2d.fillRect(0, 0, 140, 180);
|
|
6448
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6449
|
+
ctx2d.lineWidth = 1;
|
|
6450
|
+
ctx2d.strokeRect(0.5, 0.5, 139, 179);
|
|
6451
|
+
ctx2d.fillStyle = "#64748b";
|
|
6452
|
+
ctx2d.font = "bold 10px sans-serif";
|
|
6453
|
+
ctx2d.textAlign = "center";
|
|
6454
|
+
ctx2d.fillText(`Page ${itemIdx + 1}`, 70, 90);
|
|
6455
|
+
}
|
|
6456
|
+
}
|
|
6457
|
+
});
|
|
6458
|
+
}
|
|
6459
|
+
return items;
|
|
5438
6460
|
},
|
|
5439
6461
|
download: () => {
|
|
5440
6462
|
const mimeType = this.mimeTypes.find((m) => m.includes(ext.replace(".", ""))) || "application/octet-stream";
|
|
@@ -5539,23 +6561,24 @@ var OpenDocumentPlugin = class {
|
|
|
5539
6561
|
case "h": {
|
|
5540
6562
|
const level = Math.min(6, Math.max(1, Number(node.getAttribute("text:outline-level") || 1)));
|
|
5541
6563
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5542
|
-
html += `<h${level} style="${style}; font-family:
|
|
6564
|
+
html += `<h${level} style="${style}; margin: 18px 0 8px; color: #1e3a8a; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${node.textContent || ""}</h${level}>`;
|
|
5543
6565
|
break;
|
|
5544
6566
|
}
|
|
5545
6567
|
case "p": {
|
|
5546
6568
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5547
6569
|
const inner = this.renderSpans(node, styles, images);
|
|
5548
|
-
|
|
6570
|
+
const isInsideLi = node.parentElement?.localName === "list-item" || node.parentElement?.tagName?.toLowerCase() === "list-item";
|
|
6571
|
+
html += `<p style="${style}; line-height: 1.5; margin: ${isInsideLi ? "0" : "8px 0 12px"}; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${inner}</p>`;
|
|
5549
6572
|
break;
|
|
5550
6573
|
}
|
|
5551
6574
|
case "list": {
|
|
5552
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
6575
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
5553
6576
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5554
6577
|
html += "</ul>";
|
|
5555
6578
|
break;
|
|
5556
6579
|
}
|
|
5557
6580
|
case "list-item": {
|
|
5558
|
-
html +=
|
|
6581
|
+
html += '<li style="margin: 4px 0; font-size: 11pt; line-height: 1.5; color: #1e293b;">';
|
|
5559
6582
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5560
6583
|
html += "</li>";
|
|
5561
6584
|
break;
|
|
@@ -5681,28 +6704,26 @@ var DocPlugin = class {
|
|
|
5681
6704
|
getToolbarActions(instance) {
|
|
5682
6705
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5683
6706
|
const actions = [];
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
if (
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
instance.goToPage?.(page);
|
|
5702
|
-
}
|
|
6707
|
+
actions.push({
|
|
6708
|
+
id: "page-nav",
|
|
6709
|
+
icon: "",
|
|
6710
|
+
label: "Page Navigation",
|
|
6711
|
+
type: "page-nav",
|
|
6712
|
+
group: "navigation",
|
|
6713
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
6714
|
+
max: totalPages,
|
|
6715
|
+
execute: (action, page) => {
|
|
6716
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
6717
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
6718
|
+
if (action === "prev") {
|
|
6719
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
6720
|
+
} else if (action === "next") {
|
|
6721
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
6722
|
+
} else if (typeof page === "number") {
|
|
6723
|
+
instance.goToPage?.(page);
|
|
5703
6724
|
}
|
|
5704
|
-
}
|
|
5705
|
-
}
|
|
6725
|
+
}
|
|
6726
|
+
});
|
|
5706
6727
|
actions.push(
|
|
5707
6728
|
{
|
|
5708
6729
|
id: "zoom-out",
|
|
@@ -5776,8 +6797,9 @@ var DocPlugin = class {
|
|
|
5776
6797
|
container.className = "fp-doc-container";
|
|
5777
6798
|
container.style.width = "100%";
|
|
5778
6799
|
container.style.height = "100%";
|
|
5779
|
-
container.style.
|
|
5780
|
-
container.style.
|
|
6800
|
+
container.style.overflowX = "hidden";
|
|
6801
|
+
container.style.overflowY = "auto";
|
|
6802
|
+
container.style.padding = "16px 8px";
|
|
5781
6803
|
container.style.backgroundColor = "#f1f5f9";
|
|
5782
6804
|
container.style.display = "flex";
|
|
5783
6805
|
container.style.justifyContent = "center";
|
|
@@ -5822,16 +6844,15 @@ var DocPlugin = class {
|
|
|
5822
6844
|
const pageCard = document.createElement("div");
|
|
5823
6845
|
pageCard.className = "fp-doc-page-card";
|
|
5824
6846
|
pageCard.style.width = "816px";
|
|
5825
|
-
pageCard.style.
|
|
6847
|
+
pageCard.style.minHeight = "1056px";
|
|
5826
6848
|
pageCard.style.backgroundColor = "#ffffff";
|
|
5827
|
-
pageCard.style.boxShadow = "0
|
|
6849
|
+
pageCard.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
5828
6850
|
pageCard.style.borderRadius = "4px";
|
|
5829
|
-
pageCard.style.padding = "
|
|
6851
|
+
pageCard.style.padding = "72px 56px";
|
|
5830
6852
|
pageCard.style.boxSizing = "border-box";
|
|
5831
|
-
pageCard.style.overflow = "hidden";
|
|
5832
6853
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5833
6854
|
pageCard.style.transformOrigin = "top center";
|
|
5834
|
-
pageCard.style.transition = "transform 0.
|
|
6855
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
5835
6856
|
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5836
6857
|
pageCard.style.color = "#1e293b";
|
|
5837
6858
|
if (isFallback && i === 0) {
|
|
@@ -5848,34 +6869,15 @@ var DocPlugin = class {
|
|
|
5848
6869
|
container.appendChild(pageCard);
|
|
5849
6870
|
pageCards.push(pageCard);
|
|
5850
6871
|
}
|
|
5851
|
-
let indicator = null;
|
|
5852
|
-
if (totalPages > 1) {
|
|
5853
|
-
indicator = document.createElement("div");
|
|
5854
|
-
indicator.className = "fp-doc-page-indicator";
|
|
5855
|
-
indicator.style.position = "fixed";
|
|
5856
|
-
indicator.style.bottom = "16px";
|
|
5857
|
-
indicator.style.left = "50%";
|
|
5858
|
-
indicator.style.transform = "translateX(-50%)";
|
|
5859
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
5860
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
5861
|
-
indicator.style.color = "#f8fafc";
|
|
5862
|
-
indicator.style.fontSize = "12px";
|
|
5863
|
-
indicator.style.fontWeight = "600";
|
|
5864
|
-
indicator.style.padding = "5px 14px";
|
|
5865
|
-
indicator.style.borderRadius = "20px";
|
|
5866
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
5867
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
5868
|
-
indicator.style.zIndex = "10";
|
|
5869
|
-
indicator.style.userSelect = "none";
|
|
5870
|
-
indicator.style.pointerEvents = "none";
|
|
5871
|
-
indicator.style.textAlign = "center";
|
|
5872
|
-
container.appendChild(indicator);
|
|
5873
|
-
}
|
|
5874
6872
|
let rotation = 0;
|
|
5875
6873
|
const applyTransform = () => {
|
|
5876
6874
|
const activeCard = pageCards[currentPage - 1];
|
|
5877
6875
|
if (activeCard) {
|
|
5878
6876
|
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
6877
|
+
const baseH = activeCard.offsetHeight || 1056;
|
|
6878
|
+
const scaledH = baseH * scale;
|
|
6879
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6880
|
+
activeCard.style.marginBottom = `${extraH + 32}px`;
|
|
5879
6881
|
}
|
|
5880
6882
|
};
|
|
5881
6883
|
const showPage = (pageNum) => {
|
|
@@ -5888,35 +6890,39 @@ var DocPlugin = class {
|
|
|
5888
6890
|
card.style.display = "none";
|
|
5889
6891
|
}
|
|
5890
6892
|
});
|
|
5891
|
-
if (indicator) {
|
|
5892
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5893
|
-
}
|
|
5894
6893
|
container.scrollTop = 0;
|
|
5895
6894
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5896
6895
|
};
|
|
5897
6896
|
if (totalPages > 1) {
|
|
5898
6897
|
showPage(1);
|
|
5899
6898
|
}
|
|
5900
|
-
let fitMode = "width";
|
|
6899
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6900
|
+
let isUserZoomed = false;
|
|
5901
6901
|
const calculateFitScale = (mode = fitMode) => {
|
|
5902
6902
|
const elW = 816;
|
|
5903
6903
|
const elH = 1056;
|
|
5904
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
5905
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
6904
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6905
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5906
6906
|
const sW = availW / elW;
|
|
5907
6907
|
const sH = availH / elH;
|
|
5908
6908
|
if (mode === "page") {
|
|
5909
|
-
return Math.max(0.
|
|
6909
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5910
6910
|
}
|
|
5911
|
-
return Math.max(0.
|
|
6911
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5912
6912
|
};
|
|
6913
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6914
|
+
if (!isUserZoomed) {
|
|
6915
|
+
scale = calculateFitScale(fitMode);
|
|
6916
|
+
applyTransform();
|
|
6917
|
+
}
|
|
6918
|
+
}) : null;
|
|
6919
|
+
resizeObserver?.observe(ctx.container);
|
|
5913
6920
|
setTimeout(() => {
|
|
5914
|
-
|
|
5915
|
-
scale = calculateFitScale("width");
|
|
6921
|
+
scale = calculateFitScale(fitMode);
|
|
5916
6922
|
applyTransform();
|
|
5917
6923
|
}, 60);
|
|
5918
6924
|
const cleanup = () => {
|
|
5919
|
-
|
|
6925
|
+
resizeObserver?.disconnect();
|
|
5920
6926
|
container.remove();
|
|
5921
6927
|
ctx.container.innerHTML = "";
|
|
5922
6928
|
};
|
|
@@ -5927,21 +6933,25 @@ var DocPlugin = class {
|
|
|
5927
6933
|
getCurrentPage: () => currentPage,
|
|
5928
6934
|
goToPage: (page) => showPage(page),
|
|
5929
6935
|
zoomIn: () => {
|
|
6936
|
+
isUserZoomed = true;
|
|
5930
6937
|
scale += 0.15;
|
|
5931
6938
|
applyTransform();
|
|
5932
6939
|
},
|
|
5933
6940
|
zoomOut: () => {
|
|
6941
|
+
isUserZoomed = true;
|
|
5934
6942
|
scale = Math.max(0.2, scale - 0.15);
|
|
5935
6943
|
applyTransform();
|
|
5936
6944
|
},
|
|
5937
6945
|
getZoom: () => scale,
|
|
5938
6946
|
setZoom: (level) => {
|
|
6947
|
+
isUserZoomed = true;
|
|
5939
6948
|
scale = level;
|
|
5940
6949
|
applyTransform();
|
|
5941
6950
|
},
|
|
5942
6951
|
fitToPage: () => {
|
|
5943
|
-
|
|
5944
|
-
|
|
6952
|
+
isUserZoomed = false;
|
|
6953
|
+
fitMode = "width";
|
|
6954
|
+
scale = calculateFitScale("width");
|
|
5945
6955
|
rotation = 0;
|
|
5946
6956
|
applyTransform();
|
|
5947
6957
|
},
|
|
@@ -6318,25 +7328,31 @@ ${chartSvg}
|
|
|
6318
7328
|
i++;
|
|
6319
7329
|
continue;
|
|
6320
7330
|
}
|
|
6321
|
-
if (
|
|
7331
|
+
if (/^\d{1,2}$/.test(line.trim())) {
|
|
7332
|
+
i++;
|
|
7333
|
+
continue;
|
|
7334
|
+
}
|
|
7335
|
+
const isShortLine = line.length < 60 && !line.endsWith(".") && !line.endsWith(",");
|
|
7336
|
+
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));
|
|
7337
|
+
if (isTitleLike) {
|
|
6322
7338
|
if (inList) {
|
|
6323
7339
|
html += "</ul>";
|
|
6324
7340
|
inList = false;
|
|
6325
7341
|
}
|
|
6326
|
-
html += `<h2 style="font-size:
|
|
7342
|
+
html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 18px 0 10px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6__default.default.sanitize(line, sanitizeOptions)}</h2>`;
|
|
6327
7343
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
6328
7344
|
if (!inList) {
|
|
6329
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
7345
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
6330
7346
|
inList = true;
|
|
6331
7347
|
}
|
|
6332
7348
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
6333
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
7349
|
+
html += `<li style="margin: 4px 0; line-height: 1.5; font-size: 11pt; color: #1e293b;">${DOMPurify6__default.default.sanitize(bulletText, sanitizeOptions)}</li>`;
|
|
6334
7350
|
} else {
|
|
6335
7351
|
if (inList) {
|
|
6336
7352
|
html += "</ul>";
|
|
6337
7353
|
inList = false;
|
|
6338
7354
|
}
|
|
6339
|
-
html += `<p style="line-height: 1.
|
|
7355
|
+
html += `<p style="line-height: 1.5; margin: 0 0 12px 0; font-size: 11pt; color: #1e293b; text-align: justify;">${DOMPurify6__default.default.sanitize(line, sanitizeOptions)}</p>`;
|
|
6340
7356
|
}
|
|
6341
7357
|
i++;
|
|
6342
7358
|
}
|