@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.js
CHANGED
|
@@ -578,8 +578,7 @@ var ICON_FULLSCREEN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="non
|
|
|
578
578
|
var ICON_COPY = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`;
|
|
579
579
|
var ICON_FAST_FORWARD = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 19 22 12 13 5 13 19"></polygon><polygon points="2 19 11 12 2 5 2 19"></polygon></svg>`;
|
|
580
580
|
var ICON_REWIND = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="11 19 2 12 11 5 11 19"></polygon><polygon points="22 19 13 12 22 5 22 19"></polygon></svg>`;
|
|
581
|
-
var
|
|
582
|
-
var ICON_EXTERNAL_WINDOW = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>`;
|
|
581
|
+
var ICON_EXTERNAL_WINDOW = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"></rect><line x1="3" y1="8" x2="21" y2="8"></line><circle cx="6" cy="5.5" r="0.75" fill="currentColor"></circle><circle cx="8.5" cy="5.5" r="0.75" fill="currentColor"></circle><polyline points="14 13 18 13 18 17"></polyline><line x1="11" y1="20" x2="18" y2="13"></line></svg>`;
|
|
583
582
|
var ICON_MAP = {
|
|
584
583
|
"zoom-in": ICON_ZOOM_IN,
|
|
585
584
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -606,28 +605,177 @@ var ICON_MAP = {
|
|
|
606
605
|
"forward-10": ICON_FAST_FORWARD,
|
|
607
606
|
"rewind": ICON_REWIND,
|
|
608
607
|
"replay-10": ICON_REWIND,
|
|
609
|
-
"speed": ICON_SPEED,
|
|
610
608
|
"open-window": ICON_EXTERNAL_WINDOW,
|
|
611
|
-
"external-window": ICON_EXTERNAL_WINDOW
|
|
609
|
+
"external-window": ICON_EXTERNAL_WINDOW,
|
|
610
|
+
"openWindow": ICON_EXTERNAL_WINDOW,
|
|
611
|
+
"openSeparateWindow": ICON_EXTERNAL_WINDOW
|
|
612
612
|
};
|
|
613
613
|
var ToolbarController = class {
|
|
614
614
|
el;
|
|
615
615
|
toolbarEl;
|
|
616
616
|
actions = [];
|
|
617
|
+
config = {};
|
|
617
618
|
pageInputEl = null;
|
|
618
619
|
pageLabelEl = null;
|
|
619
|
-
|
|
620
|
+
prevPageBtn = null;
|
|
621
|
+
nextPageBtn = null;
|
|
622
|
+
constructor(container, config) {
|
|
620
623
|
this.el = container;
|
|
624
|
+
if (config) this.config = { ...config };
|
|
621
625
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
622
626
|
this.el.appendChild(this.toolbarEl);
|
|
623
627
|
}
|
|
628
|
+
setConfig(config) {
|
|
629
|
+
this.config = { ...config };
|
|
630
|
+
this.render();
|
|
631
|
+
}
|
|
632
|
+
getConfig() {
|
|
633
|
+
return { ...this.config };
|
|
634
|
+
}
|
|
635
|
+
hideAction(actionId) {
|
|
636
|
+
this.config[actionId] = false;
|
|
637
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = false;
|
|
638
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = false;
|
|
639
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
640
|
+
this.config.fitPage = false;
|
|
641
|
+
this.config.fitToPage = false;
|
|
642
|
+
this.config.fitWidth = false;
|
|
643
|
+
}
|
|
644
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = false;
|
|
645
|
+
if (actionId === "fullscreen") this.config.fullscreen = false;
|
|
646
|
+
if (actionId === "download") this.config.download = false;
|
|
647
|
+
if (actionId === "print") this.config.print = false;
|
|
648
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
649
|
+
this.config.openWindow = false;
|
|
650
|
+
this.config.openSeparateWindow = false;
|
|
651
|
+
}
|
|
652
|
+
if (actionId === "copy") this.config.copy = false;
|
|
653
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
654
|
+
this.config.pageNav = false;
|
|
655
|
+
this.config.pagination = false;
|
|
656
|
+
}
|
|
657
|
+
this.render();
|
|
658
|
+
}
|
|
659
|
+
showAction(actionId) {
|
|
660
|
+
this.config[actionId] = true;
|
|
661
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = true;
|
|
662
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = true;
|
|
663
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
664
|
+
this.config.fitPage = true;
|
|
665
|
+
this.config.fitToPage = true;
|
|
666
|
+
this.config.fitWidth = true;
|
|
667
|
+
}
|
|
668
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = true;
|
|
669
|
+
if (actionId === "fullscreen") this.config.fullscreen = true;
|
|
670
|
+
if (actionId === "download") this.config.download = true;
|
|
671
|
+
if (actionId === "print") this.config.print = true;
|
|
672
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
673
|
+
this.config.openWindow = true;
|
|
674
|
+
this.config.openSeparateWindow = true;
|
|
675
|
+
}
|
|
676
|
+
if (actionId === "copy") this.config.copy = true;
|
|
677
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
678
|
+
this.config.pageNav = true;
|
|
679
|
+
this.config.pagination = true;
|
|
680
|
+
}
|
|
681
|
+
this.render();
|
|
682
|
+
}
|
|
683
|
+
normalizeActionId(actionId) {
|
|
684
|
+
if (actionId === "zoomIn") return "zoom-in";
|
|
685
|
+
if (actionId === "zoomOut") return "zoom-out";
|
|
686
|
+
if (actionId === "fitPage" || actionId === "fitToPage" || actionId === "fitWidth") return "fit-page";
|
|
687
|
+
if (actionId === "rotateCW") return "rotate-cw";
|
|
688
|
+
if (actionId === "rotateCCW") return "rotate-ccw";
|
|
689
|
+
if (actionId === "openWindow" || actionId === "openSeparateWindow") return "open-window";
|
|
690
|
+
if (actionId === "pageNav") return "page-nav";
|
|
691
|
+
return actionId;
|
|
692
|
+
}
|
|
693
|
+
enableAction(actionId) {
|
|
694
|
+
const norm = this.normalizeActionId(actionId);
|
|
695
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
696
|
+
if (btn) {
|
|
697
|
+
btn.disabled = false;
|
|
698
|
+
btn.classList.remove("disabled");
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
disableAction(actionId) {
|
|
702
|
+
const norm = this.normalizeActionId(actionId);
|
|
703
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
704
|
+
if (btn) {
|
|
705
|
+
btn.disabled = true;
|
|
706
|
+
btn.classList.add("disabled");
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
setActionActive(actionId, active) {
|
|
710
|
+
const norm = this.normalizeActionId(actionId);
|
|
711
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
712
|
+
if (btn) {
|
|
713
|
+
if (active) {
|
|
714
|
+
btn.classList.add("active");
|
|
715
|
+
} else {
|
|
716
|
+
btn.classList.remove("active");
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
isActionEnabled(action) {
|
|
721
|
+
const c = this.config;
|
|
722
|
+
const id = action.id;
|
|
723
|
+
if (c[id] === false) return false;
|
|
724
|
+
if (id === "zoom-in" && (c.zoomIn === false || c["zoom-in"] === false)) return false;
|
|
725
|
+
if (id === "zoom-out" && (c.zoomOut === false || c["zoom-out"] === false)) return false;
|
|
726
|
+
if ((id === "fit-page" || id === "fit-width" || id === "fit-slide") && (c.fitPage === false || c.fitToPage === false || c.fitWidth === false || c["fit-page"] === false || c["fit-width"] === false)) {
|
|
727
|
+
return false;
|
|
728
|
+
}
|
|
729
|
+
if ((id === "rotate-cw" || id === "rotate-ccw" || id === "rotate") && (c.rotate === false || c.rotateCW === false || c.rotateCCW === false || c["rotate-cw"] === false)) {
|
|
730
|
+
return false;
|
|
731
|
+
}
|
|
732
|
+
if (id === "fullscreen" && c.fullscreen === false) return false;
|
|
733
|
+
if (id === "download" && c.download === false) return false;
|
|
734
|
+
if (id === "print" && c.print === false) return false;
|
|
735
|
+
if ((id === "open-window" || id === "external-window") && (c.openWindow === false || c.openSeparateWindow === false || c["open-window"] === false)) {
|
|
736
|
+
return false;
|
|
737
|
+
}
|
|
738
|
+
if (id === "copy" && c.copy === false) return false;
|
|
739
|
+
if (id === "thumbnails" && c.thumbnails === false) return false;
|
|
740
|
+
if (id === "page-nav" && (c.pageNav === false || c.pagination === false || c["page-nav"] === false)) {
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
743
|
+
if ((id === "prev" || id === "page-prev") && (c.prevPage === false || c.prev === false || c["prev"] === false || c.pageNav === false || c.pagination === false)) {
|
|
744
|
+
return false;
|
|
745
|
+
}
|
|
746
|
+
if ((id === "next" || id === "page-next") && (c.nextPage === false || c.next === false || c["next"] === false || c.pageNav === false || c.pagination === false)) {
|
|
747
|
+
return false;
|
|
748
|
+
}
|
|
749
|
+
if (id === "play" && c.play === false) return false;
|
|
750
|
+
if (id === "pause" && c.pause === false) return false;
|
|
751
|
+
if ((id === "fast-forward" || id === "forward-10") && (c.fastForward === false || c["fast-forward"] === false)) {
|
|
752
|
+
return false;
|
|
753
|
+
}
|
|
754
|
+
if ((id === "rewind" || id === "replay-10") && (c.rewind === false || c["rewind"] === false)) {
|
|
755
|
+
return false;
|
|
756
|
+
}
|
|
757
|
+
if (id === "speed" && c.speed === false) return false;
|
|
758
|
+
return true;
|
|
759
|
+
}
|
|
624
760
|
setPage(page, max) {
|
|
625
761
|
if (this.pageInputEl) {
|
|
626
762
|
this.pageInputEl.value = page.toString();
|
|
763
|
+
if (max !== void 0) {
|
|
764
|
+
this.pageInputEl.max = max.toString();
|
|
765
|
+
}
|
|
627
766
|
}
|
|
628
767
|
if (max !== void 0 && this.pageLabelEl) {
|
|
629
768
|
this.pageLabelEl.textContent = ` / ${max}`;
|
|
630
769
|
}
|
|
770
|
+
const currentMax = max !== void 0 ? max : parseInt(this.pageInputEl?.max || "1", 10) || 1;
|
|
771
|
+
if (this.prevPageBtn) {
|
|
772
|
+
this.prevPageBtn.disabled = page <= 1;
|
|
773
|
+
this.prevPageBtn.style.opacity = page <= 1 ? "0.4" : "1";
|
|
774
|
+
}
|
|
775
|
+
if (this.nextPageBtn) {
|
|
776
|
+
this.nextPageBtn.disabled = page >= currentMax;
|
|
777
|
+
this.nextPageBtn.style.opacity = page >= currentMax ? "0.4" : "1";
|
|
778
|
+
}
|
|
631
779
|
}
|
|
632
780
|
update(actions) {
|
|
633
781
|
this.actions = actions;
|
|
@@ -650,8 +798,9 @@ var ToolbarController = class {
|
|
|
650
798
|
view: [],
|
|
651
799
|
actions: []
|
|
652
800
|
};
|
|
653
|
-
const
|
|
654
|
-
const
|
|
801
|
+
const enabledActions = this.actions.filter((a) => this.isActionEnabled(a));
|
|
802
|
+
const hasPageNav = enabledActions.some((a) => a.type === "page-nav");
|
|
803
|
+
const effectiveActions = hasPageNav ? enabledActions.filter((a) => a.id !== "page-prev" && a.id !== "page-next" && a.id !== "prev" && a.id !== "next") : enabledActions;
|
|
655
804
|
for (const action of effectiveActions) {
|
|
656
805
|
if (groups[action.group]) {
|
|
657
806
|
groups[action.group].push(action);
|
|
@@ -711,6 +860,13 @@ var ToolbarController = class {
|
|
|
711
860
|
action.execute("go", val);
|
|
712
861
|
});
|
|
713
862
|
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
863
|
+
const curVal = action.value ?? 1;
|
|
864
|
+
prevBtn.disabled = curVal <= 1;
|
|
865
|
+
prevBtn.style.opacity = curVal <= 1 ? "0.4" : "1";
|
|
866
|
+
nextBtn.disabled = curVal >= max;
|
|
867
|
+
nextBtn.style.opacity = curVal >= max ? "0.4" : "1";
|
|
868
|
+
this.prevPageBtn = prevBtn;
|
|
869
|
+
this.nextPageBtn = nextBtn;
|
|
714
870
|
this.pageInputEl = input;
|
|
715
871
|
this.pageLabelEl = label;
|
|
716
872
|
groupEl.appendChild(prevBtn);
|
|
@@ -766,25 +922,63 @@ var ToolbarController = class {
|
|
|
766
922
|
var ThumbnailPanel = class {
|
|
767
923
|
el;
|
|
768
924
|
panelEl;
|
|
925
|
+
listEl;
|
|
926
|
+
headerEl;
|
|
769
927
|
thumbnails = [];
|
|
770
928
|
onSelect;
|
|
929
|
+
onToggleCallback;
|
|
771
930
|
activeIndex = 0;
|
|
772
|
-
|
|
931
|
+
observer;
|
|
932
|
+
renderedIndices = /* @__PURE__ */ new Set();
|
|
933
|
+
constructor(container, onToggle) {
|
|
773
934
|
this.el = container;
|
|
935
|
+
this.onToggleCallback = onToggle;
|
|
774
936
|
this.panelEl = createElement("div", { className: "fp-thumbnail-panel hidden" });
|
|
937
|
+
this.panelEl.style.width = "0px";
|
|
938
|
+
this.panelEl.style.minWidth = "0px";
|
|
939
|
+
this.panelEl.style.opacity = "0";
|
|
940
|
+
this.headerEl = createElement("div", { className: "fp-thumbnail-header" });
|
|
941
|
+
const title = createElement("span", { className: "fp-thumbnail-title" }, "Pages");
|
|
942
|
+
const closeBtn = createElement("button", {
|
|
943
|
+
className: "fp-thumbnail-close-btn",
|
|
944
|
+
title: "Close Thumbnails",
|
|
945
|
+
type: "button"
|
|
946
|
+
});
|
|
947
|
+
closeBtn.innerHTML = ICON_CLOSE;
|
|
948
|
+
closeBtn.addEventListener("click", (e) => {
|
|
949
|
+
e.stopPropagation();
|
|
950
|
+
this.hide();
|
|
951
|
+
});
|
|
952
|
+
this.headerEl.appendChild(title);
|
|
953
|
+
this.headerEl.appendChild(closeBtn);
|
|
954
|
+
this.listEl = createElement("div", { className: "fp-thumbnail-list" });
|
|
955
|
+
this.panelEl.appendChild(this.headerEl);
|
|
956
|
+
this.panelEl.appendChild(this.listEl);
|
|
775
957
|
this.el.appendChild(this.panelEl);
|
|
776
958
|
}
|
|
959
|
+
isOpen() {
|
|
960
|
+
return !this.panelEl.classList.contains("hidden") && this.panelEl.style.width !== "0px";
|
|
961
|
+
}
|
|
777
962
|
update(thumbnails, onSelect) {
|
|
778
963
|
this.thumbnails = thumbnails;
|
|
779
964
|
this.onSelect = onSelect;
|
|
965
|
+
this.renderedIndices.clear();
|
|
966
|
+
const titleEl = this.headerEl.querySelector(".fp-thumbnail-title");
|
|
967
|
+
if (titleEl) {
|
|
968
|
+
titleEl.textContent = `Pages (${thumbnails.length})`;
|
|
969
|
+
}
|
|
780
970
|
this.render();
|
|
971
|
+
if (this.isOpen()) {
|
|
972
|
+
this.renderAllVisible();
|
|
973
|
+
}
|
|
781
974
|
}
|
|
782
975
|
setActive(index) {
|
|
783
976
|
this.activeIndex = index;
|
|
784
|
-
const items = this.
|
|
977
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
785
978
|
items.forEach((item, i) => {
|
|
786
979
|
if (i === index) {
|
|
787
980
|
item.classList.add("active");
|
|
981
|
+
item.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
788
982
|
} else {
|
|
789
983
|
item.classList.remove("active");
|
|
790
984
|
}
|
|
@@ -792,37 +986,102 @@ var ThumbnailPanel = class {
|
|
|
792
986
|
}
|
|
793
987
|
show() {
|
|
794
988
|
this.panelEl.classList.remove("hidden");
|
|
989
|
+
this.panelEl.style.width = "200px";
|
|
990
|
+
this.panelEl.style.minWidth = "200px";
|
|
991
|
+
this.panelEl.style.opacity = "1";
|
|
992
|
+
this.panelEl.style.display = "flex";
|
|
993
|
+
this.onToggleCallback?.(true);
|
|
994
|
+
this.renderAllVisible();
|
|
795
995
|
}
|
|
796
996
|
hide() {
|
|
797
997
|
this.panelEl.classList.add("hidden");
|
|
998
|
+
this.panelEl.style.width = "0px";
|
|
999
|
+
this.panelEl.style.minWidth = "0px";
|
|
1000
|
+
this.panelEl.style.opacity = "0";
|
|
1001
|
+
this.onToggleCallback?.(false);
|
|
798
1002
|
}
|
|
799
1003
|
toggle() {
|
|
800
|
-
this.
|
|
1004
|
+
if (this.isOpen()) {
|
|
1005
|
+
this.hide();
|
|
1006
|
+
} else {
|
|
1007
|
+
this.show();
|
|
1008
|
+
}
|
|
801
1009
|
}
|
|
802
1010
|
destroy() {
|
|
1011
|
+
if (this.observer) {
|
|
1012
|
+
this.observer.disconnect();
|
|
1013
|
+
this.observer = void 0;
|
|
1014
|
+
}
|
|
1015
|
+
this.renderedIndices.clear();
|
|
803
1016
|
this.el.innerHTML = "";
|
|
804
1017
|
}
|
|
805
|
-
|
|
806
|
-
this.
|
|
1018
|
+
renderAllVisible() {
|
|
1019
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
1020
|
+
items.forEach((item) => {
|
|
1021
|
+
const idx = parseInt(item.dataset.thumbIndex || "-1", 10);
|
|
1022
|
+
if (idx >= 0 && !this.renderedIndices.has(idx)) {
|
|
1023
|
+
this.renderThumbnailItem(idx, item);
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
renderThumbnailItem(idx, itemEl) {
|
|
1028
|
+
if (this.renderedIndices.has(idx)) return;
|
|
1029
|
+
this.renderedIndices.add(idx);
|
|
1030
|
+
const canvas = itemEl.querySelector("canvas");
|
|
1031
|
+
const thumb = this.thumbnails[idx];
|
|
1032
|
+
if (canvas && thumb) {
|
|
1033
|
+
Promise.resolve(thumb.render(canvas)).catch((err) => {
|
|
1034
|
+
console.warn(`[FilePreview] Error rendering thumbnail ${idx}:`, err);
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
render() {
|
|
1039
|
+
if (this.observer) {
|
|
1040
|
+
this.observer.disconnect();
|
|
1041
|
+
}
|
|
1042
|
+
this.listEl.innerHTML = "";
|
|
1043
|
+
const useObserver = typeof IntersectionObserver !== "undefined";
|
|
1044
|
+
if (useObserver) {
|
|
1045
|
+
this.observer = new IntersectionObserver(
|
|
1046
|
+
(entries) => {
|
|
1047
|
+
for (const entry of entries) {
|
|
1048
|
+
if (entry.isIntersecting) {
|
|
1049
|
+
const target = entry.target;
|
|
1050
|
+
const idx = parseInt(target.dataset.thumbIndex || "-1", 10);
|
|
1051
|
+
if (idx >= 0) {
|
|
1052
|
+
this.renderThumbnailItem(idx, target);
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
},
|
|
1057
|
+
{
|
|
1058
|
+
root: this.listEl,
|
|
1059
|
+
rootMargin: "120px 0px 120px 0px"
|
|
1060
|
+
}
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
807
1063
|
for (let i = 0; i < this.thumbnails.length; i++) {
|
|
808
1064
|
const thumb = this.thumbnails[i];
|
|
809
|
-
const itemEl = createElement("div", {
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1065
|
+
const itemEl = createElement("div", {
|
|
1066
|
+
className: "fp-thumbnail-item" + (i === this.activeIndex ? " active" : "")
|
|
1067
|
+
});
|
|
1068
|
+
itemEl.dataset.thumbIndex = i.toString();
|
|
813
1069
|
itemEl.addEventListener("click", () => {
|
|
814
1070
|
this.setActive(i);
|
|
815
1071
|
this.onSelect?.(i);
|
|
816
1072
|
});
|
|
817
|
-
const
|
|
818
|
-
const
|
|
819
|
-
|
|
1073
|
+
const canvasWrapper = createElement("div", { className: "fp-thumbnail-canvas-wrapper" });
|
|
1074
|
+
const canvas = createElement("canvas", { width: "130", height: "170" });
|
|
1075
|
+
canvasWrapper.appendChild(canvas);
|
|
1076
|
+
const label = createElement("span", { className: "fp-thumbnail-label" }, thumb.label || `Page ${i + 1}`);
|
|
1077
|
+
itemEl.appendChild(canvasWrapper);
|
|
820
1078
|
itemEl.appendChild(label);
|
|
821
|
-
this.
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
}
|
|
825
|
-
|
|
1079
|
+
this.listEl.appendChild(itemEl);
|
|
1080
|
+
if (this.observer) {
|
|
1081
|
+
this.observer.observe(itemEl);
|
|
1082
|
+
}
|
|
1083
|
+
if (i < 4) {
|
|
1084
|
+
this.renderThumbnailItem(i, itemEl);
|
|
826
1085
|
}
|
|
827
1086
|
}
|
|
828
1087
|
}
|
|
@@ -843,6 +1102,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
843
1102
|
currentOptions = {};
|
|
844
1103
|
resizeObserver = null;
|
|
845
1104
|
fullscreenHandler = null;
|
|
1105
|
+
titleBarEl = null;
|
|
846
1106
|
/**
|
|
847
1107
|
* Register a preview plugin.
|
|
848
1108
|
*/
|
|
@@ -879,6 +1139,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
879
1139
|
}
|
|
880
1140
|
this.currentBuffer = buffer.slice(0);
|
|
881
1141
|
this.currentMetadata = metadata;
|
|
1142
|
+
this.updateTitleBar(options, metadata);
|
|
882
1143
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
883
1144
|
const fileInfo = { metadata, buffer };
|
|
884
1145
|
const matchedPlugin = await this.findPlugin(fileInfo);
|
|
@@ -902,15 +1163,21 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
902
1163
|
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
903
1164
|
const total = payload.total ?? payload.totalPages;
|
|
904
1165
|
this.toolbar?.setPage(payload.page, total);
|
|
1166
|
+
this.thumbnailPanel?.setActive(payload.page - 1);
|
|
905
1167
|
}
|
|
906
1168
|
this.eventEmitter.emit(event, payload);
|
|
907
|
-
}
|
|
1169
|
+
},
|
|
1170
|
+
toggleThumbnails: () => this.toggleThumbnails()
|
|
908
1171
|
});
|
|
909
1172
|
this.activeInstance = instance;
|
|
910
1173
|
instance.openInSeparateWindow = () => this.openInSeparateWindow();
|
|
1174
|
+
instance.toggleThumbnails = () => this.toggleThumbnails();
|
|
911
1175
|
this.hideLoading();
|
|
912
1176
|
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
913
|
-
|
|
1177
|
+
const isToolbarVisible = options.showToolbar !== false && options.toolbar !== false;
|
|
1178
|
+
if (isToolbarVisible && this.toolbar) {
|
|
1179
|
+
const toolbarConfig = this.extractToolbarConfig(options);
|
|
1180
|
+
this.toolbar.setConfig(toolbarConfig);
|
|
914
1181
|
const actions = matchedPlugin.getToolbarActions(instance);
|
|
915
1182
|
const hasFullscreen = actions.some((a) => a.id === "fullscreen");
|
|
916
1183
|
if (!hasFullscreen && this.wrapperEl) {
|
|
@@ -960,6 +1227,12 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
960
1227
|
}
|
|
961
1228
|
});
|
|
962
1229
|
}
|
|
1230
|
+
const thumbAction = actions.find((a) => a.id === "thumbnails");
|
|
1231
|
+
if (thumbAction) {
|
|
1232
|
+
thumbAction.execute = () => {
|
|
1233
|
+
this.toggleThumbnails();
|
|
1234
|
+
};
|
|
1235
|
+
}
|
|
963
1236
|
this.toolbar.update(actions);
|
|
964
1237
|
this.toolbar.show();
|
|
965
1238
|
}
|
|
@@ -1044,7 +1317,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1044
1317
|
if (targetUrl) {
|
|
1045
1318
|
const newWin2 = window.open(targetUrl, "_blank");
|
|
1046
1319
|
if (!newWin2) {
|
|
1047
|
-
|
|
1320
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
1048
1321
|
return null;
|
|
1049
1322
|
}
|
|
1050
1323
|
return newWin2;
|
|
@@ -1052,7 +1325,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1052
1325
|
const title = (this.currentMetadata?.name || "Document Preview") + " - Full Preview";
|
|
1053
1326
|
const newWin = window.open("", "_blank");
|
|
1054
1327
|
if (!newWin) {
|
|
1055
|
-
|
|
1328
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
1056
1329
|
return null;
|
|
1057
1330
|
}
|
|
1058
1331
|
newWin.document.title = title;
|
|
@@ -1129,6 +1402,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1129
1402
|
this.currentBuffer = null;
|
|
1130
1403
|
this.currentMetadata = null;
|
|
1131
1404
|
this.currentContainer = null;
|
|
1405
|
+
this.titleBarEl = null;
|
|
1132
1406
|
}
|
|
1133
1407
|
/**
|
|
1134
1408
|
* Get the currently active preview instance.
|
|
@@ -1136,7 +1410,218 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1136
1410
|
getInstance() {
|
|
1137
1411
|
return this.activeInstance;
|
|
1138
1412
|
}
|
|
1413
|
+
// --- Toolbar Configuration & Feature Toggles ---
|
|
1414
|
+
/**
|
|
1415
|
+
* Configure toolbar features dynamically through options or methods.
|
|
1416
|
+
* e.g. viewer.setToolbarConfig({ zoomIn: false, print: false })
|
|
1417
|
+
*/
|
|
1418
|
+
setToolbarConfig(config) {
|
|
1419
|
+
this.toolbar?.setConfig(config);
|
|
1420
|
+
}
|
|
1421
|
+
/**
|
|
1422
|
+
* Get current toolbar configuration.
|
|
1423
|
+
*/
|
|
1424
|
+
getToolbarConfig() {
|
|
1425
|
+
return this.toolbar?.getConfig() ?? {};
|
|
1426
|
+
}
|
|
1427
|
+
/**
|
|
1428
|
+
* Hide a specific toolbar action by ID or alias (e.g. 'zoom-in', 'print', 'download').
|
|
1429
|
+
*/
|
|
1430
|
+
hideToolbarAction(actionId) {
|
|
1431
|
+
this.toolbar?.hideAction(actionId);
|
|
1432
|
+
}
|
|
1433
|
+
/**
|
|
1434
|
+
* Show a specific toolbar action by ID or alias.
|
|
1435
|
+
*/
|
|
1436
|
+
showToolbarAction(actionId) {
|
|
1437
|
+
this.toolbar?.showAction(actionId);
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* Enable a specific toolbar action button.
|
|
1441
|
+
*/
|
|
1442
|
+
enableToolbarAction(actionId) {
|
|
1443
|
+
this.toolbar?.enableAction(actionId);
|
|
1444
|
+
}
|
|
1445
|
+
/**
|
|
1446
|
+
* Disable a specific toolbar action button.
|
|
1447
|
+
*/
|
|
1448
|
+
disableToolbarAction(actionId) {
|
|
1449
|
+
this.toolbar?.disableAction(actionId);
|
|
1450
|
+
}
|
|
1451
|
+
// --- Programmatic Toolbar Action Methods ---
|
|
1452
|
+
/**
|
|
1453
|
+
* Fit document to page so it fills the frame width with minimal margins.
|
|
1454
|
+
*/
|
|
1455
|
+
fitToPage() {
|
|
1456
|
+
this.activeInstance?.fitToPage?.();
|
|
1457
|
+
}
|
|
1458
|
+
/**
|
|
1459
|
+
* Zoom in.
|
|
1460
|
+
*/
|
|
1461
|
+
zoomIn() {
|
|
1462
|
+
this.activeInstance?.zoomIn?.();
|
|
1463
|
+
}
|
|
1464
|
+
/**
|
|
1465
|
+
* Zoom out.
|
|
1466
|
+
*/
|
|
1467
|
+
zoomOut() {
|
|
1468
|
+
this.activeInstance?.zoomOut?.();
|
|
1469
|
+
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Set specific zoom level.
|
|
1472
|
+
*/
|
|
1473
|
+
setZoom(level) {
|
|
1474
|
+
this.activeInstance?.setZoom?.(level);
|
|
1475
|
+
}
|
|
1476
|
+
/**
|
|
1477
|
+
* Get current zoom level.
|
|
1478
|
+
*/
|
|
1479
|
+
getZoom() {
|
|
1480
|
+
return this.activeInstance?.getZoom?.() ?? 1;
|
|
1481
|
+
}
|
|
1482
|
+
/**
|
|
1483
|
+
* Rotate 90 degrees clockwise.
|
|
1484
|
+
*/
|
|
1485
|
+
rotateCW() {
|
|
1486
|
+
this.activeInstance?.rotateCW?.();
|
|
1487
|
+
}
|
|
1488
|
+
/**
|
|
1489
|
+
* Rotate 90 degrees counter-clockwise.
|
|
1490
|
+
*/
|
|
1491
|
+
rotateCCW() {
|
|
1492
|
+
this.activeInstance?.rotateCCW?.();
|
|
1493
|
+
}
|
|
1494
|
+
/**
|
|
1495
|
+
* Navigate to a specific page number.
|
|
1496
|
+
*/
|
|
1497
|
+
goToPage(page) {
|
|
1498
|
+
this.activeInstance?.goToPage?.(page);
|
|
1499
|
+
this.toolbar?.setPage(page);
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* Navigate to next page.
|
|
1503
|
+
*/
|
|
1504
|
+
nextPage() {
|
|
1505
|
+
const cur = this.getCurrentPage();
|
|
1506
|
+
const max = this.getPageCount();
|
|
1507
|
+
if (cur < max) {
|
|
1508
|
+
this.goToPage(cur + 1);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
/**
|
|
1512
|
+
* Navigate to previous page.
|
|
1513
|
+
*/
|
|
1514
|
+
prevPage() {
|
|
1515
|
+
const cur = this.getCurrentPage();
|
|
1516
|
+
if (cur > 1) {
|
|
1517
|
+
this.goToPage(cur - 1);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
/**
|
|
1521
|
+
* Get total page count.
|
|
1522
|
+
*/
|
|
1523
|
+
getPageCount() {
|
|
1524
|
+
return this.activeInstance?.getPageCount?.() ?? 1;
|
|
1525
|
+
}
|
|
1526
|
+
/**
|
|
1527
|
+
* Get current page number.
|
|
1528
|
+
*/
|
|
1529
|
+
getCurrentPage() {
|
|
1530
|
+
return this.activeInstance?.getCurrentPage?.() ?? 1;
|
|
1531
|
+
}
|
|
1532
|
+
/**
|
|
1533
|
+
* Download the current document.
|
|
1534
|
+
*/
|
|
1535
|
+
download() {
|
|
1536
|
+
this.activeInstance?.download?.();
|
|
1537
|
+
}
|
|
1538
|
+
/**
|
|
1539
|
+
* Print the current document.
|
|
1540
|
+
*/
|
|
1541
|
+
print() {
|
|
1542
|
+
this.activeInstance?.print?.();
|
|
1543
|
+
}
|
|
1544
|
+
/**
|
|
1545
|
+
* Toggle fullscreen mode.
|
|
1546
|
+
*/
|
|
1547
|
+
toggleFullscreen() {
|
|
1548
|
+
try {
|
|
1549
|
+
if (!document.fullscreenElement) {
|
|
1550
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
1551
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
1552
|
+
} else {
|
|
1553
|
+
document.exitFullscreen?.();
|
|
1554
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
1555
|
+
}
|
|
1556
|
+
} catch {
|
|
1557
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
1558
|
+
}
|
|
1559
|
+
setTimeout(() => {
|
|
1560
|
+
this.activeInstance?.fitToPage?.();
|
|
1561
|
+
}, 120);
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* Toggle thumbnails sidebar panel.
|
|
1565
|
+
*/
|
|
1566
|
+
toggleThumbnails() {
|
|
1567
|
+
if (!this.thumbnailPanel) return;
|
|
1568
|
+
this.thumbnailPanel.toggle();
|
|
1569
|
+
const isOpen = this.thumbnailPanel.isOpen();
|
|
1570
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1571
|
+
setTimeout(() => {
|
|
1572
|
+
this.activeInstance?.fitToPage?.();
|
|
1573
|
+
}, 260);
|
|
1574
|
+
}
|
|
1575
|
+
/**
|
|
1576
|
+
* Set whether to display the file name / title bar above the toolbar.
|
|
1577
|
+
*/
|
|
1578
|
+
setShowFileName(show) {
|
|
1579
|
+
if (this.currentOptions) {
|
|
1580
|
+
this.currentOptions.showFileName = show;
|
|
1581
|
+
}
|
|
1582
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1583
|
+
}
|
|
1584
|
+
/**
|
|
1585
|
+
* Set or override the displayed file name in the preview panel.
|
|
1586
|
+
*/
|
|
1587
|
+
setFileName(name) {
|
|
1588
|
+
if (this.currentOptions) {
|
|
1589
|
+
this.currentOptions.fileName = name;
|
|
1590
|
+
}
|
|
1591
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1592
|
+
}
|
|
1139
1593
|
// --- Private methods ---
|
|
1594
|
+
updateTitleBar(options, metadata) {
|
|
1595
|
+
if (!this.titleBarEl) return;
|
|
1596
|
+
const show = options?.showFileName !== false;
|
|
1597
|
+
if (!show) {
|
|
1598
|
+
this.titleBarEl.style.display = "none";
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
const name = options?.fileName || metadata?.name || this.currentMetadata?.name || "";
|
|
1602
|
+
if (!name) {
|
|
1603
|
+
this.titleBarEl.style.display = "none";
|
|
1604
|
+
return;
|
|
1605
|
+
}
|
|
1606
|
+
this.titleBarEl.style.display = "flex";
|
|
1607
|
+
const ext = metadata?.extension || (name.includes(".") ? "." + name.split(".").pop() : "");
|
|
1608
|
+
const badge = ext ? ext.replace(".", "").toUpperCase() : "";
|
|
1609
|
+
this.titleBarEl.innerHTML = `
|
|
1610
|
+
<div class="fp-titlebar-info">
|
|
1611
|
+
<span class="fp-titlebar-icon">\u{1F4C4}</span>
|
|
1612
|
+
<span class="fp-titlebar-name" title="${name}">${name}</span>
|
|
1613
|
+
${badge ? `<span class="fp-titlebar-badge">${badge}</span>` : ""}
|
|
1614
|
+
</div>
|
|
1615
|
+
`;
|
|
1616
|
+
}
|
|
1617
|
+
extractToolbarConfig(options) {
|
|
1618
|
+
if (!options) return {};
|
|
1619
|
+
const nested = typeof options.toolbar === "object" ? options.toolbar : {};
|
|
1620
|
+
return {
|
|
1621
|
+
...options,
|
|
1622
|
+
...nested
|
|
1623
|
+
};
|
|
1624
|
+
}
|
|
1140
1625
|
abort() {
|
|
1141
1626
|
if (this.abortController) {
|
|
1142
1627
|
this.abortController.abort();
|
|
@@ -1179,17 +1664,29 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1179
1664
|
bodyEl.className = "fp-body";
|
|
1180
1665
|
bodyEl.appendChild(thumbnailEl);
|
|
1181
1666
|
bodyEl.appendChild(this.contentEl);
|
|
1667
|
+
const titleBarEl = document.createElement("div");
|
|
1668
|
+
titleBarEl.className = "fp-titlebar";
|
|
1669
|
+
this.titleBarEl = titleBarEl;
|
|
1670
|
+
this.updateTitleBar(options, this.currentMetadata);
|
|
1182
1671
|
if (toolbarPos === "top") {
|
|
1672
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1183
1673
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1184
1674
|
this.wrapperEl.appendChild(bodyEl);
|
|
1185
1675
|
} else {
|
|
1676
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1186
1677
|
this.wrapperEl.appendChild(bodyEl);
|
|
1187
1678
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1188
1679
|
}
|
|
1189
1680
|
container.innerHTML = "";
|
|
1190
1681
|
container.appendChild(this.wrapperEl);
|
|
1191
|
-
|
|
1192
|
-
this.
|
|
1682
|
+
const initialToolbarConfig = this.extractToolbarConfig(options);
|
|
1683
|
+
this.toolbar = new ToolbarController(toolbarEl, initialToolbarConfig);
|
|
1684
|
+
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl, (isOpen) => {
|
|
1685
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1686
|
+
setTimeout(() => {
|
|
1687
|
+
this.activeInstance?.fitToPage?.();
|
|
1688
|
+
}, 260);
|
|
1689
|
+
});
|
|
1193
1690
|
this.setupKeyboardShortcuts();
|
|
1194
1691
|
this.setupDragAndDrop(container, options);
|
|
1195
1692
|
this.setupResizeAndFullscreenListeners();
|
|
@@ -1579,6 +2076,14 @@ var PdfPlugin = class {
|
|
|
1579
2076
|
group: "zoom",
|
|
1580
2077
|
execute: () => instance.fitToPage?.()
|
|
1581
2078
|
},
|
|
2079
|
+
{
|
|
2080
|
+
id: "fit-width",
|
|
2081
|
+
icon: "fit-width",
|
|
2082
|
+
label: "Fit to Width",
|
|
2083
|
+
type: "button",
|
|
2084
|
+
group: "zoom",
|
|
2085
|
+
execute: () => instance.fitToWidth?.()
|
|
2086
|
+
},
|
|
1582
2087
|
{
|
|
1583
2088
|
id: "rotate-cw",
|
|
1584
2089
|
icon: "rotate-cw",
|
|
@@ -1587,6 +2092,14 @@ var PdfPlugin = class {
|
|
|
1587
2092
|
group: "view",
|
|
1588
2093
|
execute: () => instance.rotateCW?.()
|
|
1589
2094
|
},
|
|
2095
|
+
{
|
|
2096
|
+
id: "rotate-ccw",
|
|
2097
|
+
icon: "rotate-ccw",
|
|
2098
|
+
label: "Rotate Counter-Clockwise",
|
|
2099
|
+
type: "button",
|
|
2100
|
+
group: "view",
|
|
2101
|
+
execute: () => instance.rotateCCW?.()
|
|
2102
|
+
},
|
|
1590
2103
|
{
|
|
1591
2104
|
id: "download",
|
|
1592
2105
|
icon: "download",
|
|
@@ -1618,12 +2131,13 @@ var PdfPlugin = class {
|
|
|
1618
2131
|
container.className = "fp-pdf-container";
|
|
1619
2132
|
container.style.width = "100%";
|
|
1620
2133
|
container.style.height = "100%";
|
|
1621
|
-
container.style.
|
|
2134
|
+
container.style.overflowX = "hidden";
|
|
2135
|
+
container.style.overflowY = "auto";
|
|
1622
2136
|
container.style.display = "flex";
|
|
1623
2137
|
container.style.flexDirection = "column";
|
|
1624
2138
|
container.style.alignItems = "center";
|
|
1625
2139
|
container.style.justifyContent = "flex-start";
|
|
1626
|
-
container.style.padding = "
|
|
2140
|
+
container.style.padding = "16px 8px";
|
|
1627
2141
|
container.style.backgroundColor = "#0f172a";
|
|
1628
2142
|
container.style.boxSizing = "border-box";
|
|
1629
2143
|
container.style.position = "relative";
|
|
@@ -1634,30 +2148,12 @@ var PdfPlugin = class {
|
|
|
1634
2148
|
pageCard.style.borderRadius = "4px";
|
|
1635
2149
|
pageCard.style.overflow = "hidden";
|
|
1636
2150
|
pageCard.style.lineHeight = "0";
|
|
1637
|
-
pageCard.style.transition = "transform 0.15s ease";
|
|
1638
2151
|
pageCard.style.position = "relative";
|
|
1639
2152
|
pageCard.style.flexShrink = "0";
|
|
2153
|
+
pageCard.style.transition = "box-shadow 0.2s ease";
|
|
1640
2154
|
let canvas = document.createElement("canvas");
|
|
1641
2155
|
pageCard.appendChild(canvas);
|
|
1642
2156
|
container.appendChild(pageCard);
|
|
1643
|
-
const indicator = document.createElement("div");
|
|
1644
|
-
indicator.className = "fp-pdf-page-indicator";
|
|
1645
|
-
indicator.style.position = "sticky";
|
|
1646
|
-
indicator.style.bottom = "16px";
|
|
1647
|
-
indicator.style.marginTop = "16px";
|
|
1648
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1649
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
1650
|
-
indicator.style.color = "#f8fafc";
|
|
1651
|
-
indicator.style.fontSize = "12px";
|
|
1652
|
-
indicator.style.fontWeight = "600";
|
|
1653
|
-
indicator.style.padding = "5px 14px";
|
|
1654
|
-
indicator.style.borderRadius = "20px";
|
|
1655
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1656
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1657
|
-
indicator.style.zIndex = "10";
|
|
1658
|
-
indicator.style.userSelect = "none";
|
|
1659
|
-
indicator.style.pointerEvents = "none";
|
|
1660
|
-
container.appendChild(indicator);
|
|
1661
2157
|
ctx.container.appendChild(container);
|
|
1662
2158
|
const standardFontsUrl = typeof window !== "undefined" && window.__PDF_STANDARD_FONTS_URL__ || "./standard_fonts/";
|
|
1663
2159
|
const cmapsUrl = typeof window !== "undefined" && window.__PDF_CMAPS_URL__ || "./cmaps/";
|
|
@@ -1673,8 +2169,9 @@ var PdfPlugin = class {
|
|
|
1673
2169
|
let currentPage = 1;
|
|
1674
2170
|
let zoomScale = 1;
|
|
1675
2171
|
let rotation = 0;
|
|
1676
|
-
let fitMode = "
|
|
2172
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
1677
2173
|
let currentRenderTask = null;
|
|
2174
|
+
let textLayerDiv = null;
|
|
1678
2175
|
const renderPage = async (pageNum) => {
|
|
1679
2176
|
if (currentRenderTask) {
|
|
1680
2177
|
try {
|
|
@@ -1686,30 +2183,37 @@ var PdfPlugin = class {
|
|
|
1686
2183
|
const newCanvas = document.createElement("canvas");
|
|
1687
2184
|
pageCard.replaceChild(newCanvas, canvas);
|
|
1688
2185
|
canvas = newCanvas;
|
|
2186
|
+
if (textLayerDiv) {
|
|
2187
|
+
textLayerDiv.remove();
|
|
2188
|
+
textLayerDiv = null;
|
|
2189
|
+
}
|
|
1689
2190
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1690
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1691
2191
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1692
2192
|
const page = await pdfDoc.getPage(currentPage);
|
|
1693
2193
|
const containerWidth = container.clientWidth || 900;
|
|
1694
2194
|
const containerHeight = container.clientHeight || 700;
|
|
1695
2195
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1696
|
-
const availWidth = Math.max(
|
|
1697
|
-
const availHeight = Math.max(
|
|
2196
|
+
const availWidth = Math.max(280, containerWidth - 36);
|
|
2197
|
+
const availHeight = Math.max(280, containerHeight - 32);
|
|
1698
2198
|
const scaleW = availWidth / unscaledVp.width;
|
|
1699
2199
|
const scaleH = availHeight / unscaledVp.height;
|
|
1700
2200
|
let fitScale;
|
|
1701
2201
|
if (fitMode === "page") {
|
|
1702
|
-
fitScale = Math.max(0.4, Math.min(scaleW, scaleH));
|
|
2202
|
+
fitScale = Math.max(0.2, Math.min(4, Math.min(scaleW, scaleH)));
|
|
1703
2203
|
} else {
|
|
1704
|
-
fitScale = Math.max(0.
|
|
2204
|
+
fitScale = Math.max(0.2, Math.min(4, scaleW));
|
|
1705
2205
|
}
|
|
1706
2206
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1707
2207
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1708
2208
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
2209
|
+
const displayWidth = Math.floor(viewport.width);
|
|
2210
|
+
const displayHeight = Math.floor(viewport.height);
|
|
1709
2211
|
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1710
2212
|
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1711
|
-
canvas.style.width = `${
|
|
1712
|
-
canvas.style.height = `${
|
|
2213
|
+
canvas.style.width = `${displayWidth}px`;
|
|
2214
|
+
canvas.style.height = `${displayHeight}px`;
|
|
2215
|
+
pageCard.style.width = `${displayWidth}px`;
|
|
2216
|
+
pageCard.style.height = `${displayHeight}px`;
|
|
1713
2217
|
const canvasCtx = canvas.getContext("2d");
|
|
1714
2218
|
if (!canvasCtx) return;
|
|
1715
2219
|
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
@@ -1723,9 +2227,31 @@ var PdfPlugin = class {
|
|
|
1723
2227
|
if (err?.name !== "RenderingCancelledException") {
|
|
1724
2228
|
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1725
2229
|
}
|
|
2230
|
+
return;
|
|
1726
2231
|
} finally {
|
|
1727
2232
|
currentRenderTask = null;
|
|
1728
2233
|
}
|
|
2234
|
+
try {
|
|
2235
|
+
textLayerDiv = document.createElement("div");
|
|
2236
|
+
textLayerDiv.className = "textLayer";
|
|
2237
|
+
textLayerDiv.style.width = `${displayWidth}px`;
|
|
2238
|
+
textLayerDiv.style.height = `${displayHeight}px`;
|
|
2239
|
+
textLayerDiv.style.position = "absolute";
|
|
2240
|
+
textLayerDiv.style.top = "0";
|
|
2241
|
+
textLayerDiv.style.left = "0";
|
|
2242
|
+
textLayerDiv.style.lineHeight = "1";
|
|
2243
|
+
pageCard.appendChild(textLayerDiv);
|
|
2244
|
+
if (pdfjsLib.TextLayer) {
|
|
2245
|
+
const textLayer = new pdfjsLib.TextLayer({
|
|
2246
|
+
textContentSource: page.streamTextContent(),
|
|
2247
|
+
container: textLayerDiv,
|
|
2248
|
+
viewport
|
|
2249
|
+
});
|
|
2250
|
+
await textLayer.render();
|
|
2251
|
+
}
|
|
2252
|
+
} catch (err) {
|
|
2253
|
+
console.debug("[PdfPlugin] TextLayer notice:", err);
|
|
2254
|
+
}
|
|
1729
2255
|
};
|
|
1730
2256
|
renderPage(1);
|
|
1731
2257
|
let resizeTimer = null;
|
|
@@ -1735,11 +2261,48 @@ var PdfPlugin = class {
|
|
|
1735
2261
|
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1736
2262
|
renderPage(currentPage);
|
|
1737
2263
|
}
|
|
1738
|
-
},
|
|
2264
|
+
}, 120);
|
|
1739
2265
|
});
|
|
1740
2266
|
resizeObserver.observe(container);
|
|
2267
|
+
const onWheel = (e) => {
|
|
2268
|
+
if (e.ctrlKey || e.metaKey) {
|
|
2269
|
+
e.preventDefault();
|
|
2270
|
+
const delta = e.deltaY > 0 ? -0.15 : 0.15;
|
|
2271
|
+
zoomScale = Math.max(0.25, Math.min(4, Math.round((zoomScale + delta) * 100) / 100));
|
|
2272
|
+
renderPage(currentPage);
|
|
2273
|
+
}
|
|
2274
|
+
};
|
|
2275
|
+
container.addEventListener("wheel", onWheel, { passive: false });
|
|
2276
|
+
const onKeyDown = (e) => {
|
|
2277
|
+
const tag = e.target?.tagName?.toLowerCase();
|
|
2278
|
+
if (tag === "input" || tag === "textarea" || tag === "select") return;
|
|
2279
|
+
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
2280
|
+
if (currentPage < totalPages) {
|
|
2281
|
+
e.preventDefault();
|
|
2282
|
+
container.scrollTop = 0;
|
|
2283
|
+
renderPage(currentPage + 1);
|
|
2284
|
+
}
|
|
2285
|
+
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
2286
|
+
if (currentPage > 1) {
|
|
2287
|
+
e.preventDefault();
|
|
2288
|
+
container.scrollTop = 0;
|
|
2289
|
+
renderPage(currentPage - 1);
|
|
2290
|
+
}
|
|
2291
|
+
} else if (e.key === "Home") {
|
|
2292
|
+
e.preventDefault();
|
|
2293
|
+
container.scrollTop = 0;
|
|
2294
|
+
renderPage(1);
|
|
2295
|
+
} else if (e.key === "End") {
|
|
2296
|
+
e.preventDefault();
|
|
2297
|
+
container.scrollTop = 0;
|
|
2298
|
+
renderPage(totalPages);
|
|
2299
|
+
}
|
|
2300
|
+
};
|
|
2301
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1741
2302
|
const cleanup = () => {
|
|
1742
2303
|
resizeObserver.disconnect();
|
|
2304
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
2305
|
+
container.removeEventListener("wheel", onWheel);
|
|
1743
2306
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1744
2307
|
if (currentRenderTask) {
|
|
1745
2308
|
try {
|
|
@@ -1758,22 +2321,26 @@ var PdfPlugin = class {
|
|
|
1758
2321
|
const instance = {
|
|
1759
2322
|
destroy: cleanup,
|
|
1760
2323
|
zoomIn: () => {
|
|
1761
|
-
zoomScale = Math.min(
|
|
2324
|
+
zoomScale = Math.min(4, Math.round((zoomScale + 0.2) * 10) / 10);
|
|
1762
2325
|
renderPage(currentPage);
|
|
1763
2326
|
},
|
|
1764
2327
|
zoomOut: () => {
|
|
1765
|
-
zoomScale = Math.max(0.
|
|
2328
|
+
zoomScale = Math.max(0.25, Math.round((zoomScale - 0.2) * 10) / 10);
|
|
1766
2329
|
renderPage(currentPage);
|
|
1767
2330
|
},
|
|
1768
2331
|
getZoom: () => zoomScale,
|
|
1769
2332
|
setZoom: (level) => {
|
|
1770
|
-
zoomScale = Math.max(0.
|
|
2333
|
+
zoomScale = Math.max(0.25, Math.min(4, level));
|
|
1771
2334
|
renderPage(currentPage);
|
|
1772
2335
|
},
|
|
1773
2336
|
fitToPage: () => {
|
|
1774
|
-
fitMode =
|
|
2337
|
+
fitMode = "page";
|
|
2338
|
+
zoomScale = 1;
|
|
2339
|
+
renderPage(currentPage);
|
|
2340
|
+
},
|
|
2341
|
+
fitToWidth: () => {
|
|
2342
|
+
fitMode = "width";
|
|
1775
2343
|
zoomScale = 1;
|
|
1776
|
-
rotation = 0;
|
|
1777
2344
|
renderPage(currentPage);
|
|
1778
2345
|
},
|
|
1779
2346
|
rotateCW: () => {
|
|
@@ -1791,6 +2358,9 @@ var PdfPlugin = class {
|
|
|
1791
2358
|
container.scrollTop = 0;
|
|
1792
2359
|
renderPage(page);
|
|
1793
2360
|
},
|
|
2361
|
+
toggleThumbnails: () => {
|
|
2362
|
+
ctx?.toggleThumbnails?.();
|
|
2363
|
+
},
|
|
1794
2364
|
download: () => {
|
|
1795
2365
|
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1796
2366
|
const url = URL.createObjectURL(blob);
|
|
@@ -1824,7 +2394,7 @@ var PdfPlugin = class {
|
|
|
1824
2394
|
},
|
|
1825
2395
|
getThumbnails: async () => {
|
|
1826
2396
|
const thumbnails = [];
|
|
1827
|
-
const count =
|
|
2397
|
+
const count = totalPages;
|
|
1828
2398
|
for (let i = 1; i <= count; i++) {
|
|
1829
2399
|
thumbnails.push({
|
|
1830
2400
|
index: i,
|
|
@@ -1832,9 +2402,10 @@ var PdfPlugin = class {
|
|
|
1832
2402
|
render: async (thumbCanvas) => {
|
|
1833
2403
|
try {
|
|
1834
2404
|
const p = await pdfDoc.getPage(i);
|
|
1835
|
-
const baseVp = p.getViewport({ scale: 1 });
|
|
1836
|
-
const
|
|
1837
|
-
const
|
|
2405
|
+
const baseVp = p.getViewport({ scale: 1, rotation });
|
|
2406
|
+
const targetW = thumbCanvas.width || 130;
|
|
2407
|
+
const thumbScale = targetW / baseVp.width;
|
|
2408
|
+
const thumbVp = p.getViewport({ scale: thumbScale, rotation });
|
|
1838
2409
|
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1839
2410
|
const tCtx = thumbCanvas.getContext("2d");
|
|
1840
2411
|
if (tCtx) {
|
|
@@ -2178,28 +2749,26 @@ var DocxPlugin = class {
|
|
|
2178
2749
|
getToolbarActions(instance) {
|
|
2179
2750
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2180
2751
|
const actions = [];
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
if (
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
instance.goToPage?.(page);
|
|
2199
|
-
}
|
|
2752
|
+
actions.push({
|
|
2753
|
+
id: "page-nav",
|
|
2754
|
+
icon: "",
|
|
2755
|
+
label: "Page Navigation",
|
|
2756
|
+
type: "page-nav",
|
|
2757
|
+
group: "navigation",
|
|
2758
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2759
|
+
max: totalPages,
|
|
2760
|
+
execute: (action, page) => {
|
|
2761
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2762
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2763
|
+
if (action === "prev") {
|
|
2764
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2765
|
+
} else if (action === "next") {
|
|
2766
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2767
|
+
} else if (typeof page === "number") {
|
|
2768
|
+
instance.goToPage?.(page);
|
|
2200
2769
|
}
|
|
2201
|
-
}
|
|
2202
|
-
}
|
|
2770
|
+
}
|
|
2771
|
+
});
|
|
2203
2772
|
actions.push(
|
|
2204
2773
|
{
|
|
2205
2774
|
id: "zoom-out",
|
|
@@ -2265,11 +2834,17 @@ var DocxPlugin = class {
|
|
|
2265
2834
|
wrapper.className = "fp-docx-wrapper";
|
|
2266
2835
|
wrapper.style.transformOrigin = "top center";
|
|
2267
2836
|
wrapper.style.transition = "transform 0.2s ease";
|
|
2268
|
-
wrapper.style.padding = "
|
|
2269
|
-
wrapper.style.maxWidth = "
|
|
2837
|
+
wrapper.style.padding = "0";
|
|
2838
|
+
wrapper.style.maxWidth = "none";
|
|
2839
|
+
wrapper.style.width = "816px";
|
|
2270
2840
|
wrapper.style.margin = "0 auto";
|
|
2841
|
+
wrapper.style.display = "flex";
|
|
2842
|
+
wrapper.style.flexDirection = "column";
|
|
2843
|
+
wrapper.style.alignItems = "center";
|
|
2271
2844
|
wrapper.style.boxSizing = "border-box";
|
|
2272
|
-
ctx.container.style.
|
|
2845
|
+
ctx.container.style.overflowX = "hidden";
|
|
2846
|
+
ctx.container.style.overflowY = "auto";
|
|
2847
|
+
ctx.container.style.padding = "16px 8px";
|
|
2273
2848
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
2274
2849
|
ctx.container.appendChild(wrapper);
|
|
2275
2850
|
const styleOverride = document.createElement("style");
|
|
@@ -2443,39 +3018,13 @@ var DocxPlugin = class {
|
|
|
2443
3018
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2444
3019
|
const totalPages = Math.max(1, pageElements.length);
|
|
2445
3020
|
let currentPage = 1;
|
|
2446
|
-
let indicator = null;
|
|
2447
|
-
if (totalPages > 1) {
|
|
2448
|
-
indicator = document.createElement("div");
|
|
2449
|
-
indicator.className = "fp-docx-page-indicator";
|
|
2450
|
-
indicator.style.position = "sticky";
|
|
2451
|
-
indicator.style.bottom = "16px";
|
|
2452
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2453
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
2454
|
-
indicator.style.color = "#f8fafc";
|
|
2455
|
-
indicator.style.fontSize = "12px";
|
|
2456
|
-
indicator.style.fontWeight = "600";
|
|
2457
|
-
indicator.style.padding = "5px 14px";
|
|
2458
|
-
indicator.style.borderRadius = "20px";
|
|
2459
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2460
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2461
|
-
indicator.style.zIndex = "10";
|
|
2462
|
-
indicator.style.userSelect = "none";
|
|
2463
|
-
indicator.style.pointerEvents = "none";
|
|
2464
|
-
indicator.style.textAlign = "center";
|
|
2465
|
-
indicator.style.width = "fit-content";
|
|
2466
|
-
indicator.style.margin = "16px auto 0";
|
|
2467
|
-
ctx.container.appendChild(indicator);
|
|
2468
|
-
}
|
|
2469
3021
|
const showPage = (pageNum) => {
|
|
2470
3022
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2471
3023
|
if (pageElements.length > 1) {
|
|
2472
3024
|
pageElements.forEach((sec, idx) => {
|
|
2473
|
-
sec.style.display = idx + 1 === currentPage ? "
|
|
3025
|
+
sec.style.display = idx + 1 === currentPage ? "" : "none";
|
|
2474
3026
|
});
|
|
2475
3027
|
}
|
|
2476
|
-
if (indicator) {
|
|
2477
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2478
|
-
}
|
|
2479
3028
|
ctx.container.scrollTop = 0;
|
|
2480
3029
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2481
3030
|
};
|
|
@@ -2484,31 +3033,46 @@ var DocxPlugin = class {
|
|
|
2484
3033
|
}
|
|
2485
3034
|
scale = 1;
|
|
2486
3035
|
let rotation = 0;
|
|
2487
|
-
let fitMode = "
|
|
2488
|
-
|
|
2489
|
-
|
|
3036
|
+
let fitMode = "page";
|
|
3037
|
+
let isUserZoomed = false;
|
|
3038
|
+
const calculateFitScale = (_mode = fitMode) => {
|
|
3039
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
2490
3040
|
const elW = activeEl.offsetWidth || 816;
|
|
2491
|
-
const
|
|
2492
|
-
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
2493
|
-
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
3041
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
2494
3042
|
const sW = availW / elW;
|
|
2495
|
-
|
|
2496
|
-
if (mode === "page") {
|
|
2497
|
-
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
2498
|
-
}
|
|
2499
|
-
return Math.max(0.65, Math.min(1.05, sW));
|
|
3043
|
+
return Math.max(0.35, Math.min(3, sW));
|
|
2500
3044
|
};
|
|
2501
3045
|
const applyTransform = () => {
|
|
2502
3046
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2503
3047
|
wrapper.style.transformOrigin = "top center";
|
|
3048
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
3049
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
3050
|
+
if (scale > 1) {
|
|
3051
|
+
wrapper.style.marginBottom = `${Math.round(elH * scale - elH + 32)}px`;
|
|
3052
|
+
} else {
|
|
3053
|
+
wrapper.style.marginBottom = "32px";
|
|
3054
|
+
}
|
|
2504
3055
|
};
|
|
3056
|
+
let resizeObserver = null;
|
|
3057
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
3058
|
+
resizeObserver = new ResizeObserver(() => {
|
|
3059
|
+
if (!isUserZoomed) {
|
|
3060
|
+
const newFit = calculateFitScale("page");
|
|
3061
|
+
if (Math.abs(scale - newFit) > 0.015) {
|
|
3062
|
+
scale = newFit;
|
|
3063
|
+
applyTransform();
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
});
|
|
3067
|
+
resizeObserver.observe(ctx.container);
|
|
3068
|
+
}
|
|
2505
3069
|
setTimeout(() => {
|
|
2506
|
-
|
|
2507
|
-
scale = calculateFitScale("width");
|
|
3070
|
+
scale = calculateFitScale("page");
|
|
2508
3071
|
applyTransform();
|
|
2509
|
-
},
|
|
3072
|
+
}, 40);
|
|
2510
3073
|
const cleanup = () => {
|
|
2511
|
-
|
|
3074
|
+
resizeObserver?.disconnect();
|
|
3075
|
+
resizeObserver = null;
|
|
2512
3076
|
for (const url of createdBlobUrls) {
|
|
2513
3077
|
URL.revokeObjectURL(url);
|
|
2514
3078
|
}
|
|
@@ -2525,21 +3089,24 @@ var DocxPlugin = class {
|
|
|
2525
3089
|
showPage(page);
|
|
2526
3090
|
},
|
|
2527
3091
|
zoomIn: () => {
|
|
2528
|
-
|
|
3092
|
+
isUserZoomed = true;
|
|
3093
|
+
scale = Math.min(3.5, scale + 0.15);
|
|
2529
3094
|
applyTransform();
|
|
2530
3095
|
},
|
|
2531
3096
|
zoomOut: () => {
|
|
3097
|
+
isUserZoomed = true;
|
|
2532
3098
|
scale = Math.max(0.2, scale - 0.15);
|
|
2533
3099
|
applyTransform();
|
|
2534
3100
|
},
|
|
2535
3101
|
getZoom: () => scale,
|
|
2536
3102
|
setZoom: (level) => {
|
|
3103
|
+
isUserZoomed = true;
|
|
2537
3104
|
scale = level;
|
|
2538
3105
|
applyTransform();
|
|
2539
3106
|
},
|
|
2540
3107
|
fitToPage: () => {
|
|
2541
|
-
|
|
2542
|
-
scale = calculateFitScale(
|
|
3108
|
+
isUserZoomed = false;
|
|
3109
|
+
scale = calculateFitScale("page");
|
|
2543
3110
|
rotation = 0;
|
|
2544
3111
|
applyTransform();
|
|
2545
3112
|
},
|
|
@@ -2929,7 +3496,7 @@ var ExcelPlugin = class {
|
|
|
2929
3496
|
"application/vnd.ms-excel.template.macroEnabled.12",
|
|
2930
3497
|
"application/vnd.oasis.opendocument.spreadsheet"
|
|
2931
3498
|
];
|
|
2932
|
-
weight =
|
|
3499
|
+
weight = 85;
|
|
2933
3500
|
supports(file) {
|
|
2934
3501
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2935
3502
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
@@ -2941,6 +3508,14 @@ var ExcelPlugin = class {
|
|
|
2941
3508
|
getToolbarActions(instance) {
|
|
2942
3509
|
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2943
3510
|
const actions = [];
|
|
3511
|
+
actions.push({
|
|
3512
|
+
id: "thumbnails",
|
|
3513
|
+
icon: "thumbnails",
|
|
3514
|
+
label: "Sheet Thumbnails",
|
|
3515
|
+
type: "button",
|
|
3516
|
+
group: "navigation",
|
|
3517
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3518
|
+
});
|
|
2944
3519
|
if (totalSheets > 1) {
|
|
2945
3520
|
actions.push({
|
|
2946
3521
|
id: "page-nav",
|
|
@@ -2984,26 +3559,6 @@ var ExcelPlugin = class {
|
|
|
2984
3559
|
instance.zoomIn?.();
|
|
2985
3560
|
}
|
|
2986
3561
|
},
|
|
2987
|
-
{
|
|
2988
|
-
id: "fit-page",
|
|
2989
|
-
icon: "fit-page",
|
|
2990
|
-
label: "Fit to View",
|
|
2991
|
-
type: "button",
|
|
2992
|
-
group: "zoom",
|
|
2993
|
-
execute: () => {
|
|
2994
|
-
instance.fitToPage?.();
|
|
2995
|
-
}
|
|
2996
|
-
},
|
|
2997
|
-
{
|
|
2998
|
-
id: "rotate-cw",
|
|
2999
|
-
icon: "rotate-cw",
|
|
3000
|
-
label: "Rotate",
|
|
3001
|
-
type: "button",
|
|
3002
|
-
group: "view",
|
|
3003
|
-
execute: () => {
|
|
3004
|
-
instance.rotateCW?.();
|
|
3005
|
-
}
|
|
3006
|
-
},
|
|
3007
3562
|
{
|
|
3008
3563
|
id: "download",
|
|
3009
3564
|
icon: "download",
|
|
@@ -3023,6 +3578,16 @@ var ExcelPlugin = class {
|
|
|
3023
3578
|
execute: () => {
|
|
3024
3579
|
instance.print?.();
|
|
3025
3580
|
}
|
|
3581
|
+
},
|
|
3582
|
+
{
|
|
3583
|
+
id: "open-window",
|
|
3584
|
+
icon: "open-window",
|
|
3585
|
+
label: "Open in Separate Full Window",
|
|
3586
|
+
type: "button",
|
|
3587
|
+
group: "actions",
|
|
3588
|
+
execute: () => {
|
|
3589
|
+
instance.openInSeparateWindow?.();
|
|
3590
|
+
}
|
|
3026
3591
|
}
|
|
3027
3592
|
);
|
|
3028
3593
|
return actions;
|
|
@@ -3054,12 +3619,11 @@ var ExcelPlugin = class {
|
|
|
3054
3619
|
container.appendChild(tabsArea);
|
|
3055
3620
|
ctx.container.appendChild(container);
|
|
3056
3621
|
let scale = 1;
|
|
3057
|
-
let rotation = 0;
|
|
3058
3622
|
let currentSheetIndex = 1;
|
|
3059
3623
|
let sheetNames = [];
|
|
3060
3624
|
let wb = null;
|
|
3061
3625
|
const applyTransform = () => {
|
|
3062
|
-
contentArea.style.transform = `scale(${scale})
|
|
3626
|
+
contentArea.style.transform = `scale(${scale})`;
|
|
3063
3627
|
contentArea.style.transformOrigin = "top left";
|
|
3064
3628
|
};
|
|
3065
3629
|
const calculateFitScale = () => {
|
|
@@ -3067,7 +3631,7 @@ var ExcelPlugin = class {
|
|
|
3067
3631
|
if (!table) return 1;
|
|
3068
3632
|
const availW = Math.max(280, container.clientWidth - 48);
|
|
3069
3633
|
const tW = table.offsetWidth || 800;
|
|
3070
|
-
return Math.max(0.
|
|
3634
|
+
return Math.max(0.4, Math.min(1, availW / tW));
|
|
3071
3635
|
};
|
|
3072
3636
|
try {
|
|
3073
3637
|
wb = XLSX.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
|
|
@@ -3122,7 +3686,16 @@ var ExcelPlugin = class {
|
|
|
3122
3686
|
}
|
|
3123
3687
|
});
|
|
3124
3688
|
ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
|
|
3689
|
+
requestAnimationFrame(() => {
|
|
3690
|
+
scale = calculateFitScale();
|
|
3691
|
+
applyTransform();
|
|
3692
|
+
});
|
|
3125
3693
|
};
|
|
3694
|
+
const ro = new ResizeObserver(() => {
|
|
3695
|
+
scale = calculateFitScale();
|
|
3696
|
+
applyTransform();
|
|
3697
|
+
});
|
|
3698
|
+
ro.observe(container);
|
|
3126
3699
|
if (sheetNames.length > 0) {
|
|
3127
3700
|
sheetNames.forEach((name, idx) => {
|
|
3128
3701
|
const btn = document.createElement("button");
|
|
@@ -3149,6 +3722,7 @@ var ExcelPlugin = class {
|
|
|
3149
3722
|
`;
|
|
3150
3723
|
}
|
|
3151
3724
|
const cleanup = () => {
|
|
3725
|
+
ro.disconnect();
|
|
3152
3726
|
container.remove();
|
|
3153
3727
|
ctx.container.innerHTML = "";
|
|
3154
3728
|
};
|
|
@@ -3170,16 +3744,11 @@ var ExcelPlugin = class {
|
|
|
3170
3744
|
},
|
|
3171
3745
|
fitToPage: () => {
|
|
3172
3746
|
scale = calculateFitScale();
|
|
3173
|
-
rotation = 0;
|
|
3174
3747
|
applyTransform();
|
|
3175
3748
|
},
|
|
3176
3749
|
rotateCW: () => {
|
|
3177
|
-
rotation = (rotation + 90) % 360;
|
|
3178
|
-
applyTransform();
|
|
3179
3750
|
},
|
|
3180
3751
|
rotateCCW: () => {
|
|
3181
|
-
rotation = (rotation - 90 + 360) % 360;
|
|
3182
|
-
applyTransform();
|
|
3183
3752
|
},
|
|
3184
3753
|
goToPage: (page) => {
|
|
3185
3754
|
if (page > 0 && page <= sheetNames.length) {
|
|
@@ -3188,6 +3757,63 @@ var ExcelPlugin = class {
|
|
|
3188
3757
|
},
|
|
3189
3758
|
getPageCount: () => sheetNames.length,
|
|
3190
3759
|
getCurrentPage: () => currentSheetIndex,
|
|
3760
|
+
getThumbnails: () => {
|
|
3761
|
+
return sheetNames.map((name, idx) => ({
|
|
3762
|
+
index: idx,
|
|
3763
|
+
label: name,
|
|
3764
|
+
render: async (canvas) => {
|
|
3765
|
+
canvas.width = 140;
|
|
3766
|
+
canvas.height = 100;
|
|
3767
|
+
const c = canvas.getContext("2d");
|
|
3768
|
+
if (!c) return;
|
|
3769
|
+
c.fillStyle = "#ffffff";
|
|
3770
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
3771
|
+
c.fillStyle = "#107c41";
|
|
3772
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
3773
|
+
c.fillStyle = "#ffffff";
|
|
3774
|
+
c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
3775
|
+
c.fillText(`\u{1F4CA} ${name.slice(0, 16)}`, 6, 11);
|
|
3776
|
+
const startY = 17;
|
|
3777
|
+
const rowH = 13;
|
|
3778
|
+
const colW = 30;
|
|
3779
|
+
const colHeaders = ["A", "B", "C", "D"];
|
|
3780
|
+
c.fillStyle = "#f1f5f9";
|
|
3781
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
3782
|
+
c.strokeStyle = "#cbd5e1";
|
|
3783
|
+
c.lineWidth = 0.8;
|
|
3784
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
3785
|
+
c.fillStyle = "#64748b";
|
|
3786
|
+
c.font = "bold 7px sans-serif";
|
|
3787
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3788
|
+
c.fillText(colHeaders[ci], 14 + ci * colW, startY + 9);
|
|
3789
|
+
}
|
|
3790
|
+
const ws = wb?.Sheets[name];
|
|
3791
|
+
for (let ri = 1; ri <= 5; ri++) {
|
|
3792
|
+
const y = startY + ri * rowH;
|
|
3793
|
+
if (y > canvas.height - 2) break;
|
|
3794
|
+
c.fillStyle = "#f8fafc";
|
|
3795
|
+
c.fillRect(0, y, 12, rowH);
|
|
3796
|
+
c.fillStyle = "#94a3b8";
|
|
3797
|
+
c.font = "6px sans-serif";
|
|
3798
|
+
c.fillText(String(ri), 3, y + 9);
|
|
3799
|
+
c.strokeStyle = "#e2e8f0";
|
|
3800
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
3801
|
+
c.fillStyle = "#334155";
|
|
3802
|
+
c.font = "6px sans-serif";
|
|
3803
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3804
|
+
const cellRef = `${colHeaders[ci]}${ri}`;
|
|
3805
|
+
const cellVal = ws?.[cellRef]?.w || ws?.[cellRef]?.v;
|
|
3806
|
+
if (cellVal !== void 0) {
|
|
3807
|
+
c.fillText(String(cellVal).slice(0, 6), 14 + ci * colW, y + 9);
|
|
3808
|
+
}
|
|
3809
|
+
}
|
|
3810
|
+
}
|
|
3811
|
+
c.strokeStyle = "#cbd5e1";
|
|
3812
|
+
c.lineWidth = 1;
|
|
3813
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
3814
|
+
}
|
|
3815
|
+
}));
|
|
3816
|
+
},
|
|
3191
3817
|
download: () => {
|
|
3192
3818
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
3193
3819
|
const url = URL.createObjectURL(blob);
|
|
@@ -3220,7 +3846,16 @@ var CsvPlugin = class {
|
|
|
3220
3846
|
return ext === ".csv" || ext === ".tsv" || mime === "text/csv" || mime === "text/tab-separated-values";
|
|
3221
3847
|
}
|
|
3222
3848
|
getToolbarActions(instance) {
|
|
3223
|
-
|
|
3849
|
+
const actions = [];
|
|
3850
|
+
actions.push({
|
|
3851
|
+
id: "thumbnails",
|
|
3852
|
+
icon: "thumbnails",
|
|
3853
|
+
label: "Sheet Thumbnails",
|
|
3854
|
+
type: "button",
|
|
3855
|
+
group: "navigation",
|
|
3856
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3857
|
+
});
|
|
3858
|
+
actions.push(
|
|
3224
3859
|
{
|
|
3225
3860
|
id: "zoom-out",
|
|
3226
3861
|
icon: "zoom-out",
|
|
@@ -3260,8 +3895,19 @@ var CsvPlugin = class {
|
|
|
3260
3895
|
execute: () => {
|
|
3261
3896
|
instance.print?.();
|
|
3262
3897
|
}
|
|
3898
|
+
},
|
|
3899
|
+
{
|
|
3900
|
+
id: "open-window",
|
|
3901
|
+
icon: "open-window",
|
|
3902
|
+
label: "Open in Separate Full Window",
|
|
3903
|
+
type: "button",
|
|
3904
|
+
group: "actions",
|
|
3905
|
+
execute: () => {
|
|
3906
|
+
instance.openInSeparateWindow?.();
|
|
3907
|
+
}
|
|
3263
3908
|
}
|
|
3264
|
-
|
|
3909
|
+
);
|
|
3910
|
+
return actions;
|
|
3265
3911
|
}
|
|
3266
3912
|
async render(ctx) {
|
|
3267
3913
|
const decoder = new TextDecoder("utf-8");
|
|
@@ -3272,57 +3918,156 @@ var CsvPlugin = class {
|
|
|
3272
3918
|
container.style.overflow = "auto";
|
|
3273
3919
|
container.style.padding = "16px";
|
|
3274
3920
|
container.style.boxSizing = "border-box";
|
|
3275
|
-
|
|
3921
|
+
const tableWrapper = document.createElement("div");
|
|
3922
|
+
tableWrapper.style.transformOrigin = "top left";
|
|
3923
|
+
const delimiter = ctx.metadata.extension === ".tsv" ? " " : ",";
|
|
3924
|
+
const allLines = text.split(/\r?\n/).filter((r) => r.trim().length > 0);
|
|
3925
|
+
const headerLine = allLines[0] || "";
|
|
3926
|
+
const headerCells = headerLine.split(delimiter);
|
|
3927
|
+
const dataLines = allLines.slice(1);
|
|
3276
3928
|
const table = document.createElement("table");
|
|
3277
3929
|
table.style.borderCollapse = "collapse";
|
|
3278
|
-
table.style.
|
|
3279
|
-
table.style.fontFamily = "monospace
|
|
3930
|
+
table.style.minWidth = "100%";
|
|
3931
|
+
table.style.fontFamily = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace';
|
|
3280
3932
|
table.style.fontSize = "13px";
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3933
|
+
table.style.background = "#ffffff";
|
|
3934
|
+
table.style.border = "1px solid #d0d7de";
|
|
3935
|
+
const headerTr = document.createElement("tr");
|
|
3936
|
+
headerCells.forEach((cell) => {
|
|
3937
|
+
const th = document.createElement("th");
|
|
3938
|
+
th.textContent = cell.trim();
|
|
3939
|
+
th.style.border = "1px solid #d0d7de";
|
|
3940
|
+
th.style.padding = "8px 12px";
|
|
3941
|
+
th.style.backgroundColor = "#f6f8fa";
|
|
3942
|
+
th.style.fontWeight = "600";
|
|
3943
|
+
th.style.whiteSpace = "nowrap";
|
|
3944
|
+
headerTr.appendChild(th);
|
|
3945
|
+
});
|
|
3946
|
+
table.appendChild(headerTr);
|
|
3947
|
+
dataLines.forEach((row, idx) => {
|
|
3285
3948
|
const tr = document.createElement("tr");
|
|
3949
|
+
if (idx % 2 === 1) tr.style.backgroundColor = "#f8fafc";
|
|
3286
3950
|
const cells = row.split(delimiter);
|
|
3287
3951
|
cells.forEach((cell) => {
|
|
3288
|
-
const td = document.createElement(
|
|
3952
|
+
const td = document.createElement("td");
|
|
3289
3953
|
td.textContent = cell.trim();
|
|
3290
3954
|
td.style.border = "1px solid #d0d7de";
|
|
3291
3955
|
td.style.padding = "6px 12px";
|
|
3292
|
-
|
|
3293
|
-
td.style.backgroundColor = "#f6f8fa";
|
|
3294
|
-
td.style.fontWeight = "bold";
|
|
3295
|
-
}
|
|
3956
|
+
td.style.whiteSpace = "nowrap";
|
|
3296
3957
|
tr.appendChild(td);
|
|
3297
3958
|
});
|
|
3298
3959
|
table.appendChild(tr);
|
|
3299
3960
|
});
|
|
3300
|
-
|
|
3961
|
+
tableWrapper.appendChild(table);
|
|
3962
|
+
container.appendChild(tableWrapper);
|
|
3301
3963
|
ctx.container.appendChild(container);
|
|
3302
3964
|
let scale = 1;
|
|
3965
|
+
const calculateFitScale = () => {
|
|
3966
|
+
const availW = Math.max(280, container.clientWidth - 48);
|
|
3967
|
+
const tW = table.offsetWidth || 800;
|
|
3968
|
+
return Math.max(0.4, Math.min(1, availW / tW));
|
|
3969
|
+
};
|
|
3970
|
+
const applyScale = () => {
|
|
3971
|
+
tableWrapper.style.transform = `scale(${scale})`;
|
|
3972
|
+
};
|
|
3973
|
+
requestAnimationFrame(() => {
|
|
3974
|
+
scale = calculateFitScale();
|
|
3975
|
+
applyScale();
|
|
3976
|
+
});
|
|
3977
|
+
const ro = new ResizeObserver(() => {
|
|
3978
|
+
scale = calculateFitScale();
|
|
3979
|
+
applyScale();
|
|
3980
|
+
});
|
|
3981
|
+
ro.observe(container);
|
|
3303
3982
|
const cleanup = () => {
|
|
3983
|
+
ro.disconnect();
|
|
3304
3984
|
container.remove();
|
|
3305
3985
|
ctx.container.innerHTML = "";
|
|
3306
3986
|
};
|
|
3307
3987
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3308
3988
|
return {
|
|
3309
3989
|
destroy: cleanup,
|
|
3990
|
+
getPageCount: () => 1,
|
|
3991
|
+
getCurrentPage: () => 1,
|
|
3992
|
+
goToPage: () => {
|
|
3993
|
+
},
|
|
3994
|
+
getThumbnails: () => {
|
|
3995
|
+
const sheetName = ctx.metadata.name?.replace(/\.[^/.]+$/, "") || "Sheet1";
|
|
3996
|
+
return [{
|
|
3997
|
+
index: 0,
|
|
3998
|
+
label: sheetName,
|
|
3999
|
+
render: async (canvas) => {
|
|
4000
|
+
canvas.width = 140;
|
|
4001
|
+
canvas.height = 100;
|
|
4002
|
+
const c = canvas.getContext("2d");
|
|
4003
|
+
if (!c) return;
|
|
4004
|
+
c.fillStyle = "#ffffff";
|
|
4005
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4006
|
+
c.fillStyle = "#107c41";
|
|
4007
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
4008
|
+
c.fillStyle = "#ffffff";
|
|
4009
|
+
c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
4010
|
+
c.fillText(`\u{1F4CA} ${sheetName.slice(0, 16)}`, 6, 11);
|
|
4011
|
+
const startY = 17;
|
|
4012
|
+
const rowH = 13;
|
|
4013
|
+
const colW = 30;
|
|
4014
|
+
const cols = headerCells.slice(0, 4).map((h) => h.trim() || "Col");
|
|
4015
|
+
c.fillStyle = "#f1f5f9";
|
|
4016
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
4017
|
+
c.strokeStyle = "#cbd5e1";
|
|
4018
|
+
c.lineWidth = 0.8;
|
|
4019
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
4020
|
+
c.fillStyle = "#64748b";
|
|
4021
|
+
c.font = "bold 7px sans-serif";
|
|
4022
|
+
for (let ci = 0; ci < cols.length; ci++) {
|
|
4023
|
+
c.fillText(cols[ci].slice(0, 5), 14 + ci * colW, startY + 9);
|
|
4024
|
+
}
|
|
4025
|
+
for (let ri = 0; ri < Math.min(5, dataLines.length); ri++) {
|
|
4026
|
+
const y = startY + (ri + 1) * rowH;
|
|
4027
|
+
if (y > canvas.height - 2) break;
|
|
4028
|
+
c.fillStyle = "#f8fafc";
|
|
4029
|
+
c.fillRect(0, y, 12, rowH);
|
|
4030
|
+
c.fillStyle = "#94a3b8";
|
|
4031
|
+
c.font = "6px sans-serif";
|
|
4032
|
+
c.fillText(String(ri + 1), 3, y + 9);
|
|
4033
|
+
c.strokeStyle = "#e2e8f0";
|
|
4034
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
4035
|
+
const rowCells = dataLines[ri].split(delimiter);
|
|
4036
|
+
c.fillStyle = "#334155";
|
|
4037
|
+
c.font = "6px sans-serif";
|
|
4038
|
+
for (let ci = 0; ci < cols.length; ci++) {
|
|
4039
|
+
const val = (rowCells[ci] || "").trim();
|
|
4040
|
+
if (val) {
|
|
4041
|
+
c.fillText(val.slice(0, 6), 14 + ci * colW, y + 9);
|
|
4042
|
+
}
|
|
4043
|
+
}
|
|
4044
|
+
}
|
|
4045
|
+
c.strokeStyle = "#cbd5e1";
|
|
4046
|
+
c.lineWidth = 1;
|
|
4047
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4048
|
+
}
|
|
4049
|
+
}];
|
|
4050
|
+
},
|
|
3310
4051
|
zoomIn: () => {
|
|
3311
4052
|
scale += 0.1;
|
|
3312
|
-
|
|
4053
|
+
applyScale();
|
|
3313
4054
|
},
|
|
3314
4055
|
zoomOut: () => {
|
|
3315
4056
|
scale = Math.max(0.2, scale - 0.1);
|
|
3316
|
-
|
|
4057
|
+
applyScale();
|
|
3317
4058
|
},
|
|
3318
4059
|
getZoom: () => scale,
|
|
3319
4060
|
setZoom: (level) => {
|
|
3320
4061
|
scale = level;
|
|
3321
|
-
|
|
4062
|
+
applyScale();
|
|
3322
4063
|
},
|
|
3323
4064
|
fitToPage: () => {
|
|
3324
|
-
scale =
|
|
3325
|
-
|
|
4065
|
+
scale = calculateFitScale();
|
|
4066
|
+
applyScale();
|
|
4067
|
+
},
|
|
4068
|
+
rotateCW: () => {
|
|
4069
|
+
},
|
|
4070
|
+
rotateCCW: () => {
|
|
3326
4071
|
},
|
|
3327
4072
|
download: () => {
|
|
3328
4073
|
const blob = new Blob([ctx.buffer], { type: "text/csv" });
|
|
@@ -3384,30 +4129,36 @@ var CodePlugin = class {
|
|
|
3384
4129
|
return false;
|
|
3385
4130
|
}
|
|
3386
4131
|
getToolbarActions(instance) {
|
|
3387
|
-
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3388
|
-
const actions = [];
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
4132
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4133
|
+
const actions = [];
|
|
4134
|
+
actions.push({
|
|
4135
|
+
id: "thumbnails",
|
|
4136
|
+
icon: "thumbnails",
|
|
4137
|
+
label: "Page Thumbnails",
|
|
4138
|
+
type: "button",
|
|
4139
|
+
group: "navigation",
|
|
4140
|
+
execute: () => instance.toggleThumbnails?.()
|
|
4141
|
+
});
|
|
4142
|
+
actions.push({
|
|
4143
|
+
id: "page-nav",
|
|
4144
|
+
icon: "",
|
|
4145
|
+
label: "Page Navigation",
|
|
4146
|
+
type: "page-nav",
|
|
4147
|
+
group: "navigation",
|
|
4148
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4149
|
+
max: totalPages,
|
|
4150
|
+
execute: (action, page) => {
|
|
4151
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4152
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4153
|
+
if (action === "prev") {
|
|
4154
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4155
|
+
} else if (action === "next") {
|
|
4156
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4157
|
+
} else if (typeof page === "number") {
|
|
4158
|
+
instance.goToPage?.(page);
|
|
3408
4159
|
}
|
|
3409
|
-
}
|
|
3410
|
-
}
|
|
4160
|
+
}
|
|
4161
|
+
});
|
|
3411
4162
|
actions.push(
|
|
3412
4163
|
{
|
|
3413
4164
|
id: "zoom-out",
|
|
@@ -3429,26 +4180,6 @@ var CodePlugin = class {
|
|
|
3429
4180
|
instance.zoomIn?.();
|
|
3430
4181
|
}
|
|
3431
4182
|
},
|
|
3432
|
-
{
|
|
3433
|
-
id: "fit-page",
|
|
3434
|
-
icon: "fit-page",
|
|
3435
|
-
label: "Fit to View",
|
|
3436
|
-
type: "button",
|
|
3437
|
-
group: "zoom",
|
|
3438
|
-
execute: () => {
|
|
3439
|
-
instance.fitToPage?.();
|
|
3440
|
-
}
|
|
3441
|
-
},
|
|
3442
|
-
{
|
|
3443
|
-
id: "rotate-cw",
|
|
3444
|
-
icon: "rotate-cw",
|
|
3445
|
-
label: "Rotate",
|
|
3446
|
-
type: "button",
|
|
3447
|
-
group: "view",
|
|
3448
|
-
execute: () => {
|
|
3449
|
-
instance.rotateCW?.();
|
|
3450
|
-
}
|
|
3451
|
-
},
|
|
3452
4183
|
{
|
|
3453
4184
|
id: "copy",
|
|
3454
4185
|
icon: "copy",
|
|
@@ -3551,16 +4282,19 @@ var CodePlugin = class {
|
|
|
3551
4282
|
let fontSize = 13;
|
|
3552
4283
|
let rotation = 0;
|
|
3553
4284
|
let zoomLevel = 1;
|
|
4285
|
+
let isUserZoomed = false;
|
|
3554
4286
|
const pre = document.createElement("pre");
|
|
3555
4287
|
const code = document.createElement("code");
|
|
3556
4288
|
if (isTxt) {
|
|
4289
|
+
container.style.overflowX = "hidden";
|
|
4290
|
+
container.style.overflowY = "auto";
|
|
3557
4291
|
container.style.backgroundColor = "#f1f5f9";
|
|
3558
|
-
container.style.padding = "
|
|
4292
|
+
container.style.padding = "16px 8px";
|
|
3559
4293
|
container.style.boxSizing = "border-box";
|
|
3560
4294
|
container.style.display = "flex";
|
|
3561
4295
|
container.style.flexDirection = "column";
|
|
3562
4296
|
container.style.alignItems = "center";
|
|
3563
|
-
pre.style.margin = "0";
|
|
4297
|
+
pre.style.margin = "0 auto";
|
|
3564
4298
|
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3565
4299
|
pre.style.fontSize = "13px";
|
|
3566
4300
|
pre.style.color = "#1e293b";
|
|
@@ -3572,10 +4306,12 @@ var CodePlugin = class {
|
|
|
3572
4306
|
pre.style.minHeight = "1056px";
|
|
3573
4307
|
pre.style.padding = "72px 56px";
|
|
3574
4308
|
pre.style.boxSizing = "border-box";
|
|
3575
|
-
pre.style.boxShadow = "0 4px
|
|
4309
|
+
pre.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
3576
4310
|
pre.style.borderRadius = "4px";
|
|
3577
4311
|
pre.style.transformOrigin = "top center";
|
|
4312
|
+
pre.style.transition = "transform 0.15s ease";
|
|
3578
4313
|
} else {
|
|
4314
|
+
container.style.overflow = "auto";
|
|
3579
4315
|
container.style.backgroundColor = "#1e1e1e";
|
|
3580
4316
|
container.style.color = "#d4d4d4";
|
|
3581
4317
|
container.style.padding = "16px";
|
|
@@ -3607,42 +4343,9 @@ var CodePlugin = class {
|
|
|
3607
4343
|
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
3608
4344
|
pre.appendChild(code);
|
|
3609
4345
|
container.appendChild(pre);
|
|
3610
|
-
let indicator = null;
|
|
3611
|
-
if (totalPages > 1) {
|
|
3612
|
-
indicator = document.createElement("div");
|
|
3613
|
-
indicator.className = "fp-code-page-indicator";
|
|
3614
|
-
indicator.style.position = "sticky";
|
|
3615
|
-
indicator.style.bottom = "16px";
|
|
3616
|
-
if (isTxt) {
|
|
3617
|
-
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3618
|
-
indicator.style.color = "#334155";
|
|
3619
|
-
indicator.style.border = "1px solid #e2e8f0";
|
|
3620
|
-
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3621
|
-
} else {
|
|
3622
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3623
|
-
indicator.style.color = "#f8fafc";
|
|
3624
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3625
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3626
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
3627
|
-
}
|
|
3628
|
-
indicator.style.fontSize = "12px";
|
|
3629
|
-
indicator.style.fontWeight = "600";
|
|
3630
|
-
indicator.style.padding = "5px 14px";
|
|
3631
|
-
indicator.style.borderRadius = "20px";
|
|
3632
|
-
indicator.style.zIndex = "10";
|
|
3633
|
-
indicator.style.userSelect = "none";
|
|
3634
|
-
indicator.style.pointerEvents = "none";
|
|
3635
|
-
indicator.style.textAlign = "center";
|
|
3636
|
-
indicator.style.width = "fit-content";
|
|
3637
|
-
indicator.style.margin = "16px auto 0";
|
|
3638
|
-
container.appendChild(indicator);
|
|
3639
|
-
}
|
|
3640
4346
|
const showPage = (pageNum) => {
|
|
3641
4347
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3642
4348
|
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
3643
|
-
if (indicator) {
|
|
3644
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3645
|
-
}
|
|
3646
4349
|
container.scrollTop = 0;
|
|
3647
4350
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3648
4351
|
};
|
|
@@ -3650,36 +4353,90 @@ var CodePlugin = class {
|
|
|
3650
4353
|
showPage(1);
|
|
3651
4354
|
}
|
|
3652
4355
|
ctx.container.appendChild(container);
|
|
3653
|
-
const
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
ctx.container.innerHTML = "";
|
|
4356
|
+
const calculateTxtFit = () => {
|
|
4357
|
+
const availW = Math.max(280, container.clientWidth - 32);
|
|
4358
|
+
return Math.max(0.4, Math.min(3, availW / 816));
|
|
3657
4359
|
};
|
|
3658
|
-
ctx.signal.addEventListener("abort", cleanup);
|
|
3659
4360
|
const updateTransform = () => {
|
|
3660
4361
|
if (isTxt) {
|
|
3661
4362
|
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
4363
|
+
const scaledH = 1056 * zoomLevel;
|
|
4364
|
+
const extraH = Math.max(0, scaledH - 1056);
|
|
4365
|
+
pre.style.marginBottom = `${extraH + 32}px`;
|
|
3662
4366
|
} else {
|
|
3663
4367
|
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3664
4368
|
pre.style.fontSize = `${fontSize}px`;
|
|
3665
4369
|
}
|
|
3666
4370
|
};
|
|
4371
|
+
let resizeObserver = null;
|
|
4372
|
+
if (isTxt) {
|
|
4373
|
+
setTimeout(() => {
|
|
4374
|
+
zoomLevel = calculateTxtFit();
|
|
4375
|
+
updateTransform();
|
|
4376
|
+
}, 60);
|
|
4377
|
+
resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
4378
|
+
if (!isUserZoomed) {
|
|
4379
|
+
zoomLevel = calculateTxtFit();
|
|
4380
|
+
updateTransform();
|
|
4381
|
+
}
|
|
4382
|
+
}) : null;
|
|
4383
|
+
resizeObserver?.observe(container);
|
|
4384
|
+
}
|
|
4385
|
+
const cleanup = () => {
|
|
4386
|
+
resizeObserver?.disconnect();
|
|
4387
|
+
container.remove();
|
|
4388
|
+
ctx.container.innerHTML = "";
|
|
4389
|
+
};
|
|
4390
|
+
ctx.signal.addEventListener("abort", cleanup);
|
|
3667
4391
|
return {
|
|
3668
4392
|
destroy: cleanup,
|
|
3669
4393
|
getPageCount: () => totalPages,
|
|
3670
4394
|
getCurrentPage: () => currentPage,
|
|
3671
4395
|
goToPage: (page) => showPage(page),
|
|
4396
|
+
getThumbnails: () => {
|
|
4397
|
+
return rawPages.map((pageText, idx) => ({
|
|
4398
|
+
index: idx,
|
|
4399
|
+
label: `Page ${idx + 1}`,
|
|
4400
|
+
render: async (canvas) => {
|
|
4401
|
+
canvas.width = 140;
|
|
4402
|
+
canvas.height = 180;
|
|
4403
|
+
const c = canvas.getContext("2d");
|
|
4404
|
+
if (!c) return;
|
|
4405
|
+
c.fillStyle = "#ffffff";
|
|
4406
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4407
|
+
c.strokeStyle = "#cbd5e1";
|
|
4408
|
+
c.lineWidth = 1;
|
|
4409
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4410
|
+
c.fillStyle = "#64748b";
|
|
4411
|
+
const lines = (pageText || "").split("\n").slice(0, 24);
|
|
4412
|
+
const lineH = 6;
|
|
4413
|
+
const startY = 14;
|
|
4414
|
+
const startX = 12;
|
|
4415
|
+
const maxW = canvas.width - 24;
|
|
4416
|
+
c.font = "5px monospace";
|
|
4417
|
+
for (let li = 0; li < lines.length; li++) {
|
|
4418
|
+
const l = lines[li].trim();
|
|
4419
|
+
if (!l) continue;
|
|
4420
|
+
const y = startY + li * lineH;
|
|
4421
|
+
if (y > canvas.height - 12) break;
|
|
4422
|
+
c.fillText(l.slice(0, 30), startX, y, maxW);
|
|
4423
|
+
}
|
|
4424
|
+
}
|
|
4425
|
+
}));
|
|
4426
|
+
},
|
|
3672
4427
|
zoomIn: () => {
|
|
4428
|
+
isUserZoomed = true;
|
|
3673
4429
|
if (isTxt) {
|
|
3674
|
-
zoomLevel = Math.min(3, zoomLevel + 0.
|
|
4430
|
+
zoomLevel = Math.min(3.5, zoomLevel + 0.15);
|
|
3675
4431
|
} else {
|
|
3676
4432
|
fontSize = Math.min(32, fontSize + 2);
|
|
3677
4433
|
}
|
|
3678
4434
|
updateTransform();
|
|
3679
4435
|
},
|
|
3680
4436
|
zoomOut: () => {
|
|
4437
|
+
isUserZoomed = true;
|
|
3681
4438
|
if (isTxt) {
|
|
3682
|
-
zoomLevel = Math.max(0.1, zoomLevel - 0.
|
|
4439
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.15);
|
|
3683
4440
|
} else {
|
|
3684
4441
|
fontSize = Math.max(8, fontSize - 2);
|
|
3685
4442
|
}
|
|
@@ -3687,6 +4444,7 @@ var CodePlugin = class {
|
|
|
3687
4444
|
},
|
|
3688
4445
|
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
3689
4446
|
setZoom: (level) => {
|
|
4447
|
+
isUserZoomed = true;
|
|
3690
4448
|
if (isTxt) {
|
|
3691
4449
|
zoomLevel = level;
|
|
3692
4450
|
} else {
|
|
@@ -3695,9 +4453,10 @@ var CodePlugin = class {
|
|
|
3695
4453
|
updateTransform();
|
|
3696
4454
|
},
|
|
3697
4455
|
fitToPage: () => {
|
|
4456
|
+
isUserZoomed = false;
|
|
3698
4457
|
fontSize = 13;
|
|
3699
4458
|
rotation = 0;
|
|
3700
|
-
zoomLevel = isTxt ?
|
|
4459
|
+
zoomLevel = isTxt ? calculateTxtFit() : 1;
|
|
3701
4460
|
updateTransform();
|
|
3702
4461
|
},
|
|
3703
4462
|
rotateCW: () => {
|
|
@@ -4564,6 +5323,148 @@ var ThreeDPlugin = class {
|
|
|
4564
5323
|
function threeDPlugin() {
|
|
4565
5324
|
return new ThreeDPlugin();
|
|
4566
5325
|
}
|
|
5326
|
+
function cleanRtfText(raw) {
|
|
5327
|
+
return raw.replace(/\\bin\d+\s/g, "").replace(/{\\\*[^}]+}/g, "").replace(/\\u(-?\d+)\??/g, (_, code) => {
|
|
5328
|
+
let num = parseInt(code, 10);
|
|
5329
|
+
if (num < 0) num += 65536;
|
|
5330
|
+
return String.fromCharCode(num);
|
|
5331
|
+
}).replace(/\\'([0-9a-fA-F]{2})/g, (_, hex) => {
|
|
5332
|
+
return String.fromCharCode(parseInt(hex, 16));
|
|
5333
|
+
}).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();
|
|
5334
|
+
}
|
|
5335
|
+
function parseRtfTables(rtfText) {
|
|
5336
|
+
const rowSegments = rtfText.split(/\\row\b/);
|
|
5337
|
+
if (rowSegments.length <= 1) return [];
|
|
5338
|
+
const rawTables = [];
|
|
5339
|
+
let currentTable = null;
|
|
5340
|
+
let charOffset = 0;
|
|
5341
|
+
for (let i = 0; i < rowSegments.length - 1; i++) {
|
|
5342
|
+
const segment = rowSegments[i];
|
|
5343
|
+
const segmentStart = charOffset;
|
|
5344
|
+
const segmentEnd = charOffset + segment.length + 4;
|
|
5345
|
+
const cellParts = segment.split(/\\cell\b/);
|
|
5346
|
+
if (cellParts.length > 1) {
|
|
5347
|
+
const cellxMatches = [...segment.matchAll(/\\cellx(\d+)/g)].map((m) => parseInt(m[1], 10));
|
|
5348
|
+
let cellWidths = [];
|
|
5349
|
+
if (cellxMatches.length > 0) {
|
|
5350
|
+
let seq = [cellxMatches[0]];
|
|
5351
|
+
for (let k = 1; k < cellxMatches.length; k++) {
|
|
5352
|
+
if (cellxMatches[k] > cellxMatches[k - 1]) seq.push(cellxMatches[k]);
|
|
5353
|
+
else break;
|
|
5354
|
+
}
|
|
5355
|
+
let prev = 0;
|
|
5356
|
+
cellWidths = seq.map((x) => {
|
|
5357
|
+
const w = x - prev;
|
|
5358
|
+
prev = x;
|
|
5359
|
+
return w;
|
|
5360
|
+
});
|
|
5361
|
+
}
|
|
5362
|
+
const cells = [];
|
|
5363
|
+
for (let c = 0; c < cellParts.length - 1; c++) {
|
|
5364
|
+
let rawCell = cellParts[c];
|
|
5365
|
+
if (c === 0) {
|
|
5366
|
+
const lastTrowd = rawCell.lastIndexOf("\\trowd");
|
|
5367
|
+
if (lastTrowd !== -1) rawCell = rawCell.slice(lastTrowd);
|
|
5368
|
+
}
|
|
5369
|
+
cells.push(cleanRtfText(rawCell));
|
|
5370
|
+
}
|
|
5371
|
+
const isNewTable = !currentTable || segmentStart - currentTable.lastEnd > 2500;
|
|
5372
|
+
if (isNewTable) {
|
|
5373
|
+
const prevTextSlice = rtfText.slice(Math.max(0, segmentStart - 4e3), segmentStart);
|
|
5374
|
+
const cleanPrev = cleanRtfText(prevTextSlice);
|
|
5375
|
+
const anchorBefore = cleanPrev.slice(-80).trim();
|
|
5376
|
+
currentTable = {
|
|
5377
|
+
id: `RTF_TABLE_${rawTables.length}`,
|
|
5378
|
+
startPos: segmentStart,
|
|
5379
|
+
lastEnd: segmentEnd,
|
|
5380
|
+
rows: [],
|
|
5381
|
+
columnWidths: cellWidths,
|
|
5382
|
+
anchorBefore,
|
|
5383
|
+
anchorAfter: ""
|
|
5384
|
+
};
|
|
5385
|
+
rawTables.push(currentTable);
|
|
5386
|
+
}
|
|
5387
|
+
if (currentTable) {
|
|
5388
|
+
currentTable.rows.push({
|
|
5389
|
+
cells,
|
|
5390
|
+
widths: cellWidths.length === cells.length ? cellWidths : currentTable.columnWidths
|
|
5391
|
+
});
|
|
5392
|
+
currentTable.lastEnd = segmentEnd;
|
|
5393
|
+
}
|
|
5394
|
+
}
|
|
5395
|
+
charOffset += segment.length + 4;
|
|
5396
|
+
}
|
|
5397
|
+
rawTables.forEach((tbl) => {
|
|
5398
|
+
const afterSlice = rtfText.slice(tbl.lastEnd, Math.min(rtfText.length, tbl.lastEnd + 2e3));
|
|
5399
|
+
const cleanAfter = cleanRtfText(afterSlice);
|
|
5400
|
+
tbl.anchorAfter = cleanAfter.slice(0, 80).trim();
|
|
5401
|
+
});
|
|
5402
|
+
return rawTables.map((tbl) => {
|
|
5403
|
+
const totalW = (tbl.columnWidths || []).reduce((a, b) => a + b, 0);
|
|
5404
|
+
const colPercents = totalW > 0 ? tbl.columnWidths.map((w) => Math.round(w / totalW * 100)) : [];
|
|
5405
|
+
return {
|
|
5406
|
+
id: tbl.id,
|
|
5407
|
+
rows: tbl.rows.map((r) => r.cells),
|
|
5408
|
+
colPercents,
|
|
5409
|
+
anchorBefore: tbl.anchorBefore,
|
|
5410
|
+
anchorAfter: tbl.anchorAfter
|
|
5411
|
+
};
|
|
5412
|
+
});
|
|
5413
|
+
}
|
|
5414
|
+
function renderRtfTableElement(table) {
|
|
5415
|
+
const tableEl = document.createElement("table");
|
|
5416
|
+
tableEl.className = "fp-rtf-table";
|
|
5417
|
+
tableEl.style.width = "100%";
|
|
5418
|
+
tableEl.style.borderCollapse = "collapse";
|
|
5419
|
+
tableEl.style.margin = "16px 0 20px";
|
|
5420
|
+
tableEl.style.fontSize = "10pt";
|
|
5421
|
+
tableEl.style.lineHeight = "1.5";
|
|
5422
|
+
tableEl.style.border = "1px solid #cbd5e1";
|
|
5423
|
+
tableEl.style.borderRadius = "4px";
|
|
5424
|
+
tableEl.style.boxSizing = "border-box";
|
|
5425
|
+
tableEl.style.backgroundColor = "#ffffff";
|
|
5426
|
+
const thead = document.createElement("thead");
|
|
5427
|
+
const tbody = document.createElement("tbody");
|
|
5428
|
+
table.rows.forEach((rowCells, rIdx) => {
|
|
5429
|
+
const tr = document.createElement("tr");
|
|
5430
|
+
const isHeader = rIdx === 0;
|
|
5431
|
+
if (isHeader) {
|
|
5432
|
+
tr.style.backgroundColor = "#f8fafc";
|
|
5433
|
+
tr.style.borderBottom = "2px solid #cbd5e1";
|
|
5434
|
+
} else {
|
|
5435
|
+
tr.style.borderBottom = "1px solid #e2e8f0";
|
|
5436
|
+
if (rIdx % 2 === 0) {
|
|
5437
|
+
tr.style.backgroundColor = "#fcfdfe";
|
|
5438
|
+
}
|
|
5439
|
+
}
|
|
5440
|
+
rowCells.forEach((cellText, cIdx) => {
|
|
5441
|
+
const cellEl = document.createElement(isHeader ? "th" : "td");
|
|
5442
|
+
cellEl.style.padding = "8px 12px";
|
|
5443
|
+
cellEl.style.border = "1px solid #cbd5e1";
|
|
5444
|
+
cellEl.style.verticalAlign = "top";
|
|
5445
|
+
cellEl.style.color = isHeader ? "#0f172a" : "#1e293b";
|
|
5446
|
+
cellEl.style.fontWeight = isHeader ? "600" : "normal";
|
|
5447
|
+
if (table.colPercents && table.colPercents[cIdx]) {
|
|
5448
|
+
cellEl.style.width = `${table.colPercents[cIdx]}%`;
|
|
5449
|
+
}
|
|
5450
|
+
if (/^\d+$/.test(cellText.trim()) || cellText.trim() === "#") {
|
|
5451
|
+
cellEl.style.textAlign = "center";
|
|
5452
|
+
} else {
|
|
5453
|
+
cellEl.style.textAlign = "left";
|
|
5454
|
+
}
|
|
5455
|
+
cellEl.textContent = cellText;
|
|
5456
|
+
tr.appendChild(cellEl);
|
|
5457
|
+
});
|
|
5458
|
+
if (isHeader) {
|
|
5459
|
+
thead.appendChild(tr);
|
|
5460
|
+
} else {
|
|
5461
|
+
tbody.appendChild(tr);
|
|
5462
|
+
}
|
|
5463
|
+
});
|
|
5464
|
+
tableEl.appendChild(thead);
|
|
5465
|
+
tableEl.appendChild(tbody);
|
|
5466
|
+
return tableEl;
|
|
5467
|
+
}
|
|
4567
5468
|
var RtfPlugin = class {
|
|
4568
5469
|
id = "rtf";
|
|
4569
5470
|
name = "Rich Text Format (RTF)";
|
|
@@ -4578,29 +5479,35 @@ var RtfPlugin = class {
|
|
|
4578
5479
|
getToolbarActions(instance) {
|
|
4579
5480
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4580
5481
|
const actions = [];
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
if (
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
instance.goToPage?.(page);
|
|
4599
|
-
}
|
|
5482
|
+
actions.push({
|
|
5483
|
+
id: "page-nav",
|
|
5484
|
+
icon: "",
|
|
5485
|
+
label: "Page Navigation",
|
|
5486
|
+
type: "page-nav",
|
|
5487
|
+
group: "navigation",
|
|
5488
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5489
|
+
max: totalPages,
|
|
5490
|
+
execute: (action, page) => {
|
|
5491
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5492
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5493
|
+
if (action === "prev") {
|
|
5494
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5495
|
+
} else if (action === "next") {
|
|
5496
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5497
|
+
} else if (typeof page === "number") {
|
|
5498
|
+
instance.goToPage?.(page);
|
|
4600
5499
|
}
|
|
4601
|
-
}
|
|
4602
|
-
}
|
|
5500
|
+
}
|
|
5501
|
+
});
|
|
4603
5502
|
actions.push(
|
|
5503
|
+
{
|
|
5504
|
+
id: "thumbnails",
|
|
5505
|
+
icon: "thumbnails",
|
|
5506
|
+
label: "Thumbnails",
|
|
5507
|
+
type: "button",
|
|
5508
|
+
group: "view",
|
|
5509
|
+
execute: () => instance.toggleThumbnails?.()
|
|
5510
|
+
},
|
|
4604
5511
|
{
|
|
4605
5512
|
id: "zoom-out",
|
|
4606
5513
|
icon: "zoom-out",
|
|
@@ -4671,67 +5578,143 @@ var RtfPlugin = class {
|
|
|
4671
5578
|
async render(ctx) {
|
|
4672
5579
|
const wrapper = document.createElement("div");
|
|
4673
5580
|
wrapper.className = "fp-rtf-wrapper";
|
|
4674
|
-
wrapper.style.padding = "
|
|
4675
|
-
wrapper.style.
|
|
5581
|
+
wrapper.style.padding = "0";
|
|
5582
|
+
wrapper.style.width = "816px";
|
|
4676
5583
|
wrapper.style.margin = "0 auto";
|
|
4677
|
-
wrapper.style.
|
|
4678
|
-
wrapper.style.
|
|
4679
|
-
wrapper.style.
|
|
4680
|
-
wrapper.style.
|
|
5584
|
+
wrapper.style.boxSizing = "border-box";
|
|
5585
|
+
wrapper.style.display = "flex";
|
|
5586
|
+
wrapper.style.flexDirection = "column";
|
|
5587
|
+
wrapper.style.alignItems = "center";
|
|
5588
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4681
5589
|
wrapper.style.transformOrigin = "top center";
|
|
4682
|
-
wrapper.style.transition = "transform 0.
|
|
4683
|
-
ctx.container.style.
|
|
4684
|
-
ctx.container.style.
|
|
5590
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5591
|
+
ctx.container.style.overflowX = "hidden";
|
|
5592
|
+
ctx.container.style.overflowY = "auto";
|
|
5593
|
+
ctx.container.style.padding = "16px 8px";
|
|
4685
5594
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
4686
5595
|
ctx.container.appendChild(wrapper);
|
|
4687
5596
|
let scale = 1;
|
|
4688
5597
|
let rotation = 0;
|
|
4689
5598
|
let pageElements = [];
|
|
4690
|
-
let
|
|
5599
|
+
let isUserZoomed = false;
|
|
5600
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
4691
5601
|
const calculateFitScale = (mode = fitMode) => {
|
|
4692
5602
|
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4693
|
-
const elW =
|
|
4694
|
-
const singlePageH =
|
|
4695
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
4696
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
5603
|
+
const elW = 816;
|
|
5604
|
+
const singlePageH = activeEl?.offsetHeight || 1056;
|
|
5605
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
5606
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
4697
5607
|
const sW = availW / elW;
|
|
4698
5608
|
const sH = availH / singlePageH;
|
|
4699
5609
|
if (mode === "page") {
|
|
4700
|
-
return Math.max(0.
|
|
5610
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
4701
5611
|
}
|
|
4702
|
-
return Math.max(0.
|
|
5612
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
4703
5613
|
};
|
|
4704
5614
|
const applyTransform = () => {
|
|
4705
5615
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4706
5616
|
wrapper.style.transformOrigin = "top center";
|
|
5617
|
+
const activeEl = pageElements[currentPage - 1];
|
|
5618
|
+
const baseH = activeEl?.offsetHeight || 1056;
|
|
5619
|
+
const scaledH = baseH * scale;
|
|
5620
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
5621
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
4707
5622
|
};
|
|
5623
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
5624
|
+
if (!isUserZoomed) {
|
|
5625
|
+
scale = calculateFitScale(fitMode);
|
|
5626
|
+
applyTransform();
|
|
5627
|
+
}
|
|
5628
|
+
}) : null;
|
|
5629
|
+
resizeObserver?.observe(ctx.container);
|
|
4708
5630
|
setTimeout(() => {
|
|
4709
|
-
|
|
4710
|
-
scale = calculateFitScale("width");
|
|
5631
|
+
scale = calculateFitScale(fitMode);
|
|
4711
5632
|
applyTransform();
|
|
4712
5633
|
}, 60);
|
|
4713
5634
|
try {
|
|
4714
5635
|
if (typeof RTFJS.loggingEnabled === "function") {
|
|
4715
5636
|
RTFJS.loggingEnabled(false);
|
|
4716
5637
|
}
|
|
5638
|
+
const rawText = new TextDecoder("latin1").decode(ctx.buffer);
|
|
5639
|
+
const tables = parseRtfTables(rawText);
|
|
4717
5640
|
const doc = new RTFJS.Document(ctx.buffer, {});
|
|
4718
5641
|
const htmlElements = await doc.render();
|
|
4719
5642
|
const contentNodes = [];
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
5643
|
+
const extractBlocks = (nodes) => {
|
|
5644
|
+
for (const item of nodes) {
|
|
5645
|
+
if (!item || !(item instanceof HTMLElement)) continue;
|
|
5646
|
+
const tag = item.tagName.toLowerCase();
|
|
5647
|
+
const hasChildBlocks = Array.from(item.children).some((c) => {
|
|
5648
|
+
const ct = c.tagName.toLowerCase();
|
|
5649
|
+
return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
|
|
5650
|
+
});
|
|
5651
|
+
if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
|
|
5652
|
+
extractBlocks(Array.from(item.children));
|
|
5653
|
+
} else {
|
|
5654
|
+
const svgs = item.querySelectorAll("svg, img");
|
|
5655
|
+
svgs.forEach((s) => {
|
|
5656
|
+
const el = s;
|
|
5657
|
+
el.style.maxWidth = "100%";
|
|
5658
|
+
el.style.maxHeight = "360px";
|
|
5659
|
+
el.style.display = "block";
|
|
5660
|
+
el.style.margin = "12px auto";
|
|
5661
|
+
if (s.tagName.toLowerCase() === "svg") {
|
|
5662
|
+
s.removeAttribute("width");
|
|
5663
|
+
s.removeAttribute("height");
|
|
5664
|
+
el.style.width = "100%";
|
|
5665
|
+
el.style.maxHeight = "360px";
|
|
5666
|
+
}
|
|
5667
|
+
});
|
|
5668
|
+
if (tag === "p" || tag === "div") {
|
|
5669
|
+
item.style.display = "block";
|
|
5670
|
+
item.style.marginBottom = "12px";
|
|
5671
|
+
item.style.lineHeight = "1.6";
|
|
5672
|
+
}
|
|
5673
|
+
contentNodes.push(item);
|
|
5674
|
+
}
|
|
4725
5675
|
}
|
|
4726
|
-
}
|
|
5676
|
+
};
|
|
5677
|
+
extractBlocks(htmlElements);
|
|
5678
|
+
tables.forEach((table) => {
|
|
5679
|
+
const tableEl = renderRtfTableElement(table);
|
|
5680
|
+
let inserted = false;
|
|
5681
|
+
if (table.anchorBefore && table.anchorBefore.length > 10) {
|
|
5682
|
+
const keyword = table.anchorBefore.slice(-35).trim();
|
|
5683
|
+
for (let i = 0; i < contentNodes.length; i++) {
|
|
5684
|
+
if (contentNodes[i].textContent?.includes(keyword)) {
|
|
5685
|
+
contentNodes.splice(i + 1, 0, tableEl);
|
|
5686
|
+
inserted = true;
|
|
5687
|
+
break;
|
|
5688
|
+
}
|
|
5689
|
+
}
|
|
5690
|
+
}
|
|
5691
|
+
if (!inserted && table.anchorAfter && table.anchorAfter.length > 10) {
|
|
5692
|
+
const keyword = table.anchorAfter.slice(0, 35).trim();
|
|
5693
|
+
for (let i = 0; i < contentNodes.length; i++) {
|
|
5694
|
+
if (contentNodes[i].textContent?.includes(keyword)) {
|
|
5695
|
+
contentNodes.splice(i, 0, tableEl);
|
|
5696
|
+
inserted = true;
|
|
5697
|
+
break;
|
|
5698
|
+
}
|
|
5699
|
+
}
|
|
5700
|
+
}
|
|
5701
|
+
if (!inserted) {
|
|
5702
|
+
if (contentNodes.length > 2) {
|
|
5703
|
+
contentNodes.splice(2, 0, tableEl);
|
|
5704
|
+
} else {
|
|
5705
|
+
contentNodes.push(tableEl);
|
|
5706
|
+
}
|
|
5707
|
+
}
|
|
5708
|
+
});
|
|
4727
5709
|
wrapper.innerHTML = "";
|
|
4728
5710
|
contentNodes.forEach((node) => wrapper.appendChild(node));
|
|
4729
5711
|
const childHeights = contentNodes.map((c) => {
|
|
4730
5712
|
const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
|
|
4731
5713
|
const offH = c.offsetHeight || 0;
|
|
5714
|
+
const realH = Math.max(rectH, offH);
|
|
5715
|
+
if (realH > 0) return realH;
|
|
4732
5716
|
const textLen = c.textContent?.trim().length || 0;
|
|
4733
|
-
|
|
4734
|
-
return Math.max(rectH, offH, estH);
|
|
5717
|
+
return Math.max(24, Math.ceil(textLen / 95) * 22 + 12);
|
|
4735
5718
|
});
|
|
4736
5719
|
wrapper.innerHTML = "";
|
|
4737
5720
|
const createRtfCard = () => {
|
|
@@ -4740,35 +5723,49 @@ var RtfPlugin = class {
|
|
|
4740
5723
|
card.style.backgroundColor = "#ffffff";
|
|
4741
5724
|
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
4742
5725
|
card.style.borderRadius = "4px";
|
|
4743
|
-
card.style.padding = "
|
|
5726
|
+
card.style.padding = "64px 56px";
|
|
4744
5727
|
card.style.width = "816px";
|
|
4745
5728
|
card.style.minHeight = "1056px";
|
|
4746
5729
|
card.style.boxSizing = "border-box";
|
|
4747
5730
|
card.style.marginBottom = "24px";
|
|
4748
5731
|
card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4749
5732
|
card.style.lineHeight = "1.6";
|
|
5733
|
+
card.style.color = "#1e293b";
|
|
4750
5734
|
return card;
|
|
4751
5735
|
};
|
|
4752
5736
|
let curCard = createRtfCard();
|
|
4753
5737
|
wrapper.appendChild(curCard);
|
|
4754
5738
|
pageElements = [curCard];
|
|
4755
5739
|
let curH = 0;
|
|
4756
|
-
const maxH =
|
|
5740
|
+
const maxH = 928;
|
|
4757
5741
|
for (let i = 0; i < contentNodes.length; i++) {
|
|
4758
5742
|
const child = contentNodes[i];
|
|
4759
5743
|
const chH = childHeights[i];
|
|
4760
|
-
|
|
4761
|
-
curH
|
|
4762
|
-
|
|
5744
|
+
const isChildEmpty = (child.textContent || "").trim().length === 0 && !child.querySelector("table, img, svg, canvas");
|
|
5745
|
+
if (curH === 0 && isChildEmpty) {
|
|
5746
|
+
continue;
|
|
5747
|
+
}
|
|
5748
|
+
if (curH + chH > maxH && curCard.childNodes.length > 0) {
|
|
4763
5749
|
curCard = createRtfCard();
|
|
4764
5750
|
wrapper.appendChild(curCard);
|
|
4765
5751
|
pageElements.push(curCard);
|
|
4766
5752
|
curH = 0;
|
|
4767
5753
|
}
|
|
5754
|
+
curCard.appendChild(child);
|
|
5755
|
+
curH += chH;
|
|
5756
|
+
}
|
|
5757
|
+
pageElements = pageElements.filter((card) => {
|
|
5758
|
+
const hasText = (card.textContent || "").trim().length > 0;
|
|
5759
|
+
const hasMedia = card.querySelector("table, img, svg, canvas") !== null;
|
|
5760
|
+
return hasText || hasMedia;
|
|
5761
|
+
});
|
|
5762
|
+
if (pageElements.length === 0) {
|
|
5763
|
+
pageElements = [curCard];
|
|
4768
5764
|
}
|
|
4769
5765
|
} catch (err) {
|
|
4770
5766
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
4771
5767
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
5768
|
+
const tables = parseRtfTables(text);
|
|
4772
5769
|
const rawPages = text.split(/\\page\b/).map((segment) => {
|
|
4773
5770
|
return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
|
|
4774
5771
|
}).filter((p) => p.length > 0);
|
|
@@ -4779,47 +5776,26 @@ var RtfPlugin = class {
|
|
|
4779
5776
|
pageCard.style.backgroundColor = "#ffffff";
|
|
4780
5777
|
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4781
5778
|
pageCard.style.borderRadius = "4px";
|
|
4782
|
-
pageCard.style.padding = "
|
|
5779
|
+
pageCard.style.padding = "64px 56px";
|
|
4783
5780
|
pageCard.style.width = "816px";
|
|
4784
5781
|
pageCard.style.minHeight = "1056px";
|
|
4785
|
-
pageCard.style.maxWidth = "100%";
|
|
4786
5782
|
pageCard.style.boxSizing = "border-box";
|
|
4787
|
-
pageCard.style.fontFamily = "serif
|
|
5783
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4788
5784
|
pageCard.style.fontSize = "12pt";
|
|
4789
5785
|
pageCard.style.lineHeight = "1.6";
|
|
4790
5786
|
pageCard.style.color = "#1e293b";
|
|
4791
5787
|
pageCard.style.whiteSpace = "pre-wrap";
|
|
4792
5788
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4793
5789
|
pageCard.textContent = pages[i];
|
|
5790
|
+
if (i === 1 && tables.length > 0) {
|
|
5791
|
+
tables.forEach((tbl) => pageCard.appendChild(renderRtfTableElement(tbl)));
|
|
5792
|
+
}
|
|
4794
5793
|
wrapper.appendChild(pageCard);
|
|
4795
5794
|
pageElements.push(pageCard);
|
|
4796
5795
|
}
|
|
4797
5796
|
}
|
|
4798
5797
|
const totalPages = Math.max(1, pageElements.length);
|
|
4799
5798
|
let currentPage = 1;
|
|
4800
|
-
let indicator = null;
|
|
4801
|
-
if (totalPages > 1) {
|
|
4802
|
-
indicator = document.createElement("div");
|
|
4803
|
-
indicator.className = "fp-rtf-page-indicator";
|
|
4804
|
-
indicator.style.position = "sticky";
|
|
4805
|
-
indicator.style.bottom = "16px";
|
|
4806
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4807
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
4808
|
-
indicator.style.color = "#f8fafc";
|
|
4809
|
-
indicator.style.fontSize = "12px";
|
|
4810
|
-
indicator.style.fontWeight = "600";
|
|
4811
|
-
indicator.style.padding = "5px 14px";
|
|
4812
|
-
indicator.style.borderRadius = "20px";
|
|
4813
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4814
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4815
|
-
indicator.style.zIndex = "10";
|
|
4816
|
-
indicator.style.userSelect = "none";
|
|
4817
|
-
indicator.style.pointerEvents = "none";
|
|
4818
|
-
indicator.style.textAlign = "center";
|
|
4819
|
-
indicator.style.width = "fit-content";
|
|
4820
|
-
indicator.style.margin = "16px auto 0";
|
|
4821
|
-
ctx.container.appendChild(indicator);
|
|
4822
|
-
}
|
|
4823
5799
|
const showPage = (pageNum) => {
|
|
4824
5800
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4825
5801
|
if (totalPages > 1) {
|
|
@@ -4827,9 +5803,6 @@ var RtfPlugin = class {
|
|
|
4827
5803
|
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4828
5804
|
});
|
|
4829
5805
|
}
|
|
4830
|
-
if (indicator) {
|
|
4831
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4832
|
-
}
|
|
4833
5806
|
ctx.container.scrollTop = 0;
|
|
4834
5807
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4835
5808
|
};
|
|
@@ -4837,7 +5810,7 @@ var RtfPlugin = class {
|
|
|
4837
5810
|
showPage(1);
|
|
4838
5811
|
}
|
|
4839
5812
|
const cleanup = () => {
|
|
4840
|
-
|
|
5813
|
+
resizeObserver?.disconnect();
|
|
4841
5814
|
wrapper.remove();
|
|
4842
5815
|
ctx.container.innerHTML = "";
|
|
4843
5816
|
};
|
|
@@ -4847,22 +5820,52 @@ var RtfPlugin = class {
|
|
|
4847
5820
|
getPageCount: () => totalPages,
|
|
4848
5821
|
getCurrentPage: () => currentPage,
|
|
4849
5822
|
goToPage: (page) => showPage(page),
|
|
5823
|
+
getThumbnails: async () => {
|
|
5824
|
+
const items = [];
|
|
5825
|
+
for (let idx = 0; idx < totalPages; idx++) {
|
|
5826
|
+
const pageIdx = idx;
|
|
5827
|
+
items.push({
|
|
5828
|
+
index: pageIdx,
|
|
5829
|
+
label: `Page ${pageIdx + 1}`,
|
|
5830
|
+
render: async (canvas) => {
|
|
5831
|
+
const ctx2d = canvas.getContext("2d");
|
|
5832
|
+
if (!ctx2d) return;
|
|
5833
|
+
canvas.width = 140;
|
|
5834
|
+
canvas.height = 180;
|
|
5835
|
+
ctx2d.fillStyle = "#ffffff";
|
|
5836
|
+
ctx2d.fillRect(0, 0, 140, 180);
|
|
5837
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
5838
|
+
ctx2d.lineWidth = 1;
|
|
5839
|
+
ctx2d.strokeRect(0.5, 0.5, 139, 179);
|
|
5840
|
+
ctx2d.fillStyle = "#334155";
|
|
5841
|
+
ctx2d.font = 'bold 11px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
5842
|
+
ctx2d.textAlign = "center";
|
|
5843
|
+
ctx2d.fillText(`Page ${pageIdx + 1}`, 70, 95);
|
|
5844
|
+
}
|
|
5845
|
+
});
|
|
5846
|
+
}
|
|
5847
|
+
return items;
|
|
5848
|
+
},
|
|
4850
5849
|
zoomIn: () => {
|
|
5850
|
+
isUserZoomed = true;
|
|
4851
5851
|
scale += 0.15;
|
|
4852
5852
|
applyTransform();
|
|
4853
5853
|
},
|
|
4854
5854
|
zoomOut: () => {
|
|
5855
|
+
isUserZoomed = true;
|
|
4855
5856
|
scale = Math.max(0.2, scale - 0.15);
|
|
4856
5857
|
applyTransform();
|
|
4857
5858
|
},
|
|
4858
5859
|
getZoom: () => scale,
|
|
4859
5860
|
setZoom: (level) => {
|
|
5861
|
+
isUserZoomed = true;
|
|
4860
5862
|
scale = level;
|
|
4861
5863
|
applyTransform();
|
|
4862
5864
|
},
|
|
4863
5865
|
fitToPage: () => {
|
|
4864
|
-
|
|
4865
|
-
|
|
5866
|
+
isUserZoomed = false;
|
|
5867
|
+
fitMode = "width";
|
|
5868
|
+
scale = calculateFitScale("width");
|
|
4866
5869
|
rotation = 0;
|
|
4867
5870
|
applyTransform();
|
|
4868
5871
|
},
|
|
@@ -5050,40 +6053,36 @@ var OpenDocumentPlugin = class {
|
|
|
5050
6053
|
const isPresentation = instance.isPresentation;
|
|
5051
6054
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5052
6055
|
const actions = [];
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
max
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
if (
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
instance.goToPage?.(page);
|
|
5081
|
-
} else if (typeof action === "number") {
|
|
5082
|
-
instance.goToPage?.(action);
|
|
5083
|
-
}
|
|
6056
|
+
actions.push({
|
|
6057
|
+
id: "thumbnails",
|
|
6058
|
+
icon: "thumbnails",
|
|
6059
|
+
label: isPresentation ? "Slide Thumbnails" : "Page Thumbnails",
|
|
6060
|
+
type: "button",
|
|
6061
|
+
group: "navigation",
|
|
6062
|
+
execute: () => instance.toggleThumbnails?.()
|
|
6063
|
+
});
|
|
6064
|
+
actions.push({
|
|
6065
|
+
id: "page-nav",
|
|
6066
|
+
icon: "",
|
|
6067
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
6068
|
+
type: "page-nav",
|
|
6069
|
+
group: "navigation",
|
|
6070
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
6071
|
+
max: totalPages,
|
|
6072
|
+
execute: (action, page) => {
|
|
6073
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
6074
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
6075
|
+
if (action === "prev") {
|
|
6076
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
6077
|
+
} else if (action === "next") {
|
|
6078
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
6079
|
+
} else if (typeof page === "number") {
|
|
6080
|
+
instance.goToPage?.(page);
|
|
6081
|
+
} else if (typeof action === "number") {
|
|
6082
|
+
instance.goToPage?.(action);
|
|
5084
6083
|
}
|
|
5085
|
-
}
|
|
5086
|
-
}
|
|
6084
|
+
}
|
|
6085
|
+
});
|
|
5087
6086
|
actions.push(
|
|
5088
6087
|
{
|
|
5089
6088
|
id: "zoom-out",
|
|
@@ -5174,49 +6173,65 @@ var OpenDocumentPlugin = class {
|
|
|
5174
6173
|
container.className = "fp-odf-container";
|
|
5175
6174
|
container.style.width = "100%";
|
|
5176
6175
|
container.style.height = "100%";
|
|
5177
|
-
container.style.
|
|
5178
|
-
container.style.
|
|
6176
|
+
container.style.overflowX = "hidden";
|
|
6177
|
+
container.style.overflowY = "auto";
|
|
6178
|
+
container.style.padding = "16px 8px";
|
|
5179
6179
|
container.style.backgroundColor = "#f1f5f9";
|
|
5180
6180
|
const wrapper = document.createElement("div");
|
|
5181
6181
|
wrapper.className = "fp-odf-wrapper";
|
|
5182
6182
|
wrapper.style.margin = "0 auto";
|
|
6183
|
+
wrapper.style.width = isPresentation ? "960px" : "816px";
|
|
6184
|
+
wrapper.style.boxSizing = "border-box";
|
|
5183
6185
|
wrapper.style.backgroundColor = "#ffffff";
|
|
5184
6186
|
wrapper.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
5185
6187
|
wrapper.style.borderRadius = "4px";
|
|
5186
6188
|
wrapper.style.transformOrigin = "top center";
|
|
5187
|
-
wrapper.style.transition = "transform 0.
|
|
6189
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5188
6190
|
container.appendChild(wrapper);
|
|
5189
6191
|
ctx.container.appendChild(container);
|
|
5190
6192
|
let scale = 1;
|
|
5191
6193
|
let rotation = 0;
|
|
5192
|
-
let
|
|
6194
|
+
let isUserZoomed = false;
|
|
6195
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6196
|
+
let currentPage = 1;
|
|
6197
|
+
let totalPages = 1;
|
|
6198
|
+
let slides = [];
|
|
5193
6199
|
const calculateFitScale = (mode = fitMode) => {
|
|
5194
|
-
const
|
|
5195
|
-
const
|
|
5196
|
-
const
|
|
5197
|
-
const
|
|
6200
|
+
const activeSlide = slides[currentPage - 1];
|
|
6201
|
+
const elW = isPresentation ? 960 : 816;
|
|
6202
|
+
const singlePageH = Math.min(activeSlide?.offsetHeight || wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
6203
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6204
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5198
6205
|
const sW = availW / elW;
|
|
5199
6206
|
const sH = availH / (isPresentation ? 540 : singlePageH);
|
|
5200
6207
|
if (isPresentation) {
|
|
5201
|
-
return Math.min(
|
|
6208
|
+
return Math.min(2.5, Math.min(sW, sH));
|
|
5202
6209
|
}
|
|
5203
6210
|
if (mode === "page") {
|
|
5204
|
-
return Math.max(0.
|
|
6211
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5205
6212
|
}
|
|
5206
|
-
return Math.max(0.
|
|
6213
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5207
6214
|
};
|
|
5208
6215
|
const applyTransform = () => {
|
|
5209
6216
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5210
6217
|
wrapper.style.transformOrigin = "top center";
|
|
6218
|
+
const activeSlide = slides[currentPage - 1];
|
|
6219
|
+
const baseH = activeSlide?.offsetHeight || wrapper.offsetHeight || 1056;
|
|
6220
|
+
const scaledH = baseH * scale;
|
|
6221
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6222
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
5211
6223
|
};
|
|
6224
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6225
|
+
if (!isUserZoomed) {
|
|
6226
|
+
scale = calculateFitScale(fitMode);
|
|
6227
|
+
applyTransform();
|
|
6228
|
+
}
|
|
6229
|
+
}) : null;
|
|
6230
|
+
resizeObserver?.observe(ctx.container);
|
|
5212
6231
|
setTimeout(() => {
|
|
5213
|
-
|
|
5214
|
-
scale = calculateFitScale("width");
|
|
6232
|
+
scale = calculateFitScale(fitMode);
|
|
5215
6233
|
applyTransform();
|
|
5216
6234
|
}, 60);
|
|
5217
|
-
let currentPage = 1;
|
|
5218
|
-
let totalPages = 1;
|
|
5219
|
-
let slides = [];
|
|
5220
6235
|
if (isPresentation) {
|
|
5221
6236
|
wrapper.style.maxWidth = "960px";
|
|
5222
6237
|
wrapper.style.aspectRatio = "16 / 9";
|
|
@@ -5317,24 +6332,9 @@ var OpenDocumentPlugin = class {
|
|
|
5317
6332
|
wrapper.appendChild(page);
|
|
5318
6333
|
slides.push(page);
|
|
5319
6334
|
});
|
|
5320
|
-
const pageIndicator = document.createElement("div");
|
|
5321
|
-
pageIndicator.className = "fp-odt-page-indicator";
|
|
5322
|
-
pageIndicator.style.position = "sticky";
|
|
5323
|
-
pageIndicator.style.bottom = "16px";
|
|
5324
|
-
pageIndicator.style.left = "50%";
|
|
5325
|
-
pageIndicator.style.transform = "translateX(-50%)";
|
|
5326
|
-
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
5327
|
-
pageIndicator.style.color = "#fff";
|
|
5328
|
-
pageIndicator.style.padding = "6px 12px";
|
|
5329
|
-
pageIndicator.style.borderRadius = "16px";
|
|
5330
|
-
pageIndicator.style.fontSize = "12px";
|
|
5331
|
-
pageIndicator.style.zIndex = "100";
|
|
5332
|
-
pageIndicator.style.display = "inline-block";
|
|
5333
|
-
pageIndicator.style.width = "fit-content";
|
|
5334
|
-
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
5335
|
-
container.appendChild(pageIndicator);
|
|
5336
6335
|
}
|
|
5337
6336
|
const cleanup = () => {
|
|
6337
|
+
resizeObserver?.disconnect();
|
|
5338
6338
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
5339
6339
|
container.remove();
|
|
5340
6340
|
ctx.container.innerHTML = "";
|
|
@@ -5346,10 +6346,6 @@ var OpenDocumentPlugin = class {
|
|
|
5346
6346
|
slides.forEach((s, idx) => {
|
|
5347
6347
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
5348
6348
|
});
|
|
5349
|
-
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
5350
|
-
if (indicator) {
|
|
5351
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5352
|
-
}
|
|
5353
6349
|
container.scrollTop = 0;
|
|
5354
6350
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5355
6351
|
};
|
|
@@ -5357,21 +6353,25 @@ var OpenDocumentPlugin = class {
|
|
|
5357
6353
|
destroy: cleanup,
|
|
5358
6354
|
isPresentation,
|
|
5359
6355
|
zoomIn: () => {
|
|
6356
|
+
isUserZoomed = true;
|
|
5360
6357
|
scale += 0.15;
|
|
5361
6358
|
applyTransform();
|
|
5362
6359
|
},
|
|
5363
6360
|
zoomOut: () => {
|
|
6361
|
+
isUserZoomed = true;
|
|
5364
6362
|
scale = Math.max(0.2, scale - 0.15);
|
|
5365
6363
|
applyTransform();
|
|
5366
6364
|
},
|
|
5367
6365
|
getZoom: () => scale,
|
|
5368
6366
|
setZoom: (level) => {
|
|
6367
|
+
isUserZoomed = true;
|
|
5369
6368
|
scale = level;
|
|
5370
6369
|
applyTransform();
|
|
5371
6370
|
},
|
|
5372
6371
|
fitToPage: () => {
|
|
5373
|
-
|
|
5374
|
-
|
|
6372
|
+
isUserZoomed = false;
|
|
6373
|
+
fitMode = "width";
|
|
6374
|
+
scale = calculateFitScale("width");
|
|
5375
6375
|
rotation = 0;
|
|
5376
6376
|
applyTransform();
|
|
5377
6377
|
},
|
|
@@ -5387,23 +6387,45 @@ var OpenDocumentPlugin = class {
|
|
|
5387
6387
|
getPageCount: () => totalPages,
|
|
5388
6388
|
getCurrentPage: () => currentPage,
|
|
5389
6389
|
getThumbnails: async () => {
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
canvas
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
6390
|
+
const count = totalPages || slides.length || 1;
|
|
6391
|
+
const items = [];
|
|
6392
|
+
for (let idx = 0; idx < count; idx++) {
|
|
6393
|
+
const itemIdx = idx;
|
|
6394
|
+
items.push({
|
|
6395
|
+
index: itemIdx,
|
|
6396
|
+
label: isPresentation ? `Slide ${itemIdx + 1}` : `Page ${itemIdx + 1}`,
|
|
6397
|
+
render: async (canvas) => {
|
|
6398
|
+
const ctx2d = canvas.getContext("2d");
|
|
6399
|
+
if (!ctx2d) return;
|
|
6400
|
+
if (isPresentation) {
|
|
6401
|
+
canvas.width = 160;
|
|
6402
|
+
canvas.height = 90;
|
|
6403
|
+
ctx2d.fillStyle = "#f8fafc";
|
|
6404
|
+
ctx2d.fillRect(0, 0, 160, 90);
|
|
6405
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6406
|
+
ctx2d.lineWidth = 1;
|
|
6407
|
+
ctx2d.strokeRect(0.5, 0.5, 159, 89);
|
|
6408
|
+
ctx2d.fillStyle = "#334155";
|
|
6409
|
+
ctx2d.font = "bold 11px sans-serif";
|
|
6410
|
+
ctx2d.textAlign = "center";
|
|
6411
|
+
ctx2d.fillText(`Slide ${itemIdx + 1}`, 80, 50);
|
|
6412
|
+
} else {
|
|
6413
|
+
canvas.width = 140;
|
|
6414
|
+
canvas.height = 180;
|
|
6415
|
+
ctx2d.fillStyle = "#ffffff";
|
|
6416
|
+
ctx2d.fillRect(0, 0, 140, 180);
|
|
6417
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6418
|
+
ctx2d.lineWidth = 1;
|
|
6419
|
+
ctx2d.strokeRect(0.5, 0.5, 139, 179);
|
|
6420
|
+
ctx2d.fillStyle = "#64748b";
|
|
6421
|
+
ctx2d.font = "bold 10px sans-serif";
|
|
6422
|
+
ctx2d.textAlign = "center";
|
|
6423
|
+
ctx2d.fillText(`Page ${itemIdx + 1}`, 70, 90);
|
|
6424
|
+
}
|
|
6425
|
+
}
|
|
6426
|
+
});
|
|
6427
|
+
}
|
|
6428
|
+
return items;
|
|
5407
6429
|
},
|
|
5408
6430
|
download: () => {
|
|
5409
6431
|
const mimeType = this.mimeTypes.find((m) => m.includes(ext.replace(".", ""))) || "application/octet-stream";
|
|
@@ -5508,23 +6530,24 @@ var OpenDocumentPlugin = class {
|
|
|
5508
6530
|
case "h": {
|
|
5509
6531
|
const level = Math.min(6, Math.max(1, Number(node.getAttribute("text:outline-level") || 1)));
|
|
5510
6532
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5511
|
-
html += `<h${level} style="${style}; font-family:
|
|
6533
|
+
html += `<h${level} style="${style}; margin: 18px 0 8px; color: #1e3a8a; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${node.textContent || ""}</h${level}>`;
|
|
5512
6534
|
break;
|
|
5513
6535
|
}
|
|
5514
6536
|
case "p": {
|
|
5515
6537
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5516
6538
|
const inner = this.renderSpans(node, styles, images);
|
|
5517
|
-
|
|
6539
|
+
const isInsideLi = node.parentElement?.localName === "list-item" || node.parentElement?.tagName?.toLowerCase() === "list-item";
|
|
6540
|
+
html += `<p style="${style}; line-height: 1.5; margin: ${isInsideLi ? "0" : "8px 0 12px"}; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${inner}</p>`;
|
|
5518
6541
|
break;
|
|
5519
6542
|
}
|
|
5520
6543
|
case "list": {
|
|
5521
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
6544
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
5522
6545
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5523
6546
|
html += "</ul>";
|
|
5524
6547
|
break;
|
|
5525
6548
|
}
|
|
5526
6549
|
case "list-item": {
|
|
5527
|
-
html +=
|
|
6550
|
+
html += '<li style="margin: 4px 0; font-size: 11pt; line-height: 1.5; color: #1e293b;">';
|
|
5528
6551
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5529
6552
|
html += "</li>";
|
|
5530
6553
|
break;
|
|
@@ -5650,28 +6673,26 @@ var DocPlugin = class {
|
|
|
5650
6673
|
getToolbarActions(instance) {
|
|
5651
6674
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5652
6675
|
const actions = [];
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
if (
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
instance.goToPage?.(page);
|
|
5671
|
-
}
|
|
6676
|
+
actions.push({
|
|
6677
|
+
id: "page-nav",
|
|
6678
|
+
icon: "",
|
|
6679
|
+
label: "Page Navigation",
|
|
6680
|
+
type: "page-nav",
|
|
6681
|
+
group: "navigation",
|
|
6682
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
6683
|
+
max: totalPages,
|
|
6684
|
+
execute: (action, page) => {
|
|
6685
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
6686
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
6687
|
+
if (action === "prev") {
|
|
6688
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
6689
|
+
} else if (action === "next") {
|
|
6690
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
6691
|
+
} else if (typeof page === "number") {
|
|
6692
|
+
instance.goToPage?.(page);
|
|
5672
6693
|
}
|
|
5673
|
-
}
|
|
5674
|
-
}
|
|
6694
|
+
}
|
|
6695
|
+
});
|
|
5675
6696
|
actions.push(
|
|
5676
6697
|
{
|
|
5677
6698
|
id: "zoom-out",
|
|
@@ -5745,8 +6766,9 @@ var DocPlugin = class {
|
|
|
5745
6766
|
container.className = "fp-doc-container";
|
|
5746
6767
|
container.style.width = "100%";
|
|
5747
6768
|
container.style.height = "100%";
|
|
5748
|
-
container.style.
|
|
5749
|
-
container.style.
|
|
6769
|
+
container.style.overflowX = "hidden";
|
|
6770
|
+
container.style.overflowY = "auto";
|
|
6771
|
+
container.style.padding = "16px 8px";
|
|
5750
6772
|
container.style.backgroundColor = "#f1f5f9";
|
|
5751
6773
|
container.style.display = "flex";
|
|
5752
6774
|
container.style.justifyContent = "center";
|
|
@@ -5791,16 +6813,15 @@ var DocPlugin = class {
|
|
|
5791
6813
|
const pageCard = document.createElement("div");
|
|
5792
6814
|
pageCard.className = "fp-doc-page-card";
|
|
5793
6815
|
pageCard.style.width = "816px";
|
|
5794
|
-
pageCard.style.
|
|
6816
|
+
pageCard.style.minHeight = "1056px";
|
|
5795
6817
|
pageCard.style.backgroundColor = "#ffffff";
|
|
5796
|
-
pageCard.style.boxShadow = "0
|
|
6818
|
+
pageCard.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
5797
6819
|
pageCard.style.borderRadius = "4px";
|
|
5798
|
-
pageCard.style.padding = "
|
|
6820
|
+
pageCard.style.padding = "72px 56px";
|
|
5799
6821
|
pageCard.style.boxSizing = "border-box";
|
|
5800
|
-
pageCard.style.overflow = "hidden";
|
|
5801
6822
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5802
6823
|
pageCard.style.transformOrigin = "top center";
|
|
5803
|
-
pageCard.style.transition = "transform 0.
|
|
6824
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
5804
6825
|
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5805
6826
|
pageCard.style.color = "#1e293b";
|
|
5806
6827
|
if (isFallback && i === 0) {
|
|
@@ -5817,34 +6838,15 @@ var DocPlugin = class {
|
|
|
5817
6838
|
container.appendChild(pageCard);
|
|
5818
6839
|
pageCards.push(pageCard);
|
|
5819
6840
|
}
|
|
5820
|
-
let indicator = null;
|
|
5821
|
-
if (totalPages > 1) {
|
|
5822
|
-
indicator = document.createElement("div");
|
|
5823
|
-
indicator.className = "fp-doc-page-indicator";
|
|
5824
|
-
indicator.style.position = "fixed";
|
|
5825
|
-
indicator.style.bottom = "16px";
|
|
5826
|
-
indicator.style.left = "50%";
|
|
5827
|
-
indicator.style.transform = "translateX(-50%)";
|
|
5828
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
5829
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
5830
|
-
indicator.style.color = "#f8fafc";
|
|
5831
|
-
indicator.style.fontSize = "12px";
|
|
5832
|
-
indicator.style.fontWeight = "600";
|
|
5833
|
-
indicator.style.padding = "5px 14px";
|
|
5834
|
-
indicator.style.borderRadius = "20px";
|
|
5835
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
5836
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
5837
|
-
indicator.style.zIndex = "10";
|
|
5838
|
-
indicator.style.userSelect = "none";
|
|
5839
|
-
indicator.style.pointerEvents = "none";
|
|
5840
|
-
indicator.style.textAlign = "center";
|
|
5841
|
-
container.appendChild(indicator);
|
|
5842
|
-
}
|
|
5843
6841
|
let rotation = 0;
|
|
5844
6842
|
const applyTransform = () => {
|
|
5845
6843
|
const activeCard = pageCards[currentPage - 1];
|
|
5846
6844
|
if (activeCard) {
|
|
5847
6845
|
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
6846
|
+
const baseH = activeCard.offsetHeight || 1056;
|
|
6847
|
+
const scaledH = baseH * scale;
|
|
6848
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6849
|
+
activeCard.style.marginBottom = `${extraH + 32}px`;
|
|
5848
6850
|
}
|
|
5849
6851
|
};
|
|
5850
6852
|
const showPage = (pageNum) => {
|
|
@@ -5857,35 +6859,39 @@ var DocPlugin = class {
|
|
|
5857
6859
|
card.style.display = "none";
|
|
5858
6860
|
}
|
|
5859
6861
|
});
|
|
5860
|
-
if (indicator) {
|
|
5861
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5862
|
-
}
|
|
5863
6862
|
container.scrollTop = 0;
|
|
5864
6863
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5865
6864
|
};
|
|
5866
6865
|
if (totalPages > 1) {
|
|
5867
6866
|
showPage(1);
|
|
5868
6867
|
}
|
|
5869
|
-
let fitMode = "width";
|
|
6868
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6869
|
+
let isUserZoomed = false;
|
|
5870
6870
|
const calculateFitScale = (mode = fitMode) => {
|
|
5871
6871
|
const elW = 816;
|
|
5872
6872
|
const elH = 1056;
|
|
5873
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
5874
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
6873
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6874
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5875
6875
|
const sW = availW / elW;
|
|
5876
6876
|
const sH = availH / elH;
|
|
5877
6877
|
if (mode === "page") {
|
|
5878
|
-
return Math.max(0.
|
|
6878
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5879
6879
|
}
|
|
5880
|
-
return Math.max(0.
|
|
6880
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5881
6881
|
};
|
|
6882
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6883
|
+
if (!isUserZoomed) {
|
|
6884
|
+
scale = calculateFitScale(fitMode);
|
|
6885
|
+
applyTransform();
|
|
6886
|
+
}
|
|
6887
|
+
}) : null;
|
|
6888
|
+
resizeObserver?.observe(ctx.container);
|
|
5882
6889
|
setTimeout(() => {
|
|
5883
|
-
|
|
5884
|
-
scale = calculateFitScale("width");
|
|
6890
|
+
scale = calculateFitScale(fitMode);
|
|
5885
6891
|
applyTransform();
|
|
5886
6892
|
}, 60);
|
|
5887
6893
|
const cleanup = () => {
|
|
5888
|
-
|
|
6894
|
+
resizeObserver?.disconnect();
|
|
5889
6895
|
container.remove();
|
|
5890
6896
|
ctx.container.innerHTML = "";
|
|
5891
6897
|
};
|
|
@@ -5896,21 +6902,25 @@ var DocPlugin = class {
|
|
|
5896
6902
|
getCurrentPage: () => currentPage,
|
|
5897
6903
|
goToPage: (page) => showPage(page),
|
|
5898
6904
|
zoomIn: () => {
|
|
6905
|
+
isUserZoomed = true;
|
|
5899
6906
|
scale += 0.15;
|
|
5900
6907
|
applyTransform();
|
|
5901
6908
|
},
|
|
5902
6909
|
zoomOut: () => {
|
|
6910
|
+
isUserZoomed = true;
|
|
5903
6911
|
scale = Math.max(0.2, scale - 0.15);
|
|
5904
6912
|
applyTransform();
|
|
5905
6913
|
},
|
|
5906
6914
|
getZoom: () => scale,
|
|
5907
6915
|
setZoom: (level) => {
|
|
6916
|
+
isUserZoomed = true;
|
|
5908
6917
|
scale = level;
|
|
5909
6918
|
applyTransform();
|
|
5910
6919
|
},
|
|
5911
6920
|
fitToPage: () => {
|
|
5912
|
-
|
|
5913
|
-
|
|
6921
|
+
isUserZoomed = false;
|
|
6922
|
+
fitMode = "width";
|
|
6923
|
+
scale = calculateFitScale("width");
|
|
5914
6924
|
rotation = 0;
|
|
5915
6925
|
applyTransform();
|
|
5916
6926
|
},
|
|
@@ -6287,25 +7297,31 @@ ${chartSvg}
|
|
|
6287
7297
|
i++;
|
|
6288
7298
|
continue;
|
|
6289
7299
|
}
|
|
6290
|
-
if (
|
|
7300
|
+
if (/^\d{1,2}$/.test(line.trim())) {
|
|
7301
|
+
i++;
|
|
7302
|
+
continue;
|
|
7303
|
+
}
|
|
7304
|
+
const isShortLine = line.length < 60 && !line.endsWith(".") && !line.endsWith(",");
|
|
7305
|
+
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));
|
|
7306
|
+
if (isTitleLike) {
|
|
6291
7307
|
if (inList) {
|
|
6292
7308
|
html += "</ul>";
|
|
6293
7309
|
inList = false;
|
|
6294
7310
|
}
|
|
6295
|
-
html += `<h2 style="font-size:
|
|
7311
|
+
html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 18px 0 10px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6.sanitize(line, sanitizeOptions)}</h2>`;
|
|
6296
7312
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
6297
7313
|
if (!inList) {
|
|
6298
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
7314
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
6299
7315
|
inList = true;
|
|
6300
7316
|
}
|
|
6301
7317
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
6302
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
7318
|
+
html += `<li style="margin: 4px 0; line-height: 1.5; font-size: 11pt; color: #1e293b;">${DOMPurify6.sanitize(bulletText, sanitizeOptions)}</li>`;
|
|
6303
7319
|
} else {
|
|
6304
7320
|
if (inList) {
|
|
6305
7321
|
html += "</ul>";
|
|
6306
7322
|
inList = false;
|
|
6307
7323
|
}
|
|
6308
|
-
html += `<p style="line-height: 1.
|
|
7324
|
+
html += `<p style="line-height: 1.5; margin: 0 0 12px 0; font-size: 11pt; color: #1e293b; text-align: justify;">${DOMPurify6.sanitize(line, sanitizeOptions)}</p>`;
|
|
6309
7325
|
}
|
|
6310
7326
|
i++;
|
|
6311
7327
|
}
|