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