@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/vue.cjs
CHANGED
|
@@ -527,8 +527,7 @@ var ICON_FULLSCREEN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="non
|
|
|
527
527
|
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>`;
|
|
528
528
|
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>`;
|
|
529
529
|
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>`;
|
|
530
|
-
var
|
|
531
|
-
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>`;
|
|
530
|
+
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>`;
|
|
532
531
|
var ICON_MAP = {
|
|
533
532
|
"zoom-in": ICON_ZOOM_IN,
|
|
534
533
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -555,28 +554,177 @@ var ICON_MAP = {
|
|
|
555
554
|
"forward-10": ICON_FAST_FORWARD,
|
|
556
555
|
"rewind": ICON_REWIND,
|
|
557
556
|
"replay-10": ICON_REWIND,
|
|
558
|
-
"speed": ICON_SPEED,
|
|
559
557
|
"open-window": ICON_EXTERNAL_WINDOW,
|
|
560
|
-
"external-window": ICON_EXTERNAL_WINDOW
|
|
558
|
+
"external-window": ICON_EXTERNAL_WINDOW,
|
|
559
|
+
"openWindow": ICON_EXTERNAL_WINDOW,
|
|
560
|
+
"openSeparateWindow": ICON_EXTERNAL_WINDOW
|
|
561
561
|
};
|
|
562
562
|
var ToolbarController = class {
|
|
563
563
|
el;
|
|
564
564
|
toolbarEl;
|
|
565
565
|
actions = [];
|
|
566
|
+
config = {};
|
|
566
567
|
pageInputEl = null;
|
|
567
568
|
pageLabelEl = null;
|
|
568
|
-
|
|
569
|
+
prevPageBtn = null;
|
|
570
|
+
nextPageBtn = null;
|
|
571
|
+
constructor(container, config) {
|
|
569
572
|
this.el = container;
|
|
573
|
+
if (config) this.config = { ...config };
|
|
570
574
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
571
575
|
this.el.appendChild(this.toolbarEl);
|
|
572
576
|
}
|
|
577
|
+
setConfig(config) {
|
|
578
|
+
this.config = { ...config };
|
|
579
|
+
this.render();
|
|
580
|
+
}
|
|
581
|
+
getConfig() {
|
|
582
|
+
return { ...this.config };
|
|
583
|
+
}
|
|
584
|
+
hideAction(actionId) {
|
|
585
|
+
this.config[actionId] = false;
|
|
586
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = false;
|
|
587
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = false;
|
|
588
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
589
|
+
this.config.fitPage = false;
|
|
590
|
+
this.config.fitToPage = false;
|
|
591
|
+
this.config.fitWidth = false;
|
|
592
|
+
}
|
|
593
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = false;
|
|
594
|
+
if (actionId === "fullscreen") this.config.fullscreen = false;
|
|
595
|
+
if (actionId === "download") this.config.download = false;
|
|
596
|
+
if (actionId === "print") this.config.print = false;
|
|
597
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
598
|
+
this.config.openWindow = false;
|
|
599
|
+
this.config.openSeparateWindow = false;
|
|
600
|
+
}
|
|
601
|
+
if (actionId === "copy") this.config.copy = false;
|
|
602
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
603
|
+
this.config.pageNav = false;
|
|
604
|
+
this.config.pagination = false;
|
|
605
|
+
}
|
|
606
|
+
this.render();
|
|
607
|
+
}
|
|
608
|
+
showAction(actionId) {
|
|
609
|
+
this.config[actionId] = true;
|
|
610
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = true;
|
|
611
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = true;
|
|
612
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
613
|
+
this.config.fitPage = true;
|
|
614
|
+
this.config.fitToPage = true;
|
|
615
|
+
this.config.fitWidth = true;
|
|
616
|
+
}
|
|
617
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = true;
|
|
618
|
+
if (actionId === "fullscreen") this.config.fullscreen = true;
|
|
619
|
+
if (actionId === "download") this.config.download = true;
|
|
620
|
+
if (actionId === "print") this.config.print = true;
|
|
621
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
622
|
+
this.config.openWindow = true;
|
|
623
|
+
this.config.openSeparateWindow = true;
|
|
624
|
+
}
|
|
625
|
+
if (actionId === "copy") this.config.copy = true;
|
|
626
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
627
|
+
this.config.pageNav = true;
|
|
628
|
+
this.config.pagination = true;
|
|
629
|
+
}
|
|
630
|
+
this.render();
|
|
631
|
+
}
|
|
632
|
+
normalizeActionId(actionId) {
|
|
633
|
+
if (actionId === "zoomIn") return "zoom-in";
|
|
634
|
+
if (actionId === "zoomOut") return "zoom-out";
|
|
635
|
+
if (actionId === "fitPage" || actionId === "fitToPage" || actionId === "fitWidth") return "fit-page";
|
|
636
|
+
if (actionId === "rotateCW") return "rotate-cw";
|
|
637
|
+
if (actionId === "rotateCCW") return "rotate-ccw";
|
|
638
|
+
if (actionId === "openWindow" || actionId === "openSeparateWindow") return "open-window";
|
|
639
|
+
if (actionId === "pageNav") return "page-nav";
|
|
640
|
+
return actionId;
|
|
641
|
+
}
|
|
642
|
+
enableAction(actionId) {
|
|
643
|
+
const norm = this.normalizeActionId(actionId);
|
|
644
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
645
|
+
if (btn) {
|
|
646
|
+
btn.disabled = false;
|
|
647
|
+
btn.classList.remove("disabled");
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
disableAction(actionId) {
|
|
651
|
+
const norm = this.normalizeActionId(actionId);
|
|
652
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
653
|
+
if (btn) {
|
|
654
|
+
btn.disabled = true;
|
|
655
|
+
btn.classList.add("disabled");
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
setActionActive(actionId, active) {
|
|
659
|
+
const norm = this.normalizeActionId(actionId);
|
|
660
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
661
|
+
if (btn) {
|
|
662
|
+
if (active) {
|
|
663
|
+
btn.classList.add("active");
|
|
664
|
+
} else {
|
|
665
|
+
btn.classList.remove("active");
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
isActionEnabled(action) {
|
|
670
|
+
const c = this.config;
|
|
671
|
+
const id = action.id;
|
|
672
|
+
if (c[id] === false) return false;
|
|
673
|
+
if (id === "zoom-in" && (c.zoomIn === false || c["zoom-in"] === false)) return false;
|
|
674
|
+
if (id === "zoom-out" && (c.zoomOut === false || c["zoom-out"] === false)) return false;
|
|
675
|
+
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)) {
|
|
676
|
+
return false;
|
|
677
|
+
}
|
|
678
|
+
if ((id === "rotate-cw" || id === "rotate-ccw" || id === "rotate") && (c.rotate === false || c.rotateCW === false || c.rotateCCW === false || c["rotate-cw"] === false)) {
|
|
679
|
+
return false;
|
|
680
|
+
}
|
|
681
|
+
if (id === "fullscreen" && c.fullscreen === false) return false;
|
|
682
|
+
if (id === "download" && c.download === false) return false;
|
|
683
|
+
if (id === "print" && c.print === false) return false;
|
|
684
|
+
if ((id === "open-window" || id === "external-window") && (c.openWindow === false || c.openSeparateWindow === false || c["open-window"] === false)) {
|
|
685
|
+
return false;
|
|
686
|
+
}
|
|
687
|
+
if (id === "copy" && c.copy === false) return false;
|
|
688
|
+
if (id === "thumbnails" && c.thumbnails === false) return false;
|
|
689
|
+
if (id === "page-nav" && (c.pageNav === false || c.pagination === false || c["page-nav"] === false)) {
|
|
690
|
+
return false;
|
|
691
|
+
}
|
|
692
|
+
if ((id === "prev" || id === "page-prev") && (c.prevPage === false || c.prev === false || c["prev"] === false || c.pageNav === false || c.pagination === false)) {
|
|
693
|
+
return false;
|
|
694
|
+
}
|
|
695
|
+
if ((id === "next" || id === "page-next") && (c.nextPage === false || c.next === false || c["next"] === false || c.pageNav === false || c.pagination === false)) {
|
|
696
|
+
return false;
|
|
697
|
+
}
|
|
698
|
+
if (id === "play" && c.play === false) return false;
|
|
699
|
+
if (id === "pause" && c.pause === false) return false;
|
|
700
|
+
if ((id === "fast-forward" || id === "forward-10") && (c.fastForward === false || c["fast-forward"] === false)) {
|
|
701
|
+
return false;
|
|
702
|
+
}
|
|
703
|
+
if ((id === "rewind" || id === "replay-10") && (c.rewind === false || c["rewind"] === false)) {
|
|
704
|
+
return false;
|
|
705
|
+
}
|
|
706
|
+
if (id === "speed" && c.speed === false) return false;
|
|
707
|
+
return true;
|
|
708
|
+
}
|
|
573
709
|
setPage(page, max) {
|
|
574
710
|
if (this.pageInputEl) {
|
|
575
711
|
this.pageInputEl.value = page.toString();
|
|
712
|
+
if (max !== void 0) {
|
|
713
|
+
this.pageInputEl.max = max.toString();
|
|
714
|
+
}
|
|
576
715
|
}
|
|
577
716
|
if (max !== void 0 && this.pageLabelEl) {
|
|
578
717
|
this.pageLabelEl.textContent = ` / ${max}`;
|
|
579
718
|
}
|
|
719
|
+
const currentMax = max !== void 0 ? max : parseInt(this.pageInputEl?.max || "1", 10) || 1;
|
|
720
|
+
if (this.prevPageBtn) {
|
|
721
|
+
this.prevPageBtn.disabled = page <= 1;
|
|
722
|
+
this.prevPageBtn.style.opacity = page <= 1 ? "0.4" : "1";
|
|
723
|
+
}
|
|
724
|
+
if (this.nextPageBtn) {
|
|
725
|
+
this.nextPageBtn.disabled = page >= currentMax;
|
|
726
|
+
this.nextPageBtn.style.opacity = page >= currentMax ? "0.4" : "1";
|
|
727
|
+
}
|
|
580
728
|
}
|
|
581
729
|
update(actions) {
|
|
582
730
|
this.actions = actions;
|
|
@@ -599,8 +747,9 @@ var ToolbarController = class {
|
|
|
599
747
|
view: [],
|
|
600
748
|
actions: []
|
|
601
749
|
};
|
|
602
|
-
const
|
|
603
|
-
const
|
|
750
|
+
const enabledActions = this.actions.filter((a) => this.isActionEnabled(a));
|
|
751
|
+
const hasPageNav = enabledActions.some((a) => a.type === "page-nav");
|
|
752
|
+
const effectiveActions = hasPageNav ? enabledActions.filter((a) => a.id !== "page-prev" && a.id !== "page-next" && a.id !== "prev" && a.id !== "next") : enabledActions;
|
|
604
753
|
for (const action of effectiveActions) {
|
|
605
754
|
if (groups[action.group]) {
|
|
606
755
|
groups[action.group].push(action);
|
|
@@ -660,6 +809,13 @@ var ToolbarController = class {
|
|
|
660
809
|
action.execute("go", val);
|
|
661
810
|
});
|
|
662
811
|
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
812
|
+
const curVal = action.value ?? 1;
|
|
813
|
+
prevBtn.disabled = curVal <= 1;
|
|
814
|
+
prevBtn.style.opacity = curVal <= 1 ? "0.4" : "1";
|
|
815
|
+
nextBtn.disabled = curVal >= max;
|
|
816
|
+
nextBtn.style.opacity = curVal >= max ? "0.4" : "1";
|
|
817
|
+
this.prevPageBtn = prevBtn;
|
|
818
|
+
this.nextPageBtn = nextBtn;
|
|
663
819
|
this.pageInputEl = input;
|
|
664
820
|
this.pageLabelEl = label;
|
|
665
821
|
groupEl.appendChild(prevBtn);
|
|
@@ -715,25 +871,63 @@ var ToolbarController = class {
|
|
|
715
871
|
var ThumbnailPanel = class {
|
|
716
872
|
el;
|
|
717
873
|
panelEl;
|
|
874
|
+
listEl;
|
|
875
|
+
headerEl;
|
|
718
876
|
thumbnails = [];
|
|
719
877
|
onSelect;
|
|
878
|
+
onToggleCallback;
|
|
720
879
|
activeIndex = 0;
|
|
721
|
-
|
|
880
|
+
observer;
|
|
881
|
+
renderedIndices = /* @__PURE__ */ new Set();
|
|
882
|
+
constructor(container, onToggle) {
|
|
722
883
|
this.el = container;
|
|
884
|
+
this.onToggleCallback = onToggle;
|
|
723
885
|
this.panelEl = createElement("div", { className: "fp-thumbnail-panel hidden" });
|
|
886
|
+
this.panelEl.style.width = "0px";
|
|
887
|
+
this.panelEl.style.minWidth = "0px";
|
|
888
|
+
this.panelEl.style.opacity = "0";
|
|
889
|
+
this.headerEl = createElement("div", { className: "fp-thumbnail-header" });
|
|
890
|
+
const title = createElement("span", { className: "fp-thumbnail-title" }, "Pages");
|
|
891
|
+
const closeBtn = createElement("button", {
|
|
892
|
+
className: "fp-thumbnail-close-btn",
|
|
893
|
+
title: "Close Thumbnails",
|
|
894
|
+
type: "button"
|
|
895
|
+
});
|
|
896
|
+
closeBtn.innerHTML = ICON_CLOSE;
|
|
897
|
+
closeBtn.addEventListener("click", (e) => {
|
|
898
|
+
e.stopPropagation();
|
|
899
|
+
this.hide();
|
|
900
|
+
});
|
|
901
|
+
this.headerEl.appendChild(title);
|
|
902
|
+
this.headerEl.appendChild(closeBtn);
|
|
903
|
+
this.listEl = createElement("div", { className: "fp-thumbnail-list" });
|
|
904
|
+
this.panelEl.appendChild(this.headerEl);
|
|
905
|
+
this.panelEl.appendChild(this.listEl);
|
|
724
906
|
this.el.appendChild(this.panelEl);
|
|
725
907
|
}
|
|
908
|
+
isOpen() {
|
|
909
|
+
return !this.panelEl.classList.contains("hidden") && this.panelEl.style.width !== "0px";
|
|
910
|
+
}
|
|
726
911
|
update(thumbnails, onSelect) {
|
|
727
912
|
this.thumbnails = thumbnails;
|
|
728
913
|
this.onSelect = onSelect;
|
|
914
|
+
this.renderedIndices.clear();
|
|
915
|
+
const titleEl = this.headerEl.querySelector(".fp-thumbnail-title");
|
|
916
|
+
if (titleEl) {
|
|
917
|
+
titleEl.textContent = `Pages (${thumbnails.length})`;
|
|
918
|
+
}
|
|
729
919
|
this.render();
|
|
920
|
+
if (this.isOpen()) {
|
|
921
|
+
this.renderAllVisible();
|
|
922
|
+
}
|
|
730
923
|
}
|
|
731
924
|
setActive(index) {
|
|
732
925
|
this.activeIndex = index;
|
|
733
|
-
const items = this.
|
|
926
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
734
927
|
items.forEach((item, i) => {
|
|
735
928
|
if (i === index) {
|
|
736
929
|
item.classList.add("active");
|
|
930
|
+
item.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
737
931
|
} else {
|
|
738
932
|
item.classList.remove("active");
|
|
739
933
|
}
|
|
@@ -741,37 +935,102 @@ var ThumbnailPanel = class {
|
|
|
741
935
|
}
|
|
742
936
|
show() {
|
|
743
937
|
this.panelEl.classList.remove("hidden");
|
|
938
|
+
this.panelEl.style.width = "200px";
|
|
939
|
+
this.panelEl.style.minWidth = "200px";
|
|
940
|
+
this.panelEl.style.opacity = "1";
|
|
941
|
+
this.panelEl.style.display = "flex";
|
|
942
|
+
this.onToggleCallback?.(true);
|
|
943
|
+
this.renderAllVisible();
|
|
744
944
|
}
|
|
745
945
|
hide() {
|
|
746
946
|
this.panelEl.classList.add("hidden");
|
|
947
|
+
this.panelEl.style.width = "0px";
|
|
948
|
+
this.panelEl.style.minWidth = "0px";
|
|
949
|
+
this.panelEl.style.opacity = "0";
|
|
950
|
+
this.onToggleCallback?.(false);
|
|
747
951
|
}
|
|
748
952
|
toggle() {
|
|
749
|
-
this.
|
|
953
|
+
if (this.isOpen()) {
|
|
954
|
+
this.hide();
|
|
955
|
+
} else {
|
|
956
|
+
this.show();
|
|
957
|
+
}
|
|
750
958
|
}
|
|
751
959
|
destroy() {
|
|
960
|
+
if (this.observer) {
|
|
961
|
+
this.observer.disconnect();
|
|
962
|
+
this.observer = void 0;
|
|
963
|
+
}
|
|
964
|
+
this.renderedIndices.clear();
|
|
752
965
|
this.el.innerHTML = "";
|
|
753
966
|
}
|
|
754
|
-
|
|
755
|
-
this.
|
|
967
|
+
renderAllVisible() {
|
|
968
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
969
|
+
items.forEach((item) => {
|
|
970
|
+
const idx = parseInt(item.dataset.thumbIndex || "-1", 10);
|
|
971
|
+
if (idx >= 0 && !this.renderedIndices.has(idx)) {
|
|
972
|
+
this.renderThumbnailItem(idx, item);
|
|
973
|
+
}
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
renderThumbnailItem(idx, itemEl) {
|
|
977
|
+
if (this.renderedIndices.has(idx)) return;
|
|
978
|
+
this.renderedIndices.add(idx);
|
|
979
|
+
const canvas = itemEl.querySelector("canvas");
|
|
980
|
+
const thumb = this.thumbnails[idx];
|
|
981
|
+
if (canvas && thumb) {
|
|
982
|
+
Promise.resolve(thumb.render(canvas)).catch((err) => {
|
|
983
|
+
console.warn(`[FilePreview] Error rendering thumbnail ${idx}:`, err);
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
render() {
|
|
988
|
+
if (this.observer) {
|
|
989
|
+
this.observer.disconnect();
|
|
990
|
+
}
|
|
991
|
+
this.listEl.innerHTML = "";
|
|
992
|
+
const useObserver = typeof IntersectionObserver !== "undefined";
|
|
993
|
+
if (useObserver) {
|
|
994
|
+
this.observer = new IntersectionObserver(
|
|
995
|
+
(entries) => {
|
|
996
|
+
for (const entry of entries) {
|
|
997
|
+
if (entry.isIntersecting) {
|
|
998
|
+
const target = entry.target;
|
|
999
|
+
const idx = parseInt(target.dataset.thumbIndex || "-1", 10);
|
|
1000
|
+
if (idx >= 0) {
|
|
1001
|
+
this.renderThumbnailItem(idx, target);
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
},
|
|
1006
|
+
{
|
|
1007
|
+
root: this.listEl,
|
|
1008
|
+
rootMargin: "120px 0px 120px 0px"
|
|
1009
|
+
}
|
|
1010
|
+
);
|
|
1011
|
+
}
|
|
756
1012
|
for (let i = 0; i < this.thumbnails.length; i++) {
|
|
757
1013
|
const thumb = this.thumbnails[i];
|
|
758
|
-
const itemEl = createElement("div", {
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
1014
|
+
const itemEl = createElement("div", {
|
|
1015
|
+
className: "fp-thumbnail-item" + (i === this.activeIndex ? " active" : "")
|
|
1016
|
+
});
|
|
1017
|
+
itemEl.dataset.thumbIndex = i.toString();
|
|
762
1018
|
itemEl.addEventListener("click", () => {
|
|
763
1019
|
this.setActive(i);
|
|
764
1020
|
this.onSelect?.(i);
|
|
765
1021
|
});
|
|
766
|
-
const
|
|
767
|
-
const
|
|
768
|
-
|
|
1022
|
+
const canvasWrapper = createElement("div", { className: "fp-thumbnail-canvas-wrapper" });
|
|
1023
|
+
const canvas = createElement("canvas", { width: "130", height: "170" });
|
|
1024
|
+
canvasWrapper.appendChild(canvas);
|
|
1025
|
+
const label = createElement("span", { className: "fp-thumbnail-label" }, thumb.label || `Page ${i + 1}`);
|
|
1026
|
+
itemEl.appendChild(canvasWrapper);
|
|
769
1027
|
itemEl.appendChild(label);
|
|
770
|
-
this.
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
}
|
|
774
|
-
|
|
1028
|
+
this.listEl.appendChild(itemEl);
|
|
1029
|
+
if (this.observer) {
|
|
1030
|
+
this.observer.observe(itemEl);
|
|
1031
|
+
}
|
|
1032
|
+
if (i < 4) {
|
|
1033
|
+
this.renderThumbnailItem(i, itemEl);
|
|
775
1034
|
}
|
|
776
1035
|
}
|
|
777
1036
|
}
|
|
@@ -792,6 +1051,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
792
1051
|
currentOptions = {};
|
|
793
1052
|
resizeObserver = null;
|
|
794
1053
|
fullscreenHandler = null;
|
|
1054
|
+
titleBarEl = null;
|
|
795
1055
|
/**
|
|
796
1056
|
* Register a preview plugin.
|
|
797
1057
|
*/
|
|
@@ -828,6 +1088,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
828
1088
|
}
|
|
829
1089
|
this.currentBuffer = buffer.slice(0);
|
|
830
1090
|
this.currentMetadata = metadata;
|
|
1091
|
+
this.updateTitleBar(options, metadata);
|
|
831
1092
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
832
1093
|
const fileInfo = { metadata, buffer };
|
|
833
1094
|
const matchedPlugin = await this.findPlugin(fileInfo);
|
|
@@ -851,15 +1112,21 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
851
1112
|
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
852
1113
|
const total = payload.total ?? payload.totalPages;
|
|
853
1114
|
this.toolbar?.setPage(payload.page, total);
|
|
1115
|
+
this.thumbnailPanel?.setActive(payload.page - 1);
|
|
854
1116
|
}
|
|
855
1117
|
this.eventEmitter.emit(event, payload);
|
|
856
|
-
}
|
|
1118
|
+
},
|
|
1119
|
+
toggleThumbnails: () => this.toggleThumbnails()
|
|
857
1120
|
});
|
|
858
1121
|
this.activeInstance = instance;
|
|
859
1122
|
instance.openInSeparateWindow = () => this.openInSeparateWindow();
|
|
1123
|
+
instance.toggleThumbnails = () => this.toggleThumbnails();
|
|
860
1124
|
this.hideLoading();
|
|
861
1125
|
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
862
|
-
|
|
1126
|
+
const isToolbarVisible = options.showToolbar !== false && options.toolbar !== false;
|
|
1127
|
+
if (isToolbarVisible && this.toolbar) {
|
|
1128
|
+
const toolbarConfig = this.extractToolbarConfig(options);
|
|
1129
|
+
this.toolbar.setConfig(toolbarConfig);
|
|
863
1130
|
const actions = matchedPlugin.getToolbarActions(instance);
|
|
864
1131
|
const hasFullscreen = actions.some((a) => a.id === "fullscreen");
|
|
865
1132
|
if (!hasFullscreen && this.wrapperEl) {
|
|
@@ -909,6 +1176,12 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
909
1176
|
}
|
|
910
1177
|
});
|
|
911
1178
|
}
|
|
1179
|
+
const thumbAction = actions.find((a) => a.id === "thumbnails");
|
|
1180
|
+
if (thumbAction) {
|
|
1181
|
+
thumbAction.execute = () => {
|
|
1182
|
+
this.toggleThumbnails();
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
912
1185
|
this.toolbar.update(actions);
|
|
913
1186
|
this.toolbar.show();
|
|
914
1187
|
}
|
|
@@ -993,7 +1266,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
993
1266
|
if (targetUrl) {
|
|
994
1267
|
const newWin2 = window.open(targetUrl, "_blank");
|
|
995
1268
|
if (!newWin2) {
|
|
996
|
-
|
|
1269
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
997
1270
|
return null;
|
|
998
1271
|
}
|
|
999
1272
|
return newWin2;
|
|
@@ -1001,7 +1274,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1001
1274
|
const title = (this.currentMetadata?.name || "Document Preview") + " - Full Preview";
|
|
1002
1275
|
const newWin = window.open("", "_blank");
|
|
1003
1276
|
if (!newWin) {
|
|
1004
|
-
|
|
1277
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
1005
1278
|
return null;
|
|
1006
1279
|
}
|
|
1007
1280
|
newWin.document.title = title;
|
|
@@ -1078,6 +1351,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1078
1351
|
this.currentBuffer = null;
|
|
1079
1352
|
this.currentMetadata = null;
|
|
1080
1353
|
this.currentContainer = null;
|
|
1354
|
+
this.titleBarEl = null;
|
|
1081
1355
|
}
|
|
1082
1356
|
/**
|
|
1083
1357
|
* Get the currently active preview instance.
|
|
@@ -1085,7 +1359,218 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1085
1359
|
getInstance() {
|
|
1086
1360
|
return this.activeInstance;
|
|
1087
1361
|
}
|
|
1362
|
+
// --- Toolbar Configuration & Feature Toggles ---
|
|
1363
|
+
/**
|
|
1364
|
+
* Configure toolbar features dynamically through options or methods.
|
|
1365
|
+
* e.g. viewer.setToolbarConfig({ zoomIn: false, print: false })
|
|
1366
|
+
*/
|
|
1367
|
+
setToolbarConfig(config) {
|
|
1368
|
+
this.toolbar?.setConfig(config);
|
|
1369
|
+
}
|
|
1370
|
+
/**
|
|
1371
|
+
* Get current toolbar configuration.
|
|
1372
|
+
*/
|
|
1373
|
+
getToolbarConfig() {
|
|
1374
|
+
return this.toolbar?.getConfig() ?? {};
|
|
1375
|
+
}
|
|
1376
|
+
/**
|
|
1377
|
+
* Hide a specific toolbar action by ID or alias (e.g. 'zoom-in', 'print', 'download').
|
|
1378
|
+
*/
|
|
1379
|
+
hideToolbarAction(actionId) {
|
|
1380
|
+
this.toolbar?.hideAction(actionId);
|
|
1381
|
+
}
|
|
1382
|
+
/**
|
|
1383
|
+
* Show a specific toolbar action by ID or alias.
|
|
1384
|
+
*/
|
|
1385
|
+
showToolbarAction(actionId) {
|
|
1386
|
+
this.toolbar?.showAction(actionId);
|
|
1387
|
+
}
|
|
1388
|
+
/**
|
|
1389
|
+
* Enable a specific toolbar action button.
|
|
1390
|
+
*/
|
|
1391
|
+
enableToolbarAction(actionId) {
|
|
1392
|
+
this.toolbar?.enableAction(actionId);
|
|
1393
|
+
}
|
|
1394
|
+
/**
|
|
1395
|
+
* Disable a specific toolbar action button.
|
|
1396
|
+
*/
|
|
1397
|
+
disableToolbarAction(actionId) {
|
|
1398
|
+
this.toolbar?.disableAction(actionId);
|
|
1399
|
+
}
|
|
1400
|
+
// --- Programmatic Toolbar Action Methods ---
|
|
1401
|
+
/**
|
|
1402
|
+
* Fit document to page so it fills the frame width with minimal margins.
|
|
1403
|
+
*/
|
|
1404
|
+
fitToPage() {
|
|
1405
|
+
this.activeInstance?.fitToPage?.();
|
|
1406
|
+
}
|
|
1407
|
+
/**
|
|
1408
|
+
* Zoom in.
|
|
1409
|
+
*/
|
|
1410
|
+
zoomIn() {
|
|
1411
|
+
this.activeInstance?.zoomIn?.();
|
|
1412
|
+
}
|
|
1413
|
+
/**
|
|
1414
|
+
* Zoom out.
|
|
1415
|
+
*/
|
|
1416
|
+
zoomOut() {
|
|
1417
|
+
this.activeInstance?.zoomOut?.();
|
|
1418
|
+
}
|
|
1419
|
+
/**
|
|
1420
|
+
* Set specific zoom level.
|
|
1421
|
+
*/
|
|
1422
|
+
setZoom(level) {
|
|
1423
|
+
this.activeInstance?.setZoom?.(level);
|
|
1424
|
+
}
|
|
1425
|
+
/**
|
|
1426
|
+
* Get current zoom level.
|
|
1427
|
+
*/
|
|
1428
|
+
getZoom() {
|
|
1429
|
+
return this.activeInstance?.getZoom?.() ?? 1;
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* Rotate 90 degrees clockwise.
|
|
1433
|
+
*/
|
|
1434
|
+
rotateCW() {
|
|
1435
|
+
this.activeInstance?.rotateCW?.();
|
|
1436
|
+
}
|
|
1437
|
+
/**
|
|
1438
|
+
* Rotate 90 degrees counter-clockwise.
|
|
1439
|
+
*/
|
|
1440
|
+
rotateCCW() {
|
|
1441
|
+
this.activeInstance?.rotateCCW?.();
|
|
1442
|
+
}
|
|
1443
|
+
/**
|
|
1444
|
+
* Navigate to a specific page number.
|
|
1445
|
+
*/
|
|
1446
|
+
goToPage(page) {
|
|
1447
|
+
this.activeInstance?.goToPage?.(page);
|
|
1448
|
+
this.toolbar?.setPage(page);
|
|
1449
|
+
}
|
|
1450
|
+
/**
|
|
1451
|
+
* Navigate to next page.
|
|
1452
|
+
*/
|
|
1453
|
+
nextPage() {
|
|
1454
|
+
const cur = this.getCurrentPage();
|
|
1455
|
+
const max = this.getPageCount();
|
|
1456
|
+
if (cur < max) {
|
|
1457
|
+
this.goToPage(cur + 1);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
/**
|
|
1461
|
+
* Navigate to previous page.
|
|
1462
|
+
*/
|
|
1463
|
+
prevPage() {
|
|
1464
|
+
const cur = this.getCurrentPage();
|
|
1465
|
+
if (cur > 1) {
|
|
1466
|
+
this.goToPage(cur - 1);
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
/**
|
|
1470
|
+
* Get total page count.
|
|
1471
|
+
*/
|
|
1472
|
+
getPageCount() {
|
|
1473
|
+
return this.activeInstance?.getPageCount?.() ?? 1;
|
|
1474
|
+
}
|
|
1475
|
+
/**
|
|
1476
|
+
* Get current page number.
|
|
1477
|
+
*/
|
|
1478
|
+
getCurrentPage() {
|
|
1479
|
+
return this.activeInstance?.getCurrentPage?.() ?? 1;
|
|
1480
|
+
}
|
|
1481
|
+
/**
|
|
1482
|
+
* Download the current document.
|
|
1483
|
+
*/
|
|
1484
|
+
download() {
|
|
1485
|
+
this.activeInstance?.download?.();
|
|
1486
|
+
}
|
|
1487
|
+
/**
|
|
1488
|
+
* Print the current document.
|
|
1489
|
+
*/
|
|
1490
|
+
print() {
|
|
1491
|
+
this.activeInstance?.print?.();
|
|
1492
|
+
}
|
|
1493
|
+
/**
|
|
1494
|
+
* Toggle fullscreen mode.
|
|
1495
|
+
*/
|
|
1496
|
+
toggleFullscreen() {
|
|
1497
|
+
try {
|
|
1498
|
+
if (!document.fullscreenElement) {
|
|
1499
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
1500
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
1501
|
+
} else {
|
|
1502
|
+
document.exitFullscreen?.();
|
|
1503
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
1504
|
+
}
|
|
1505
|
+
} catch {
|
|
1506
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
1507
|
+
}
|
|
1508
|
+
setTimeout(() => {
|
|
1509
|
+
this.activeInstance?.fitToPage?.();
|
|
1510
|
+
}, 120);
|
|
1511
|
+
}
|
|
1512
|
+
/**
|
|
1513
|
+
* Toggle thumbnails sidebar panel.
|
|
1514
|
+
*/
|
|
1515
|
+
toggleThumbnails() {
|
|
1516
|
+
if (!this.thumbnailPanel) return;
|
|
1517
|
+
this.thumbnailPanel.toggle();
|
|
1518
|
+
const isOpen = this.thumbnailPanel.isOpen();
|
|
1519
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1520
|
+
setTimeout(() => {
|
|
1521
|
+
this.activeInstance?.fitToPage?.();
|
|
1522
|
+
}, 260);
|
|
1523
|
+
}
|
|
1524
|
+
/**
|
|
1525
|
+
* Set whether to display the file name / title bar above the toolbar.
|
|
1526
|
+
*/
|
|
1527
|
+
setShowFileName(show) {
|
|
1528
|
+
if (this.currentOptions) {
|
|
1529
|
+
this.currentOptions.showFileName = show;
|
|
1530
|
+
}
|
|
1531
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1532
|
+
}
|
|
1533
|
+
/**
|
|
1534
|
+
* Set or override the displayed file name in the preview panel.
|
|
1535
|
+
*/
|
|
1536
|
+
setFileName(name) {
|
|
1537
|
+
if (this.currentOptions) {
|
|
1538
|
+
this.currentOptions.fileName = name;
|
|
1539
|
+
}
|
|
1540
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1541
|
+
}
|
|
1088
1542
|
// --- Private methods ---
|
|
1543
|
+
updateTitleBar(options, metadata) {
|
|
1544
|
+
if (!this.titleBarEl) return;
|
|
1545
|
+
const show = options?.showFileName !== false;
|
|
1546
|
+
if (!show) {
|
|
1547
|
+
this.titleBarEl.style.display = "none";
|
|
1548
|
+
return;
|
|
1549
|
+
}
|
|
1550
|
+
const name = options?.fileName || metadata?.name || this.currentMetadata?.name || "";
|
|
1551
|
+
if (!name) {
|
|
1552
|
+
this.titleBarEl.style.display = "none";
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1555
|
+
this.titleBarEl.style.display = "flex";
|
|
1556
|
+
const ext = metadata?.extension || (name.includes(".") ? "." + name.split(".").pop() : "");
|
|
1557
|
+
const badge = ext ? ext.replace(".", "").toUpperCase() : "";
|
|
1558
|
+
this.titleBarEl.innerHTML = `
|
|
1559
|
+
<div class="fp-titlebar-info">
|
|
1560
|
+
<span class="fp-titlebar-icon">\u{1F4C4}</span>
|
|
1561
|
+
<span class="fp-titlebar-name" title="${name}">${name}</span>
|
|
1562
|
+
${badge ? `<span class="fp-titlebar-badge">${badge}</span>` : ""}
|
|
1563
|
+
</div>
|
|
1564
|
+
`;
|
|
1565
|
+
}
|
|
1566
|
+
extractToolbarConfig(options) {
|
|
1567
|
+
if (!options) return {};
|
|
1568
|
+
const nested = typeof options.toolbar === "object" ? options.toolbar : {};
|
|
1569
|
+
return {
|
|
1570
|
+
...options,
|
|
1571
|
+
...nested
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1089
1574
|
abort() {
|
|
1090
1575
|
if (this.abortController) {
|
|
1091
1576
|
this.abortController.abort();
|
|
@@ -1128,17 +1613,29 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1128
1613
|
bodyEl.className = "fp-body";
|
|
1129
1614
|
bodyEl.appendChild(thumbnailEl);
|
|
1130
1615
|
bodyEl.appendChild(this.contentEl);
|
|
1616
|
+
const titleBarEl = document.createElement("div");
|
|
1617
|
+
titleBarEl.className = "fp-titlebar";
|
|
1618
|
+
this.titleBarEl = titleBarEl;
|
|
1619
|
+
this.updateTitleBar(options, this.currentMetadata);
|
|
1131
1620
|
if (toolbarPos === "top") {
|
|
1621
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1132
1622
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1133
1623
|
this.wrapperEl.appendChild(bodyEl);
|
|
1134
1624
|
} else {
|
|
1625
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1135
1626
|
this.wrapperEl.appendChild(bodyEl);
|
|
1136
1627
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1137
1628
|
}
|
|
1138
1629
|
container.innerHTML = "";
|
|
1139
1630
|
container.appendChild(this.wrapperEl);
|
|
1140
|
-
|
|
1141
|
-
this.
|
|
1631
|
+
const initialToolbarConfig = this.extractToolbarConfig(options);
|
|
1632
|
+
this.toolbar = new ToolbarController(toolbarEl, initialToolbarConfig);
|
|
1633
|
+
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl, (isOpen) => {
|
|
1634
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1635
|
+
setTimeout(() => {
|
|
1636
|
+
this.activeInstance?.fitToPage?.();
|
|
1637
|
+
}, 260);
|
|
1638
|
+
});
|
|
1142
1639
|
this.setupKeyboardShortcuts();
|
|
1143
1640
|
this.setupDragAndDrop(container, options);
|
|
1144
1641
|
this.setupResizeAndFullscreenListeners();
|
|
@@ -1528,6 +2025,14 @@ var PdfPlugin = class {
|
|
|
1528
2025
|
group: "zoom",
|
|
1529
2026
|
execute: () => instance.fitToPage?.()
|
|
1530
2027
|
},
|
|
2028
|
+
{
|
|
2029
|
+
id: "fit-width",
|
|
2030
|
+
icon: "fit-width",
|
|
2031
|
+
label: "Fit to Width",
|
|
2032
|
+
type: "button",
|
|
2033
|
+
group: "zoom",
|
|
2034
|
+
execute: () => instance.fitToWidth?.()
|
|
2035
|
+
},
|
|
1531
2036
|
{
|
|
1532
2037
|
id: "rotate-cw",
|
|
1533
2038
|
icon: "rotate-cw",
|
|
@@ -1536,6 +2041,14 @@ var PdfPlugin = class {
|
|
|
1536
2041
|
group: "view",
|
|
1537
2042
|
execute: () => instance.rotateCW?.()
|
|
1538
2043
|
},
|
|
2044
|
+
{
|
|
2045
|
+
id: "rotate-ccw",
|
|
2046
|
+
icon: "rotate-ccw",
|
|
2047
|
+
label: "Rotate Counter-Clockwise",
|
|
2048
|
+
type: "button",
|
|
2049
|
+
group: "view",
|
|
2050
|
+
execute: () => instance.rotateCCW?.()
|
|
2051
|
+
},
|
|
1539
2052
|
{
|
|
1540
2053
|
id: "download",
|
|
1541
2054
|
icon: "download",
|
|
@@ -1567,12 +2080,13 @@ var PdfPlugin = class {
|
|
|
1567
2080
|
container.className = "fp-pdf-container";
|
|
1568
2081
|
container.style.width = "100%";
|
|
1569
2082
|
container.style.height = "100%";
|
|
1570
|
-
container.style.
|
|
2083
|
+
container.style.overflowX = "hidden";
|
|
2084
|
+
container.style.overflowY = "auto";
|
|
1571
2085
|
container.style.display = "flex";
|
|
1572
2086
|
container.style.flexDirection = "column";
|
|
1573
2087
|
container.style.alignItems = "center";
|
|
1574
2088
|
container.style.justifyContent = "flex-start";
|
|
1575
|
-
container.style.padding = "
|
|
2089
|
+
container.style.padding = "16px 8px";
|
|
1576
2090
|
container.style.backgroundColor = "#0f172a";
|
|
1577
2091
|
container.style.boxSizing = "border-box";
|
|
1578
2092
|
container.style.position = "relative";
|
|
@@ -1583,30 +2097,12 @@ var PdfPlugin = class {
|
|
|
1583
2097
|
pageCard.style.borderRadius = "4px";
|
|
1584
2098
|
pageCard.style.overflow = "hidden";
|
|
1585
2099
|
pageCard.style.lineHeight = "0";
|
|
1586
|
-
pageCard.style.transition = "transform 0.15s ease";
|
|
1587
2100
|
pageCard.style.position = "relative";
|
|
1588
2101
|
pageCard.style.flexShrink = "0";
|
|
2102
|
+
pageCard.style.transition = "box-shadow 0.2s ease";
|
|
1589
2103
|
let canvas = document.createElement("canvas");
|
|
1590
2104
|
pageCard.appendChild(canvas);
|
|
1591
2105
|
container.appendChild(pageCard);
|
|
1592
|
-
const indicator = document.createElement("div");
|
|
1593
|
-
indicator.className = "fp-pdf-page-indicator";
|
|
1594
|
-
indicator.style.position = "sticky";
|
|
1595
|
-
indicator.style.bottom = "16px";
|
|
1596
|
-
indicator.style.marginTop = "16px";
|
|
1597
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1598
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
1599
|
-
indicator.style.color = "#f8fafc";
|
|
1600
|
-
indicator.style.fontSize = "12px";
|
|
1601
|
-
indicator.style.fontWeight = "600";
|
|
1602
|
-
indicator.style.padding = "5px 14px";
|
|
1603
|
-
indicator.style.borderRadius = "20px";
|
|
1604
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1605
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1606
|
-
indicator.style.zIndex = "10";
|
|
1607
|
-
indicator.style.userSelect = "none";
|
|
1608
|
-
indicator.style.pointerEvents = "none";
|
|
1609
|
-
container.appendChild(indicator);
|
|
1610
2106
|
ctx.container.appendChild(container);
|
|
1611
2107
|
const standardFontsUrl = typeof window !== "undefined" && window.__PDF_STANDARD_FONTS_URL__ || "./standard_fonts/";
|
|
1612
2108
|
const cmapsUrl = typeof window !== "undefined" && window.__PDF_CMAPS_URL__ || "./cmaps/";
|
|
@@ -1622,8 +2118,9 @@ var PdfPlugin = class {
|
|
|
1622
2118
|
let currentPage = 1;
|
|
1623
2119
|
let zoomScale = 1;
|
|
1624
2120
|
let rotation = 0;
|
|
1625
|
-
let fitMode = "
|
|
2121
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
1626
2122
|
let currentRenderTask = null;
|
|
2123
|
+
let textLayerDiv = null;
|
|
1627
2124
|
const renderPage = async (pageNum) => {
|
|
1628
2125
|
if (currentRenderTask) {
|
|
1629
2126
|
try {
|
|
@@ -1635,30 +2132,37 @@ var PdfPlugin = class {
|
|
|
1635
2132
|
const newCanvas = document.createElement("canvas");
|
|
1636
2133
|
pageCard.replaceChild(newCanvas, canvas);
|
|
1637
2134
|
canvas = newCanvas;
|
|
2135
|
+
if (textLayerDiv) {
|
|
2136
|
+
textLayerDiv.remove();
|
|
2137
|
+
textLayerDiv = null;
|
|
2138
|
+
}
|
|
1638
2139
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1639
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1640
2140
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1641
2141
|
const page = await pdfDoc.getPage(currentPage);
|
|
1642
2142
|
const containerWidth = container.clientWidth || 900;
|
|
1643
2143
|
const containerHeight = container.clientHeight || 700;
|
|
1644
2144
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1645
|
-
const availWidth = Math.max(
|
|
1646
|
-
const availHeight = Math.max(
|
|
2145
|
+
const availWidth = Math.max(280, containerWidth - 36);
|
|
2146
|
+
const availHeight = Math.max(280, containerHeight - 32);
|
|
1647
2147
|
const scaleW = availWidth / unscaledVp.width;
|
|
1648
2148
|
const scaleH = availHeight / unscaledVp.height;
|
|
1649
2149
|
let fitScale;
|
|
1650
2150
|
if (fitMode === "page") {
|
|
1651
|
-
fitScale = Math.max(0.4, Math.min(scaleW, scaleH));
|
|
2151
|
+
fitScale = Math.max(0.2, Math.min(4, Math.min(scaleW, scaleH)));
|
|
1652
2152
|
} else {
|
|
1653
|
-
fitScale = Math.max(0.
|
|
2153
|
+
fitScale = Math.max(0.2, Math.min(4, scaleW));
|
|
1654
2154
|
}
|
|
1655
2155
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1656
2156
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1657
2157
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
2158
|
+
const displayWidth = Math.floor(viewport.width);
|
|
2159
|
+
const displayHeight = Math.floor(viewport.height);
|
|
1658
2160
|
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1659
2161
|
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1660
|
-
canvas.style.width = `${
|
|
1661
|
-
canvas.style.height = `${
|
|
2162
|
+
canvas.style.width = `${displayWidth}px`;
|
|
2163
|
+
canvas.style.height = `${displayHeight}px`;
|
|
2164
|
+
pageCard.style.width = `${displayWidth}px`;
|
|
2165
|
+
pageCard.style.height = `${displayHeight}px`;
|
|
1662
2166
|
const canvasCtx = canvas.getContext("2d");
|
|
1663
2167
|
if (!canvasCtx) return;
|
|
1664
2168
|
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
@@ -1672,9 +2176,31 @@ var PdfPlugin = class {
|
|
|
1672
2176
|
if (err?.name !== "RenderingCancelledException") {
|
|
1673
2177
|
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1674
2178
|
}
|
|
2179
|
+
return;
|
|
1675
2180
|
} finally {
|
|
1676
2181
|
currentRenderTask = null;
|
|
1677
2182
|
}
|
|
2183
|
+
try {
|
|
2184
|
+
textLayerDiv = document.createElement("div");
|
|
2185
|
+
textLayerDiv.className = "textLayer";
|
|
2186
|
+
textLayerDiv.style.width = `${displayWidth}px`;
|
|
2187
|
+
textLayerDiv.style.height = `${displayHeight}px`;
|
|
2188
|
+
textLayerDiv.style.position = "absolute";
|
|
2189
|
+
textLayerDiv.style.top = "0";
|
|
2190
|
+
textLayerDiv.style.left = "0";
|
|
2191
|
+
textLayerDiv.style.lineHeight = "1";
|
|
2192
|
+
pageCard.appendChild(textLayerDiv);
|
|
2193
|
+
if (pdfjsLib__namespace.TextLayer) {
|
|
2194
|
+
const textLayer = new pdfjsLib__namespace.TextLayer({
|
|
2195
|
+
textContentSource: page.streamTextContent(),
|
|
2196
|
+
container: textLayerDiv,
|
|
2197
|
+
viewport
|
|
2198
|
+
});
|
|
2199
|
+
await textLayer.render();
|
|
2200
|
+
}
|
|
2201
|
+
} catch (err) {
|
|
2202
|
+
console.debug("[PdfPlugin] TextLayer notice:", err);
|
|
2203
|
+
}
|
|
1678
2204
|
};
|
|
1679
2205
|
renderPage(1);
|
|
1680
2206
|
let resizeTimer = null;
|
|
@@ -1684,11 +2210,48 @@ var PdfPlugin = class {
|
|
|
1684
2210
|
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1685
2211
|
renderPage(currentPage);
|
|
1686
2212
|
}
|
|
1687
|
-
},
|
|
2213
|
+
}, 120);
|
|
1688
2214
|
});
|
|
1689
2215
|
resizeObserver.observe(container);
|
|
2216
|
+
const onWheel = (e) => {
|
|
2217
|
+
if (e.ctrlKey || e.metaKey) {
|
|
2218
|
+
e.preventDefault();
|
|
2219
|
+
const delta = e.deltaY > 0 ? -0.15 : 0.15;
|
|
2220
|
+
zoomScale = Math.max(0.25, Math.min(4, Math.round((zoomScale + delta) * 100) / 100));
|
|
2221
|
+
renderPage(currentPage);
|
|
2222
|
+
}
|
|
2223
|
+
};
|
|
2224
|
+
container.addEventListener("wheel", onWheel, { passive: false });
|
|
2225
|
+
const onKeyDown = (e) => {
|
|
2226
|
+
const tag = e.target?.tagName?.toLowerCase();
|
|
2227
|
+
if (tag === "input" || tag === "textarea" || tag === "select") return;
|
|
2228
|
+
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
2229
|
+
if (currentPage < totalPages) {
|
|
2230
|
+
e.preventDefault();
|
|
2231
|
+
container.scrollTop = 0;
|
|
2232
|
+
renderPage(currentPage + 1);
|
|
2233
|
+
}
|
|
2234
|
+
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
2235
|
+
if (currentPage > 1) {
|
|
2236
|
+
e.preventDefault();
|
|
2237
|
+
container.scrollTop = 0;
|
|
2238
|
+
renderPage(currentPage - 1);
|
|
2239
|
+
}
|
|
2240
|
+
} else if (e.key === "Home") {
|
|
2241
|
+
e.preventDefault();
|
|
2242
|
+
container.scrollTop = 0;
|
|
2243
|
+
renderPage(1);
|
|
2244
|
+
} else if (e.key === "End") {
|
|
2245
|
+
e.preventDefault();
|
|
2246
|
+
container.scrollTop = 0;
|
|
2247
|
+
renderPage(totalPages);
|
|
2248
|
+
}
|
|
2249
|
+
};
|
|
2250
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1690
2251
|
const cleanup = () => {
|
|
1691
2252
|
resizeObserver.disconnect();
|
|
2253
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
2254
|
+
container.removeEventListener("wheel", onWheel);
|
|
1692
2255
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1693
2256
|
if (currentRenderTask) {
|
|
1694
2257
|
try {
|
|
@@ -1707,22 +2270,26 @@ var PdfPlugin = class {
|
|
|
1707
2270
|
const instance = {
|
|
1708
2271
|
destroy: cleanup,
|
|
1709
2272
|
zoomIn: () => {
|
|
1710
|
-
zoomScale = Math.min(
|
|
2273
|
+
zoomScale = Math.min(4, Math.round((zoomScale + 0.2) * 10) / 10);
|
|
1711
2274
|
renderPage(currentPage);
|
|
1712
2275
|
},
|
|
1713
2276
|
zoomOut: () => {
|
|
1714
|
-
zoomScale = Math.max(0.
|
|
2277
|
+
zoomScale = Math.max(0.25, Math.round((zoomScale - 0.2) * 10) / 10);
|
|
1715
2278
|
renderPage(currentPage);
|
|
1716
2279
|
},
|
|
1717
2280
|
getZoom: () => zoomScale,
|
|
1718
2281
|
setZoom: (level) => {
|
|
1719
|
-
zoomScale = Math.max(0.
|
|
2282
|
+
zoomScale = Math.max(0.25, Math.min(4, level));
|
|
1720
2283
|
renderPage(currentPage);
|
|
1721
2284
|
},
|
|
1722
2285
|
fitToPage: () => {
|
|
1723
|
-
fitMode =
|
|
2286
|
+
fitMode = "page";
|
|
2287
|
+
zoomScale = 1;
|
|
2288
|
+
renderPage(currentPage);
|
|
2289
|
+
},
|
|
2290
|
+
fitToWidth: () => {
|
|
2291
|
+
fitMode = "width";
|
|
1724
2292
|
zoomScale = 1;
|
|
1725
|
-
rotation = 0;
|
|
1726
2293
|
renderPage(currentPage);
|
|
1727
2294
|
},
|
|
1728
2295
|
rotateCW: () => {
|
|
@@ -1740,6 +2307,9 @@ var PdfPlugin = class {
|
|
|
1740
2307
|
container.scrollTop = 0;
|
|
1741
2308
|
renderPage(page);
|
|
1742
2309
|
},
|
|
2310
|
+
toggleThumbnails: () => {
|
|
2311
|
+
ctx?.toggleThumbnails?.();
|
|
2312
|
+
},
|
|
1743
2313
|
download: () => {
|
|
1744
2314
|
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1745
2315
|
const url = URL.createObjectURL(blob);
|
|
@@ -1773,7 +2343,7 @@ var PdfPlugin = class {
|
|
|
1773
2343
|
},
|
|
1774
2344
|
getThumbnails: async () => {
|
|
1775
2345
|
const thumbnails = [];
|
|
1776
|
-
const count =
|
|
2346
|
+
const count = totalPages;
|
|
1777
2347
|
for (let i = 1; i <= count; i++) {
|
|
1778
2348
|
thumbnails.push({
|
|
1779
2349
|
index: i,
|
|
@@ -1781,9 +2351,10 @@ var PdfPlugin = class {
|
|
|
1781
2351
|
render: async (thumbCanvas) => {
|
|
1782
2352
|
try {
|
|
1783
2353
|
const p = await pdfDoc.getPage(i);
|
|
1784
|
-
const baseVp = p.getViewport({ scale: 1 });
|
|
1785
|
-
const
|
|
1786
|
-
const
|
|
2354
|
+
const baseVp = p.getViewport({ scale: 1, rotation });
|
|
2355
|
+
const targetW = thumbCanvas.width || 130;
|
|
2356
|
+
const thumbScale = targetW / baseVp.width;
|
|
2357
|
+
const thumbVp = p.getViewport({ scale: thumbScale, rotation });
|
|
1787
2358
|
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1788
2359
|
const tCtx = thumbCanvas.getContext("2d");
|
|
1789
2360
|
if (tCtx) {
|
|
@@ -2127,28 +2698,26 @@ var DocxPlugin = class {
|
|
|
2127
2698
|
getToolbarActions(instance) {
|
|
2128
2699
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2129
2700
|
const actions = [];
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
if (
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
instance.goToPage?.(page);
|
|
2148
|
-
}
|
|
2701
|
+
actions.push({
|
|
2702
|
+
id: "page-nav",
|
|
2703
|
+
icon: "",
|
|
2704
|
+
label: "Page Navigation",
|
|
2705
|
+
type: "page-nav",
|
|
2706
|
+
group: "navigation",
|
|
2707
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2708
|
+
max: totalPages,
|
|
2709
|
+
execute: (action, page) => {
|
|
2710
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2711
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2712
|
+
if (action === "prev") {
|
|
2713
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2714
|
+
} else if (action === "next") {
|
|
2715
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2716
|
+
} else if (typeof page === "number") {
|
|
2717
|
+
instance.goToPage?.(page);
|
|
2149
2718
|
}
|
|
2150
|
-
}
|
|
2151
|
-
}
|
|
2719
|
+
}
|
|
2720
|
+
});
|
|
2152
2721
|
actions.push(
|
|
2153
2722
|
{
|
|
2154
2723
|
id: "zoom-out",
|
|
@@ -2214,11 +2783,17 @@ var DocxPlugin = class {
|
|
|
2214
2783
|
wrapper.className = "fp-docx-wrapper";
|
|
2215
2784
|
wrapper.style.transformOrigin = "top center";
|
|
2216
2785
|
wrapper.style.transition = "transform 0.2s ease";
|
|
2217
|
-
wrapper.style.padding = "
|
|
2218
|
-
wrapper.style.maxWidth = "
|
|
2786
|
+
wrapper.style.padding = "0";
|
|
2787
|
+
wrapper.style.maxWidth = "none";
|
|
2788
|
+
wrapper.style.width = "816px";
|
|
2219
2789
|
wrapper.style.margin = "0 auto";
|
|
2790
|
+
wrapper.style.display = "flex";
|
|
2791
|
+
wrapper.style.flexDirection = "column";
|
|
2792
|
+
wrapper.style.alignItems = "center";
|
|
2220
2793
|
wrapper.style.boxSizing = "border-box";
|
|
2221
|
-
ctx.container.style.
|
|
2794
|
+
ctx.container.style.overflowX = "hidden";
|
|
2795
|
+
ctx.container.style.overflowY = "auto";
|
|
2796
|
+
ctx.container.style.padding = "16px 8px";
|
|
2222
2797
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
2223
2798
|
ctx.container.appendChild(wrapper);
|
|
2224
2799
|
const styleOverride = document.createElement("style");
|
|
@@ -2392,39 +2967,13 @@ var DocxPlugin = class {
|
|
|
2392
2967
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2393
2968
|
const totalPages = Math.max(1, pageElements.length);
|
|
2394
2969
|
let currentPage = 1;
|
|
2395
|
-
let indicator = null;
|
|
2396
|
-
if (totalPages > 1) {
|
|
2397
|
-
indicator = document.createElement("div");
|
|
2398
|
-
indicator.className = "fp-docx-page-indicator";
|
|
2399
|
-
indicator.style.position = "sticky";
|
|
2400
|
-
indicator.style.bottom = "16px";
|
|
2401
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2402
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
2403
|
-
indicator.style.color = "#f8fafc";
|
|
2404
|
-
indicator.style.fontSize = "12px";
|
|
2405
|
-
indicator.style.fontWeight = "600";
|
|
2406
|
-
indicator.style.padding = "5px 14px";
|
|
2407
|
-
indicator.style.borderRadius = "20px";
|
|
2408
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2409
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2410
|
-
indicator.style.zIndex = "10";
|
|
2411
|
-
indicator.style.userSelect = "none";
|
|
2412
|
-
indicator.style.pointerEvents = "none";
|
|
2413
|
-
indicator.style.textAlign = "center";
|
|
2414
|
-
indicator.style.width = "fit-content";
|
|
2415
|
-
indicator.style.margin = "16px auto 0";
|
|
2416
|
-
ctx.container.appendChild(indicator);
|
|
2417
|
-
}
|
|
2418
2970
|
const showPage = (pageNum) => {
|
|
2419
2971
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2420
2972
|
if (pageElements.length > 1) {
|
|
2421
2973
|
pageElements.forEach((sec, idx) => {
|
|
2422
|
-
sec.style.display = idx + 1 === currentPage ? "
|
|
2974
|
+
sec.style.display = idx + 1 === currentPage ? "" : "none";
|
|
2423
2975
|
});
|
|
2424
2976
|
}
|
|
2425
|
-
if (indicator) {
|
|
2426
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2427
|
-
}
|
|
2428
2977
|
ctx.container.scrollTop = 0;
|
|
2429
2978
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2430
2979
|
};
|
|
@@ -2433,31 +2982,46 @@ var DocxPlugin = class {
|
|
|
2433
2982
|
}
|
|
2434
2983
|
scale = 1;
|
|
2435
2984
|
let rotation = 0;
|
|
2436
|
-
let fitMode = "
|
|
2437
|
-
|
|
2438
|
-
|
|
2985
|
+
let fitMode = "page";
|
|
2986
|
+
let isUserZoomed = false;
|
|
2987
|
+
const calculateFitScale = (_mode = fitMode) => {
|
|
2988
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
2439
2989
|
const elW = activeEl.offsetWidth || 816;
|
|
2440
|
-
const
|
|
2441
|
-
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
2442
|
-
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
2990
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
2443
2991
|
const sW = availW / elW;
|
|
2444
|
-
|
|
2445
|
-
if (mode === "page") {
|
|
2446
|
-
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
2447
|
-
}
|
|
2448
|
-
return Math.max(0.65, Math.min(1.05, sW));
|
|
2992
|
+
return Math.max(0.35, Math.min(3, sW));
|
|
2449
2993
|
};
|
|
2450
2994
|
const applyTransform = () => {
|
|
2451
2995
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2452
2996
|
wrapper.style.transformOrigin = "top center";
|
|
2997
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
2998
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
2999
|
+
if (scale > 1) {
|
|
3000
|
+
wrapper.style.marginBottom = `${Math.round(elH * scale - elH + 32)}px`;
|
|
3001
|
+
} else {
|
|
3002
|
+
wrapper.style.marginBottom = "32px";
|
|
3003
|
+
}
|
|
2453
3004
|
};
|
|
3005
|
+
let resizeObserver = null;
|
|
3006
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
3007
|
+
resizeObserver = new ResizeObserver(() => {
|
|
3008
|
+
if (!isUserZoomed) {
|
|
3009
|
+
const newFit = calculateFitScale("page");
|
|
3010
|
+
if (Math.abs(scale - newFit) > 0.015) {
|
|
3011
|
+
scale = newFit;
|
|
3012
|
+
applyTransform();
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
});
|
|
3016
|
+
resizeObserver.observe(ctx.container);
|
|
3017
|
+
}
|
|
2454
3018
|
setTimeout(() => {
|
|
2455
|
-
|
|
2456
|
-
scale = calculateFitScale("width");
|
|
3019
|
+
scale = calculateFitScale("page");
|
|
2457
3020
|
applyTransform();
|
|
2458
|
-
},
|
|
3021
|
+
}, 40);
|
|
2459
3022
|
const cleanup = () => {
|
|
2460
|
-
|
|
3023
|
+
resizeObserver?.disconnect();
|
|
3024
|
+
resizeObserver = null;
|
|
2461
3025
|
for (const url of createdBlobUrls) {
|
|
2462
3026
|
URL.revokeObjectURL(url);
|
|
2463
3027
|
}
|
|
@@ -2474,21 +3038,24 @@ var DocxPlugin = class {
|
|
|
2474
3038
|
showPage(page);
|
|
2475
3039
|
},
|
|
2476
3040
|
zoomIn: () => {
|
|
2477
|
-
|
|
3041
|
+
isUserZoomed = true;
|
|
3042
|
+
scale = Math.min(3.5, scale + 0.15);
|
|
2478
3043
|
applyTransform();
|
|
2479
3044
|
},
|
|
2480
3045
|
zoomOut: () => {
|
|
3046
|
+
isUserZoomed = true;
|
|
2481
3047
|
scale = Math.max(0.2, scale - 0.15);
|
|
2482
3048
|
applyTransform();
|
|
2483
3049
|
},
|
|
2484
3050
|
getZoom: () => scale,
|
|
2485
3051
|
setZoom: (level) => {
|
|
3052
|
+
isUserZoomed = true;
|
|
2486
3053
|
scale = level;
|
|
2487
3054
|
applyTransform();
|
|
2488
3055
|
},
|
|
2489
3056
|
fitToPage: () => {
|
|
2490
|
-
|
|
2491
|
-
scale = calculateFitScale(
|
|
3057
|
+
isUserZoomed = false;
|
|
3058
|
+
scale = calculateFitScale("page");
|
|
2492
3059
|
rotation = 0;
|
|
2493
3060
|
applyTransform();
|
|
2494
3061
|
},
|
|
@@ -2878,7 +3445,7 @@ var ExcelPlugin = class {
|
|
|
2878
3445
|
"application/vnd.ms-excel.template.macroEnabled.12",
|
|
2879
3446
|
"application/vnd.oasis.opendocument.spreadsheet"
|
|
2880
3447
|
];
|
|
2881
|
-
weight =
|
|
3448
|
+
weight = 85;
|
|
2882
3449
|
supports(file) {
|
|
2883
3450
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2884
3451
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
@@ -2890,6 +3457,14 @@ var ExcelPlugin = class {
|
|
|
2890
3457
|
getToolbarActions(instance) {
|
|
2891
3458
|
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2892
3459
|
const actions = [];
|
|
3460
|
+
actions.push({
|
|
3461
|
+
id: "thumbnails",
|
|
3462
|
+
icon: "thumbnails",
|
|
3463
|
+
label: "Sheet Thumbnails",
|
|
3464
|
+
type: "button",
|
|
3465
|
+
group: "navigation",
|
|
3466
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3467
|
+
});
|
|
2893
3468
|
if (totalSheets > 1) {
|
|
2894
3469
|
actions.push({
|
|
2895
3470
|
id: "page-nav",
|
|
@@ -2933,26 +3508,6 @@ var ExcelPlugin = class {
|
|
|
2933
3508
|
instance.zoomIn?.();
|
|
2934
3509
|
}
|
|
2935
3510
|
},
|
|
2936
|
-
{
|
|
2937
|
-
id: "fit-page",
|
|
2938
|
-
icon: "fit-page",
|
|
2939
|
-
label: "Fit to View",
|
|
2940
|
-
type: "button",
|
|
2941
|
-
group: "zoom",
|
|
2942
|
-
execute: () => {
|
|
2943
|
-
instance.fitToPage?.();
|
|
2944
|
-
}
|
|
2945
|
-
},
|
|
2946
|
-
{
|
|
2947
|
-
id: "rotate-cw",
|
|
2948
|
-
icon: "rotate-cw",
|
|
2949
|
-
label: "Rotate",
|
|
2950
|
-
type: "button",
|
|
2951
|
-
group: "view",
|
|
2952
|
-
execute: () => {
|
|
2953
|
-
instance.rotateCW?.();
|
|
2954
|
-
}
|
|
2955
|
-
},
|
|
2956
3511
|
{
|
|
2957
3512
|
id: "download",
|
|
2958
3513
|
icon: "download",
|
|
@@ -2972,6 +3527,16 @@ var ExcelPlugin = class {
|
|
|
2972
3527
|
execute: () => {
|
|
2973
3528
|
instance.print?.();
|
|
2974
3529
|
}
|
|
3530
|
+
},
|
|
3531
|
+
{
|
|
3532
|
+
id: "open-window",
|
|
3533
|
+
icon: "open-window",
|
|
3534
|
+
label: "Open in Separate Full Window",
|
|
3535
|
+
type: "button",
|
|
3536
|
+
group: "actions",
|
|
3537
|
+
execute: () => {
|
|
3538
|
+
instance.openInSeparateWindow?.();
|
|
3539
|
+
}
|
|
2975
3540
|
}
|
|
2976
3541
|
);
|
|
2977
3542
|
return actions;
|
|
@@ -3003,12 +3568,11 @@ var ExcelPlugin = class {
|
|
|
3003
3568
|
container.appendChild(tabsArea);
|
|
3004
3569
|
ctx.container.appendChild(container);
|
|
3005
3570
|
let scale = 1;
|
|
3006
|
-
let rotation = 0;
|
|
3007
3571
|
let currentSheetIndex = 1;
|
|
3008
3572
|
let sheetNames = [];
|
|
3009
3573
|
let wb = null;
|
|
3010
3574
|
const applyTransform = () => {
|
|
3011
|
-
contentArea.style.transform = `scale(${scale})
|
|
3575
|
+
contentArea.style.transform = `scale(${scale})`;
|
|
3012
3576
|
contentArea.style.transformOrigin = "top left";
|
|
3013
3577
|
};
|
|
3014
3578
|
const calculateFitScale = () => {
|
|
@@ -3016,7 +3580,7 @@ var ExcelPlugin = class {
|
|
|
3016
3580
|
if (!table) return 1;
|
|
3017
3581
|
const availW = Math.max(280, container.clientWidth - 48);
|
|
3018
3582
|
const tW = table.offsetWidth || 800;
|
|
3019
|
-
return Math.max(0.
|
|
3583
|
+
return Math.max(0.4, Math.min(1, availW / tW));
|
|
3020
3584
|
};
|
|
3021
3585
|
try {
|
|
3022
3586
|
wb = XLSX__namespace.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
|
|
@@ -3071,7 +3635,16 @@ var ExcelPlugin = class {
|
|
|
3071
3635
|
}
|
|
3072
3636
|
});
|
|
3073
3637
|
ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
|
|
3638
|
+
requestAnimationFrame(() => {
|
|
3639
|
+
scale = calculateFitScale();
|
|
3640
|
+
applyTransform();
|
|
3641
|
+
});
|
|
3074
3642
|
};
|
|
3643
|
+
const ro = new ResizeObserver(() => {
|
|
3644
|
+
scale = calculateFitScale();
|
|
3645
|
+
applyTransform();
|
|
3646
|
+
});
|
|
3647
|
+
ro.observe(container);
|
|
3075
3648
|
if (sheetNames.length > 0) {
|
|
3076
3649
|
sheetNames.forEach((name, idx) => {
|
|
3077
3650
|
const btn = document.createElement("button");
|
|
@@ -3098,6 +3671,7 @@ var ExcelPlugin = class {
|
|
|
3098
3671
|
`;
|
|
3099
3672
|
}
|
|
3100
3673
|
const cleanup = () => {
|
|
3674
|
+
ro.disconnect();
|
|
3101
3675
|
container.remove();
|
|
3102
3676
|
ctx.container.innerHTML = "";
|
|
3103
3677
|
};
|
|
@@ -3119,16 +3693,11 @@ var ExcelPlugin = class {
|
|
|
3119
3693
|
},
|
|
3120
3694
|
fitToPage: () => {
|
|
3121
3695
|
scale = calculateFitScale();
|
|
3122
|
-
rotation = 0;
|
|
3123
3696
|
applyTransform();
|
|
3124
3697
|
},
|
|
3125
3698
|
rotateCW: () => {
|
|
3126
|
-
rotation = (rotation + 90) % 360;
|
|
3127
|
-
applyTransform();
|
|
3128
3699
|
},
|
|
3129
3700
|
rotateCCW: () => {
|
|
3130
|
-
rotation = (rotation - 90 + 360) % 360;
|
|
3131
|
-
applyTransform();
|
|
3132
3701
|
},
|
|
3133
3702
|
goToPage: (page) => {
|
|
3134
3703
|
if (page > 0 && page <= sheetNames.length) {
|
|
@@ -3137,6 +3706,63 @@ var ExcelPlugin = class {
|
|
|
3137
3706
|
},
|
|
3138
3707
|
getPageCount: () => sheetNames.length,
|
|
3139
3708
|
getCurrentPage: () => currentSheetIndex,
|
|
3709
|
+
getThumbnails: () => {
|
|
3710
|
+
return sheetNames.map((name, idx) => ({
|
|
3711
|
+
index: idx,
|
|
3712
|
+
label: name,
|
|
3713
|
+
render: async (canvas) => {
|
|
3714
|
+
canvas.width = 140;
|
|
3715
|
+
canvas.height = 100;
|
|
3716
|
+
const c = canvas.getContext("2d");
|
|
3717
|
+
if (!c) return;
|
|
3718
|
+
c.fillStyle = "#ffffff";
|
|
3719
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
3720
|
+
c.fillStyle = "#107c41";
|
|
3721
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
3722
|
+
c.fillStyle = "#ffffff";
|
|
3723
|
+
c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
3724
|
+
c.fillText(`\u{1F4CA} ${name.slice(0, 16)}`, 6, 11);
|
|
3725
|
+
const startY = 17;
|
|
3726
|
+
const rowH = 13;
|
|
3727
|
+
const colW = 30;
|
|
3728
|
+
const colHeaders = ["A", "B", "C", "D"];
|
|
3729
|
+
c.fillStyle = "#f1f5f9";
|
|
3730
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
3731
|
+
c.strokeStyle = "#cbd5e1";
|
|
3732
|
+
c.lineWidth = 0.8;
|
|
3733
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
3734
|
+
c.fillStyle = "#64748b";
|
|
3735
|
+
c.font = "bold 7px sans-serif";
|
|
3736
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3737
|
+
c.fillText(colHeaders[ci], 14 + ci * colW, startY + 9);
|
|
3738
|
+
}
|
|
3739
|
+
const ws = wb?.Sheets[name];
|
|
3740
|
+
for (let ri = 1; ri <= 5; ri++) {
|
|
3741
|
+
const y = startY + ri * rowH;
|
|
3742
|
+
if (y > canvas.height - 2) break;
|
|
3743
|
+
c.fillStyle = "#f8fafc";
|
|
3744
|
+
c.fillRect(0, y, 12, rowH);
|
|
3745
|
+
c.fillStyle = "#94a3b8";
|
|
3746
|
+
c.font = "6px sans-serif";
|
|
3747
|
+
c.fillText(String(ri), 3, y + 9);
|
|
3748
|
+
c.strokeStyle = "#e2e8f0";
|
|
3749
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
3750
|
+
c.fillStyle = "#334155";
|
|
3751
|
+
c.font = "6px sans-serif";
|
|
3752
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3753
|
+
const cellRef = `${colHeaders[ci]}${ri}`;
|
|
3754
|
+
const cellVal = ws?.[cellRef]?.w || ws?.[cellRef]?.v;
|
|
3755
|
+
if (cellVal !== void 0) {
|
|
3756
|
+
c.fillText(String(cellVal).slice(0, 6), 14 + ci * colW, y + 9);
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
}
|
|
3760
|
+
c.strokeStyle = "#cbd5e1";
|
|
3761
|
+
c.lineWidth = 1;
|
|
3762
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
3763
|
+
}
|
|
3764
|
+
}));
|
|
3765
|
+
},
|
|
3140
3766
|
download: () => {
|
|
3141
3767
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
3142
3768
|
const url = URL.createObjectURL(blob);
|
|
@@ -3169,7 +3795,16 @@ var CsvPlugin = class {
|
|
|
3169
3795
|
return ext === ".csv" || ext === ".tsv" || mime === "text/csv" || mime === "text/tab-separated-values";
|
|
3170
3796
|
}
|
|
3171
3797
|
getToolbarActions(instance) {
|
|
3172
|
-
|
|
3798
|
+
const actions = [];
|
|
3799
|
+
actions.push({
|
|
3800
|
+
id: "thumbnails",
|
|
3801
|
+
icon: "thumbnails",
|
|
3802
|
+
label: "Sheet Thumbnails",
|
|
3803
|
+
type: "button",
|
|
3804
|
+
group: "navigation",
|
|
3805
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3806
|
+
});
|
|
3807
|
+
actions.push(
|
|
3173
3808
|
{
|
|
3174
3809
|
id: "zoom-out",
|
|
3175
3810
|
icon: "zoom-out",
|
|
@@ -3209,8 +3844,19 @@ var CsvPlugin = class {
|
|
|
3209
3844
|
execute: () => {
|
|
3210
3845
|
instance.print?.();
|
|
3211
3846
|
}
|
|
3847
|
+
},
|
|
3848
|
+
{
|
|
3849
|
+
id: "open-window",
|
|
3850
|
+
icon: "open-window",
|
|
3851
|
+
label: "Open in Separate Full Window",
|
|
3852
|
+
type: "button",
|
|
3853
|
+
group: "actions",
|
|
3854
|
+
execute: () => {
|
|
3855
|
+
instance.openInSeparateWindow?.();
|
|
3856
|
+
}
|
|
3212
3857
|
}
|
|
3213
|
-
|
|
3858
|
+
);
|
|
3859
|
+
return actions;
|
|
3214
3860
|
}
|
|
3215
3861
|
async render(ctx) {
|
|
3216
3862
|
const decoder = new TextDecoder("utf-8");
|
|
@@ -3221,57 +3867,156 @@ var CsvPlugin = class {
|
|
|
3221
3867
|
container.style.overflow = "auto";
|
|
3222
3868
|
container.style.padding = "16px";
|
|
3223
3869
|
container.style.boxSizing = "border-box";
|
|
3224
|
-
|
|
3870
|
+
const tableWrapper = document.createElement("div");
|
|
3871
|
+
tableWrapper.style.transformOrigin = "top left";
|
|
3872
|
+
const delimiter = ctx.metadata.extension === ".tsv" ? " " : ",";
|
|
3873
|
+
const allLines = text.split(/\r?\n/).filter((r) => r.trim().length > 0);
|
|
3874
|
+
const headerLine = allLines[0] || "";
|
|
3875
|
+
const headerCells = headerLine.split(delimiter);
|
|
3876
|
+
const dataLines = allLines.slice(1);
|
|
3225
3877
|
const table = document.createElement("table");
|
|
3226
3878
|
table.style.borderCollapse = "collapse";
|
|
3227
|
-
table.style.
|
|
3228
|
-
table.style.fontFamily = "monospace
|
|
3879
|
+
table.style.minWidth = "100%";
|
|
3880
|
+
table.style.fontFamily = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace';
|
|
3229
3881
|
table.style.fontSize = "13px";
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3882
|
+
table.style.background = "#ffffff";
|
|
3883
|
+
table.style.border = "1px solid #d0d7de";
|
|
3884
|
+
const headerTr = document.createElement("tr");
|
|
3885
|
+
headerCells.forEach((cell) => {
|
|
3886
|
+
const th = document.createElement("th");
|
|
3887
|
+
th.textContent = cell.trim();
|
|
3888
|
+
th.style.border = "1px solid #d0d7de";
|
|
3889
|
+
th.style.padding = "8px 12px";
|
|
3890
|
+
th.style.backgroundColor = "#f6f8fa";
|
|
3891
|
+
th.style.fontWeight = "600";
|
|
3892
|
+
th.style.whiteSpace = "nowrap";
|
|
3893
|
+
headerTr.appendChild(th);
|
|
3894
|
+
});
|
|
3895
|
+
table.appendChild(headerTr);
|
|
3896
|
+
dataLines.forEach((row, idx) => {
|
|
3234
3897
|
const tr = document.createElement("tr");
|
|
3898
|
+
if (idx % 2 === 1) tr.style.backgroundColor = "#f8fafc";
|
|
3235
3899
|
const cells = row.split(delimiter);
|
|
3236
3900
|
cells.forEach((cell) => {
|
|
3237
|
-
const td = document.createElement(
|
|
3901
|
+
const td = document.createElement("td");
|
|
3238
3902
|
td.textContent = cell.trim();
|
|
3239
3903
|
td.style.border = "1px solid #d0d7de";
|
|
3240
3904
|
td.style.padding = "6px 12px";
|
|
3241
|
-
|
|
3242
|
-
td.style.backgroundColor = "#f6f8fa";
|
|
3243
|
-
td.style.fontWeight = "bold";
|
|
3244
|
-
}
|
|
3905
|
+
td.style.whiteSpace = "nowrap";
|
|
3245
3906
|
tr.appendChild(td);
|
|
3246
3907
|
});
|
|
3247
3908
|
table.appendChild(tr);
|
|
3248
3909
|
});
|
|
3249
|
-
|
|
3910
|
+
tableWrapper.appendChild(table);
|
|
3911
|
+
container.appendChild(tableWrapper);
|
|
3250
3912
|
ctx.container.appendChild(container);
|
|
3251
3913
|
let scale = 1;
|
|
3914
|
+
const calculateFitScale = () => {
|
|
3915
|
+
const availW = Math.max(280, container.clientWidth - 48);
|
|
3916
|
+
const tW = table.offsetWidth || 800;
|
|
3917
|
+
return Math.max(0.4, Math.min(1, availW / tW));
|
|
3918
|
+
};
|
|
3919
|
+
const applyScale = () => {
|
|
3920
|
+
tableWrapper.style.transform = `scale(${scale})`;
|
|
3921
|
+
};
|
|
3922
|
+
requestAnimationFrame(() => {
|
|
3923
|
+
scale = calculateFitScale();
|
|
3924
|
+
applyScale();
|
|
3925
|
+
});
|
|
3926
|
+
const ro = new ResizeObserver(() => {
|
|
3927
|
+
scale = calculateFitScale();
|
|
3928
|
+
applyScale();
|
|
3929
|
+
});
|
|
3930
|
+
ro.observe(container);
|
|
3252
3931
|
const cleanup = () => {
|
|
3932
|
+
ro.disconnect();
|
|
3253
3933
|
container.remove();
|
|
3254
3934
|
ctx.container.innerHTML = "";
|
|
3255
3935
|
};
|
|
3256
3936
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3257
3937
|
return {
|
|
3258
3938
|
destroy: cleanup,
|
|
3939
|
+
getPageCount: () => 1,
|
|
3940
|
+
getCurrentPage: () => 1,
|
|
3941
|
+
goToPage: () => {
|
|
3942
|
+
},
|
|
3943
|
+
getThumbnails: () => {
|
|
3944
|
+
const sheetName = ctx.metadata.name?.replace(/\.[^/.]+$/, "") || "Sheet1";
|
|
3945
|
+
return [{
|
|
3946
|
+
index: 0,
|
|
3947
|
+
label: sheetName,
|
|
3948
|
+
render: async (canvas) => {
|
|
3949
|
+
canvas.width = 140;
|
|
3950
|
+
canvas.height = 100;
|
|
3951
|
+
const c = canvas.getContext("2d");
|
|
3952
|
+
if (!c) return;
|
|
3953
|
+
c.fillStyle = "#ffffff";
|
|
3954
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
3955
|
+
c.fillStyle = "#107c41";
|
|
3956
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
3957
|
+
c.fillStyle = "#ffffff";
|
|
3958
|
+
c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
3959
|
+
c.fillText(`\u{1F4CA} ${sheetName.slice(0, 16)}`, 6, 11);
|
|
3960
|
+
const startY = 17;
|
|
3961
|
+
const rowH = 13;
|
|
3962
|
+
const colW = 30;
|
|
3963
|
+
const cols = headerCells.slice(0, 4).map((h2) => h2.trim() || "Col");
|
|
3964
|
+
c.fillStyle = "#f1f5f9";
|
|
3965
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
3966
|
+
c.strokeStyle = "#cbd5e1";
|
|
3967
|
+
c.lineWidth = 0.8;
|
|
3968
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
3969
|
+
c.fillStyle = "#64748b";
|
|
3970
|
+
c.font = "bold 7px sans-serif";
|
|
3971
|
+
for (let ci = 0; ci < cols.length; ci++) {
|
|
3972
|
+
c.fillText(cols[ci].slice(0, 5), 14 + ci * colW, startY + 9);
|
|
3973
|
+
}
|
|
3974
|
+
for (let ri = 0; ri < Math.min(5, dataLines.length); ri++) {
|
|
3975
|
+
const y = startY + (ri + 1) * rowH;
|
|
3976
|
+
if (y > canvas.height - 2) break;
|
|
3977
|
+
c.fillStyle = "#f8fafc";
|
|
3978
|
+
c.fillRect(0, y, 12, rowH);
|
|
3979
|
+
c.fillStyle = "#94a3b8";
|
|
3980
|
+
c.font = "6px sans-serif";
|
|
3981
|
+
c.fillText(String(ri + 1), 3, y + 9);
|
|
3982
|
+
c.strokeStyle = "#e2e8f0";
|
|
3983
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
3984
|
+
const rowCells = dataLines[ri].split(delimiter);
|
|
3985
|
+
c.fillStyle = "#334155";
|
|
3986
|
+
c.font = "6px sans-serif";
|
|
3987
|
+
for (let ci = 0; ci < cols.length; ci++) {
|
|
3988
|
+
const val = (rowCells[ci] || "").trim();
|
|
3989
|
+
if (val) {
|
|
3990
|
+
c.fillText(val.slice(0, 6), 14 + ci * colW, y + 9);
|
|
3991
|
+
}
|
|
3992
|
+
}
|
|
3993
|
+
}
|
|
3994
|
+
c.strokeStyle = "#cbd5e1";
|
|
3995
|
+
c.lineWidth = 1;
|
|
3996
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
3997
|
+
}
|
|
3998
|
+
}];
|
|
3999
|
+
},
|
|
3259
4000
|
zoomIn: () => {
|
|
3260
4001
|
scale += 0.1;
|
|
3261
|
-
|
|
4002
|
+
applyScale();
|
|
3262
4003
|
},
|
|
3263
4004
|
zoomOut: () => {
|
|
3264
4005
|
scale = Math.max(0.2, scale - 0.1);
|
|
3265
|
-
|
|
4006
|
+
applyScale();
|
|
3266
4007
|
},
|
|
3267
4008
|
getZoom: () => scale,
|
|
3268
4009
|
setZoom: (level) => {
|
|
3269
4010
|
scale = level;
|
|
3270
|
-
|
|
4011
|
+
applyScale();
|
|
3271
4012
|
},
|
|
3272
4013
|
fitToPage: () => {
|
|
3273
|
-
scale =
|
|
3274
|
-
|
|
4014
|
+
scale = calculateFitScale();
|
|
4015
|
+
applyScale();
|
|
4016
|
+
},
|
|
4017
|
+
rotateCW: () => {
|
|
4018
|
+
},
|
|
4019
|
+
rotateCCW: () => {
|
|
3275
4020
|
},
|
|
3276
4021
|
download: () => {
|
|
3277
4022
|
const blob = new Blob([ctx.buffer], { type: "text/csv" });
|
|
@@ -3333,30 +4078,36 @@ var CodePlugin = class {
|
|
|
3333
4078
|
return false;
|
|
3334
4079
|
}
|
|
3335
4080
|
getToolbarActions(instance) {
|
|
3336
|
-
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3337
|
-
const actions = [];
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
4081
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4082
|
+
const actions = [];
|
|
4083
|
+
actions.push({
|
|
4084
|
+
id: "thumbnails",
|
|
4085
|
+
icon: "thumbnails",
|
|
4086
|
+
label: "Page Thumbnails",
|
|
4087
|
+
type: "button",
|
|
4088
|
+
group: "navigation",
|
|
4089
|
+
execute: () => instance.toggleThumbnails?.()
|
|
4090
|
+
});
|
|
4091
|
+
actions.push({
|
|
4092
|
+
id: "page-nav",
|
|
4093
|
+
icon: "",
|
|
4094
|
+
label: "Page Navigation",
|
|
4095
|
+
type: "page-nav",
|
|
4096
|
+
group: "navigation",
|
|
4097
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4098
|
+
max: totalPages,
|
|
4099
|
+
execute: (action, page) => {
|
|
4100
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4101
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4102
|
+
if (action === "prev") {
|
|
4103
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4104
|
+
} else if (action === "next") {
|
|
4105
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4106
|
+
} else if (typeof page === "number") {
|
|
4107
|
+
instance.goToPage?.(page);
|
|
3357
4108
|
}
|
|
3358
|
-
}
|
|
3359
|
-
}
|
|
4109
|
+
}
|
|
4110
|
+
});
|
|
3360
4111
|
actions.push(
|
|
3361
4112
|
{
|
|
3362
4113
|
id: "zoom-out",
|
|
@@ -3378,26 +4129,6 @@ var CodePlugin = class {
|
|
|
3378
4129
|
instance.zoomIn?.();
|
|
3379
4130
|
}
|
|
3380
4131
|
},
|
|
3381
|
-
{
|
|
3382
|
-
id: "fit-page",
|
|
3383
|
-
icon: "fit-page",
|
|
3384
|
-
label: "Fit to View",
|
|
3385
|
-
type: "button",
|
|
3386
|
-
group: "zoom",
|
|
3387
|
-
execute: () => {
|
|
3388
|
-
instance.fitToPage?.();
|
|
3389
|
-
}
|
|
3390
|
-
},
|
|
3391
|
-
{
|
|
3392
|
-
id: "rotate-cw",
|
|
3393
|
-
icon: "rotate-cw",
|
|
3394
|
-
label: "Rotate",
|
|
3395
|
-
type: "button",
|
|
3396
|
-
group: "view",
|
|
3397
|
-
execute: () => {
|
|
3398
|
-
instance.rotateCW?.();
|
|
3399
|
-
}
|
|
3400
|
-
},
|
|
3401
4132
|
{
|
|
3402
4133
|
id: "copy",
|
|
3403
4134
|
icon: "copy",
|
|
@@ -3500,16 +4231,19 @@ var CodePlugin = class {
|
|
|
3500
4231
|
let fontSize = 13;
|
|
3501
4232
|
let rotation = 0;
|
|
3502
4233
|
let zoomLevel = 1;
|
|
4234
|
+
let isUserZoomed = false;
|
|
3503
4235
|
const pre = document.createElement("pre");
|
|
3504
4236
|
const code = document.createElement("code");
|
|
3505
4237
|
if (isTxt) {
|
|
4238
|
+
container.style.overflowX = "hidden";
|
|
4239
|
+
container.style.overflowY = "auto";
|
|
3506
4240
|
container.style.backgroundColor = "#f1f5f9";
|
|
3507
|
-
container.style.padding = "
|
|
4241
|
+
container.style.padding = "16px 8px";
|
|
3508
4242
|
container.style.boxSizing = "border-box";
|
|
3509
4243
|
container.style.display = "flex";
|
|
3510
4244
|
container.style.flexDirection = "column";
|
|
3511
4245
|
container.style.alignItems = "center";
|
|
3512
|
-
pre.style.margin = "0";
|
|
4246
|
+
pre.style.margin = "0 auto";
|
|
3513
4247
|
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3514
4248
|
pre.style.fontSize = "13px";
|
|
3515
4249
|
pre.style.color = "#1e293b";
|
|
@@ -3521,10 +4255,12 @@ var CodePlugin = class {
|
|
|
3521
4255
|
pre.style.minHeight = "1056px";
|
|
3522
4256
|
pre.style.padding = "72px 56px";
|
|
3523
4257
|
pre.style.boxSizing = "border-box";
|
|
3524
|
-
pre.style.boxShadow = "0 4px
|
|
4258
|
+
pre.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
3525
4259
|
pre.style.borderRadius = "4px";
|
|
3526
4260
|
pre.style.transformOrigin = "top center";
|
|
4261
|
+
pre.style.transition = "transform 0.15s ease";
|
|
3527
4262
|
} else {
|
|
4263
|
+
container.style.overflow = "auto";
|
|
3528
4264
|
container.style.backgroundColor = "#1e1e1e";
|
|
3529
4265
|
container.style.color = "#d4d4d4";
|
|
3530
4266
|
container.style.padding = "16px";
|
|
@@ -3556,42 +4292,9 @@ var CodePlugin = class {
|
|
|
3556
4292
|
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
3557
4293
|
pre.appendChild(code);
|
|
3558
4294
|
container.appendChild(pre);
|
|
3559
|
-
let indicator = null;
|
|
3560
|
-
if (totalPages > 1) {
|
|
3561
|
-
indicator = document.createElement("div");
|
|
3562
|
-
indicator.className = "fp-code-page-indicator";
|
|
3563
|
-
indicator.style.position = "sticky";
|
|
3564
|
-
indicator.style.bottom = "16px";
|
|
3565
|
-
if (isTxt) {
|
|
3566
|
-
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3567
|
-
indicator.style.color = "#334155";
|
|
3568
|
-
indicator.style.border = "1px solid #e2e8f0";
|
|
3569
|
-
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3570
|
-
} else {
|
|
3571
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3572
|
-
indicator.style.color = "#f8fafc";
|
|
3573
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3574
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3575
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
3576
|
-
}
|
|
3577
|
-
indicator.style.fontSize = "12px";
|
|
3578
|
-
indicator.style.fontWeight = "600";
|
|
3579
|
-
indicator.style.padding = "5px 14px";
|
|
3580
|
-
indicator.style.borderRadius = "20px";
|
|
3581
|
-
indicator.style.zIndex = "10";
|
|
3582
|
-
indicator.style.userSelect = "none";
|
|
3583
|
-
indicator.style.pointerEvents = "none";
|
|
3584
|
-
indicator.style.textAlign = "center";
|
|
3585
|
-
indicator.style.width = "fit-content";
|
|
3586
|
-
indicator.style.margin = "16px auto 0";
|
|
3587
|
-
container.appendChild(indicator);
|
|
3588
|
-
}
|
|
3589
4295
|
const showPage = (pageNum) => {
|
|
3590
4296
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3591
4297
|
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
3592
|
-
if (indicator) {
|
|
3593
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3594
|
-
}
|
|
3595
4298
|
container.scrollTop = 0;
|
|
3596
4299
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3597
4300
|
};
|
|
@@ -3599,36 +4302,90 @@ var CodePlugin = class {
|
|
|
3599
4302
|
showPage(1);
|
|
3600
4303
|
}
|
|
3601
4304
|
ctx.container.appendChild(container);
|
|
3602
|
-
const
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
ctx.container.innerHTML = "";
|
|
4305
|
+
const calculateTxtFit = () => {
|
|
4306
|
+
const availW = Math.max(280, container.clientWidth - 32);
|
|
4307
|
+
return Math.max(0.4, Math.min(3, availW / 816));
|
|
3606
4308
|
};
|
|
3607
|
-
ctx.signal.addEventListener("abort", cleanup);
|
|
3608
4309
|
const updateTransform = () => {
|
|
3609
4310
|
if (isTxt) {
|
|
3610
4311
|
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
4312
|
+
const scaledH = 1056 * zoomLevel;
|
|
4313
|
+
const extraH = Math.max(0, scaledH - 1056);
|
|
4314
|
+
pre.style.marginBottom = `${extraH + 32}px`;
|
|
3611
4315
|
} else {
|
|
3612
4316
|
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3613
4317
|
pre.style.fontSize = `${fontSize}px`;
|
|
3614
4318
|
}
|
|
3615
4319
|
};
|
|
4320
|
+
let resizeObserver = null;
|
|
4321
|
+
if (isTxt) {
|
|
4322
|
+
setTimeout(() => {
|
|
4323
|
+
zoomLevel = calculateTxtFit();
|
|
4324
|
+
updateTransform();
|
|
4325
|
+
}, 60);
|
|
4326
|
+
resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
4327
|
+
if (!isUserZoomed) {
|
|
4328
|
+
zoomLevel = calculateTxtFit();
|
|
4329
|
+
updateTransform();
|
|
4330
|
+
}
|
|
4331
|
+
}) : null;
|
|
4332
|
+
resizeObserver?.observe(container);
|
|
4333
|
+
}
|
|
4334
|
+
const cleanup = () => {
|
|
4335
|
+
resizeObserver?.disconnect();
|
|
4336
|
+
container.remove();
|
|
4337
|
+
ctx.container.innerHTML = "";
|
|
4338
|
+
};
|
|
4339
|
+
ctx.signal.addEventListener("abort", cleanup);
|
|
3616
4340
|
return {
|
|
3617
4341
|
destroy: cleanup,
|
|
3618
4342
|
getPageCount: () => totalPages,
|
|
3619
4343
|
getCurrentPage: () => currentPage,
|
|
3620
4344
|
goToPage: (page) => showPage(page),
|
|
4345
|
+
getThumbnails: () => {
|
|
4346
|
+
return rawPages.map((pageText, idx) => ({
|
|
4347
|
+
index: idx,
|
|
4348
|
+
label: `Page ${idx + 1}`,
|
|
4349
|
+
render: async (canvas) => {
|
|
4350
|
+
canvas.width = 140;
|
|
4351
|
+
canvas.height = 180;
|
|
4352
|
+
const c = canvas.getContext("2d");
|
|
4353
|
+
if (!c) return;
|
|
4354
|
+
c.fillStyle = "#ffffff";
|
|
4355
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4356
|
+
c.strokeStyle = "#cbd5e1";
|
|
4357
|
+
c.lineWidth = 1;
|
|
4358
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4359
|
+
c.fillStyle = "#64748b";
|
|
4360
|
+
const lines = (pageText || "").split("\n").slice(0, 24);
|
|
4361
|
+
const lineH = 6;
|
|
4362
|
+
const startY = 14;
|
|
4363
|
+
const startX = 12;
|
|
4364
|
+
const maxW = canvas.width - 24;
|
|
4365
|
+
c.font = "5px monospace";
|
|
4366
|
+
for (let li = 0; li < lines.length; li++) {
|
|
4367
|
+
const l = lines[li].trim();
|
|
4368
|
+
if (!l) continue;
|
|
4369
|
+
const y = startY + li * lineH;
|
|
4370
|
+
if (y > canvas.height - 12) break;
|
|
4371
|
+
c.fillText(l.slice(0, 30), startX, y, maxW);
|
|
4372
|
+
}
|
|
4373
|
+
}
|
|
4374
|
+
}));
|
|
4375
|
+
},
|
|
3621
4376
|
zoomIn: () => {
|
|
4377
|
+
isUserZoomed = true;
|
|
3622
4378
|
if (isTxt) {
|
|
3623
|
-
zoomLevel = Math.min(3, zoomLevel + 0.
|
|
4379
|
+
zoomLevel = Math.min(3.5, zoomLevel + 0.15);
|
|
3624
4380
|
} else {
|
|
3625
4381
|
fontSize = Math.min(32, fontSize + 2);
|
|
3626
4382
|
}
|
|
3627
4383
|
updateTransform();
|
|
3628
4384
|
},
|
|
3629
4385
|
zoomOut: () => {
|
|
4386
|
+
isUserZoomed = true;
|
|
3630
4387
|
if (isTxt) {
|
|
3631
|
-
zoomLevel = Math.max(0.1, zoomLevel - 0.
|
|
4388
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.15);
|
|
3632
4389
|
} else {
|
|
3633
4390
|
fontSize = Math.max(8, fontSize - 2);
|
|
3634
4391
|
}
|
|
@@ -3636,6 +4393,7 @@ var CodePlugin = class {
|
|
|
3636
4393
|
},
|
|
3637
4394
|
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
3638
4395
|
setZoom: (level) => {
|
|
4396
|
+
isUserZoomed = true;
|
|
3639
4397
|
if (isTxt) {
|
|
3640
4398
|
zoomLevel = level;
|
|
3641
4399
|
} else {
|
|
@@ -3644,9 +4402,10 @@ var CodePlugin = class {
|
|
|
3644
4402
|
updateTransform();
|
|
3645
4403
|
},
|
|
3646
4404
|
fitToPage: () => {
|
|
4405
|
+
isUserZoomed = false;
|
|
3647
4406
|
fontSize = 13;
|
|
3648
4407
|
rotation = 0;
|
|
3649
|
-
zoomLevel = isTxt ?
|
|
4408
|
+
zoomLevel = isTxt ? calculateTxtFit() : 1;
|
|
3650
4409
|
updateTransform();
|
|
3651
4410
|
},
|
|
3652
4411
|
rotateCW: () => {
|
|
@@ -4513,6 +5272,148 @@ var ThreeDPlugin = class {
|
|
|
4513
5272
|
function threeDPlugin() {
|
|
4514
5273
|
return new ThreeDPlugin();
|
|
4515
5274
|
}
|
|
5275
|
+
function cleanRtfText(raw) {
|
|
5276
|
+
return raw.replace(/\\bin\d+\s/g, "").replace(/{\\\*[^}]+}/g, "").replace(/\\u(-?\d+)\??/g, (_, code) => {
|
|
5277
|
+
let num = parseInt(code, 10);
|
|
5278
|
+
if (num < 0) num += 65536;
|
|
5279
|
+
return String.fromCharCode(num);
|
|
5280
|
+
}).replace(/\\'([0-9a-fA-F]{2})/g, (_, hex) => {
|
|
5281
|
+
return String.fromCharCode(parseInt(hex, 16));
|
|
5282
|
+
}).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();
|
|
5283
|
+
}
|
|
5284
|
+
function parseRtfTables(rtfText) {
|
|
5285
|
+
const rowSegments = rtfText.split(/\\row\b/);
|
|
5286
|
+
if (rowSegments.length <= 1) return [];
|
|
5287
|
+
const rawTables = [];
|
|
5288
|
+
let currentTable = null;
|
|
5289
|
+
let charOffset = 0;
|
|
5290
|
+
for (let i = 0; i < rowSegments.length - 1; i++) {
|
|
5291
|
+
const segment = rowSegments[i];
|
|
5292
|
+
const segmentStart = charOffset;
|
|
5293
|
+
const segmentEnd = charOffset + segment.length + 4;
|
|
5294
|
+
const cellParts = segment.split(/\\cell\b/);
|
|
5295
|
+
if (cellParts.length > 1) {
|
|
5296
|
+
const cellxMatches = [...segment.matchAll(/\\cellx(\d+)/g)].map((m) => parseInt(m[1], 10));
|
|
5297
|
+
let cellWidths = [];
|
|
5298
|
+
if (cellxMatches.length > 0) {
|
|
5299
|
+
let seq = [cellxMatches[0]];
|
|
5300
|
+
for (let k = 1; k < cellxMatches.length; k++) {
|
|
5301
|
+
if (cellxMatches[k] > cellxMatches[k - 1]) seq.push(cellxMatches[k]);
|
|
5302
|
+
else break;
|
|
5303
|
+
}
|
|
5304
|
+
let prev = 0;
|
|
5305
|
+
cellWidths = seq.map((x) => {
|
|
5306
|
+
const w = x - prev;
|
|
5307
|
+
prev = x;
|
|
5308
|
+
return w;
|
|
5309
|
+
});
|
|
5310
|
+
}
|
|
5311
|
+
const cells = [];
|
|
5312
|
+
for (let c = 0; c < cellParts.length - 1; c++) {
|
|
5313
|
+
let rawCell = cellParts[c];
|
|
5314
|
+
if (c === 0) {
|
|
5315
|
+
const lastTrowd = rawCell.lastIndexOf("\\trowd");
|
|
5316
|
+
if (lastTrowd !== -1) rawCell = rawCell.slice(lastTrowd);
|
|
5317
|
+
}
|
|
5318
|
+
cells.push(cleanRtfText(rawCell));
|
|
5319
|
+
}
|
|
5320
|
+
const isNewTable = !currentTable || segmentStart - currentTable.lastEnd > 2500;
|
|
5321
|
+
if (isNewTable) {
|
|
5322
|
+
const prevTextSlice = rtfText.slice(Math.max(0, segmentStart - 4e3), segmentStart);
|
|
5323
|
+
const cleanPrev = cleanRtfText(prevTextSlice);
|
|
5324
|
+
const anchorBefore = cleanPrev.slice(-80).trim();
|
|
5325
|
+
currentTable = {
|
|
5326
|
+
id: `RTF_TABLE_${rawTables.length}`,
|
|
5327
|
+
startPos: segmentStart,
|
|
5328
|
+
lastEnd: segmentEnd,
|
|
5329
|
+
rows: [],
|
|
5330
|
+
columnWidths: cellWidths,
|
|
5331
|
+
anchorBefore,
|
|
5332
|
+
anchorAfter: ""
|
|
5333
|
+
};
|
|
5334
|
+
rawTables.push(currentTable);
|
|
5335
|
+
}
|
|
5336
|
+
if (currentTable) {
|
|
5337
|
+
currentTable.rows.push({
|
|
5338
|
+
cells,
|
|
5339
|
+
widths: cellWidths.length === cells.length ? cellWidths : currentTable.columnWidths
|
|
5340
|
+
});
|
|
5341
|
+
currentTable.lastEnd = segmentEnd;
|
|
5342
|
+
}
|
|
5343
|
+
}
|
|
5344
|
+
charOffset += segment.length + 4;
|
|
5345
|
+
}
|
|
5346
|
+
rawTables.forEach((tbl) => {
|
|
5347
|
+
const afterSlice = rtfText.slice(tbl.lastEnd, Math.min(rtfText.length, tbl.lastEnd + 2e3));
|
|
5348
|
+
const cleanAfter = cleanRtfText(afterSlice);
|
|
5349
|
+
tbl.anchorAfter = cleanAfter.slice(0, 80).trim();
|
|
5350
|
+
});
|
|
5351
|
+
return rawTables.map((tbl) => {
|
|
5352
|
+
const totalW = (tbl.columnWidths || []).reduce((a, b) => a + b, 0);
|
|
5353
|
+
const colPercents = totalW > 0 ? tbl.columnWidths.map((w) => Math.round(w / totalW * 100)) : [];
|
|
5354
|
+
return {
|
|
5355
|
+
id: tbl.id,
|
|
5356
|
+
rows: tbl.rows.map((r) => r.cells),
|
|
5357
|
+
colPercents,
|
|
5358
|
+
anchorBefore: tbl.anchorBefore,
|
|
5359
|
+
anchorAfter: tbl.anchorAfter
|
|
5360
|
+
};
|
|
5361
|
+
});
|
|
5362
|
+
}
|
|
5363
|
+
function renderRtfTableElement(table) {
|
|
5364
|
+
const tableEl = document.createElement("table");
|
|
5365
|
+
tableEl.className = "fp-rtf-table";
|
|
5366
|
+
tableEl.style.width = "100%";
|
|
5367
|
+
tableEl.style.borderCollapse = "collapse";
|
|
5368
|
+
tableEl.style.margin = "16px 0 20px";
|
|
5369
|
+
tableEl.style.fontSize = "10pt";
|
|
5370
|
+
tableEl.style.lineHeight = "1.5";
|
|
5371
|
+
tableEl.style.border = "1px solid #cbd5e1";
|
|
5372
|
+
tableEl.style.borderRadius = "4px";
|
|
5373
|
+
tableEl.style.boxSizing = "border-box";
|
|
5374
|
+
tableEl.style.backgroundColor = "#ffffff";
|
|
5375
|
+
const thead = document.createElement("thead");
|
|
5376
|
+
const tbody = document.createElement("tbody");
|
|
5377
|
+
table.rows.forEach((rowCells, rIdx) => {
|
|
5378
|
+
const tr = document.createElement("tr");
|
|
5379
|
+
const isHeader = rIdx === 0;
|
|
5380
|
+
if (isHeader) {
|
|
5381
|
+
tr.style.backgroundColor = "#f8fafc";
|
|
5382
|
+
tr.style.borderBottom = "2px solid #cbd5e1";
|
|
5383
|
+
} else {
|
|
5384
|
+
tr.style.borderBottom = "1px solid #e2e8f0";
|
|
5385
|
+
if (rIdx % 2 === 0) {
|
|
5386
|
+
tr.style.backgroundColor = "#fcfdfe";
|
|
5387
|
+
}
|
|
5388
|
+
}
|
|
5389
|
+
rowCells.forEach((cellText, cIdx) => {
|
|
5390
|
+
const cellEl = document.createElement(isHeader ? "th" : "td");
|
|
5391
|
+
cellEl.style.padding = "8px 12px";
|
|
5392
|
+
cellEl.style.border = "1px solid #cbd5e1";
|
|
5393
|
+
cellEl.style.verticalAlign = "top";
|
|
5394
|
+
cellEl.style.color = isHeader ? "#0f172a" : "#1e293b";
|
|
5395
|
+
cellEl.style.fontWeight = isHeader ? "600" : "normal";
|
|
5396
|
+
if (table.colPercents && table.colPercents[cIdx]) {
|
|
5397
|
+
cellEl.style.width = `${table.colPercents[cIdx]}%`;
|
|
5398
|
+
}
|
|
5399
|
+
if (/^\d+$/.test(cellText.trim()) || cellText.trim() === "#") {
|
|
5400
|
+
cellEl.style.textAlign = "center";
|
|
5401
|
+
} else {
|
|
5402
|
+
cellEl.style.textAlign = "left";
|
|
5403
|
+
}
|
|
5404
|
+
cellEl.textContent = cellText;
|
|
5405
|
+
tr.appendChild(cellEl);
|
|
5406
|
+
});
|
|
5407
|
+
if (isHeader) {
|
|
5408
|
+
thead.appendChild(tr);
|
|
5409
|
+
} else {
|
|
5410
|
+
tbody.appendChild(tr);
|
|
5411
|
+
}
|
|
5412
|
+
});
|
|
5413
|
+
tableEl.appendChild(thead);
|
|
5414
|
+
tableEl.appendChild(tbody);
|
|
5415
|
+
return tableEl;
|
|
5416
|
+
}
|
|
4516
5417
|
var RtfPlugin = class {
|
|
4517
5418
|
id = "rtf";
|
|
4518
5419
|
name = "Rich Text Format (RTF)";
|
|
@@ -4527,29 +5428,35 @@ var RtfPlugin = class {
|
|
|
4527
5428
|
getToolbarActions(instance) {
|
|
4528
5429
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4529
5430
|
const actions = [];
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
if (
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
instance.goToPage?.(page);
|
|
4548
|
-
}
|
|
5431
|
+
actions.push({
|
|
5432
|
+
id: "page-nav",
|
|
5433
|
+
icon: "",
|
|
5434
|
+
label: "Page Navigation",
|
|
5435
|
+
type: "page-nav",
|
|
5436
|
+
group: "navigation",
|
|
5437
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5438
|
+
max: totalPages,
|
|
5439
|
+
execute: (action, page) => {
|
|
5440
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5441
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5442
|
+
if (action === "prev") {
|
|
5443
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5444
|
+
} else if (action === "next") {
|
|
5445
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5446
|
+
} else if (typeof page === "number") {
|
|
5447
|
+
instance.goToPage?.(page);
|
|
4549
5448
|
}
|
|
4550
|
-
}
|
|
4551
|
-
}
|
|
5449
|
+
}
|
|
5450
|
+
});
|
|
4552
5451
|
actions.push(
|
|
5452
|
+
{
|
|
5453
|
+
id: "thumbnails",
|
|
5454
|
+
icon: "thumbnails",
|
|
5455
|
+
label: "Thumbnails",
|
|
5456
|
+
type: "button",
|
|
5457
|
+
group: "view",
|
|
5458
|
+
execute: () => instance.toggleThumbnails?.()
|
|
5459
|
+
},
|
|
4553
5460
|
{
|
|
4554
5461
|
id: "zoom-out",
|
|
4555
5462
|
icon: "zoom-out",
|
|
@@ -4620,67 +5527,143 @@ var RtfPlugin = class {
|
|
|
4620
5527
|
async render(ctx) {
|
|
4621
5528
|
const wrapper = document.createElement("div");
|
|
4622
5529
|
wrapper.className = "fp-rtf-wrapper";
|
|
4623
|
-
wrapper.style.padding = "
|
|
4624
|
-
wrapper.style.
|
|
5530
|
+
wrapper.style.padding = "0";
|
|
5531
|
+
wrapper.style.width = "816px";
|
|
4625
5532
|
wrapper.style.margin = "0 auto";
|
|
4626
|
-
wrapper.style.
|
|
4627
|
-
wrapper.style.
|
|
4628
|
-
wrapper.style.
|
|
4629
|
-
wrapper.style.
|
|
5533
|
+
wrapper.style.boxSizing = "border-box";
|
|
5534
|
+
wrapper.style.display = "flex";
|
|
5535
|
+
wrapper.style.flexDirection = "column";
|
|
5536
|
+
wrapper.style.alignItems = "center";
|
|
5537
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4630
5538
|
wrapper.style.transformOrigin = "top center";
|
|
4631
|
-
wrapper.style.transition = "transform 0.
|
|
4632
|
-
ctx.container.style.
|
|
4633
|
-
ctx.container.style.
|
|
5539
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5540
|
+
ctx.container.style.overflowX = "hidden";
|
|
5541
|
+
ctx.container.style.overflowY = "auto";
|
|
5542
|
+
ctx.container.style.padding = "16px 8px";
|
|
4634
5543
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
4635
5544
|
ctx.container.appendChild(wrapper);
|
|
4636
5545
|
let scale = 1;
|
|
4637
5546
|
let rotation = 0;
|
|
4638
5547
|
let pageElements = [];
|
|
4639
|
-
let
|
|
5548
|
+
let isUserZoomed = false;
|
|
5549
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
4640
5550
|
const calculateFitScale = (mode = fitMode) => {
|
|
4641
5551
|
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4642
|
-
const elW =
|
|
4643
|
-
const singlePageH =
|
|
4644
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
4645
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
5552
|
+
const elW = 816;
|
|
5553
|
+
const singlePageH = activeEl?.offsetHeight || 1056;
|
|
5554
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
5555
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
4646
5556
|
const sW = availW / elW;
|
|
4647
5557
|
const sH = availH / singlePageH;
|
|
4648
5558
|
if (mode === "page") {
|
|
4649
|
-
return Math.max(0.
|
|
5559
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
4650
5560
|
}
|
|
4651
|
-
return Math.max(0.
|
|
5561
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
4652
5562
|
};
|
|
4653
5563
|
const applyTransform = () => {
|
|
4654
5564
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4655
5565
|
wrapper.style.transformOrigin = "top center";
|
|
5566
|
+
const activeEl = pageElements[currentPage - 1];
|
|
5567
|
+
const baseH = activeEl?.offsetHeight || 1056;
|
|
5568
|
+
const scaledH = baseH * scale;
|
|
5569
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
5570
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
4656
5571
|
};
|
|
5572
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
5573
|
+
if (!isUserZoomed) {
|
|
5574
|
+
scale = calculateFitScale(fitMode);
|
|
5575
|
+
applyTransform();
|
|
5576
|
+
}
|
|
5577
|
+
}) : null;
|
|
5578
|
+
resizeObserver?.observe(ctx.container);
|
|
4657
5579
|
setTimeout(() => {
|
|
4658
|
-
|
|
4659
|
-
scale = calculateFitScale("width");
|
|
5580
|
+
scale = calculateFitScale(fitMode);
|
|
4660
5581
|
applyTransform();
|
|
4661
5582
|
}, 60);
|
|
4662
5583
|
try {
|
|
4663
5584
|
if (typeof RTFJS__namespace.loggingEnabled === "function") {
|
|
4664
5585
|
RTFJS__namespace.loggingEnabled(false);
|
|
4665
5586
|
}
|
|
5587
|
+
const rawText = new TextDecoder("latin1").decode(ctx.buffer);
|
|
5588
|
+
const tables = parseRtfTables(rawText);
|
|
4666
5589
|
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
4667
5590
|
const htmlElements = await doc.render();
|
|
4668
5591
|
const contentNodes = [];
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
5592
|
+
const extractBlocks = (nodes) => {
|
|
5593
|
+
for (const item of nodes) {
|
|
5594
|
+
if (!item || !(item instanceof HTMLElement)) continue;
|
|
5595
|
+
const tag = item.tagName.toLowerCase();
|
|
5596
|
+
const hasChildBlocks = Array.from(item.children).some((c) => {
|
|
5597
|
+
const ct = c.tagName.toLowerCase();
|
|
5598
|
+
return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
|
|
5599
|
+
});
|
|
5600
|
+
if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
|
|
5601
|
+
extractBlocks(Array.from(item.children));
|
|
5602
|
+
} else {
|
|
5603
|
+
const svgs = item.querySelectorAll("svg, img");
|
|
5604
|
+
svgs.forEach((s) => {
|
|
5605
|
+
const el = s;
|
|
5606
|
+
el.style.maxWidth = "100%";
|
|
5607
|
+
el.style.maxHeight = "360px";
|
|
5608
|
+
el.style.display = "block";
|
|
5609
|
+
el.style.margin = "12px auto";
|
|
5610
|
+
if (s.tagName.toLowerCase() === "svg") {
|
|
5611
|
+
s.removeAttribute("width");
|
|
5612
|
+
s.removeAttribute("height");
|
|
5613
|
+
el.style.width = "100%";
|
|
5614
|
+
el.style.maxHeight = "360px";
|
|
5615
|
+
}
|
|
5616
|
+
});
|
|
5617
|
+
if (tag === "p" || tag === "div") {
|
|
5618
|
+
item.style.display = "block";
|
|
5619
|
+
item.style.marginBottom = "12px";
|
|
5620
|
+
item.style.lineHeight = "1.6";
|
|
5621
|
+
}
|
|
5622
|
+
contentNodes.push(item);
|
|
5623
|
+
}
|
|
4674
5624
|
}
|
|
4675
|
-
}
|
|
5625
|
+
};
|
|
5626
|
+
extractBlocks(htmlElements);
|
|
5627
|
+
tables.forEach((table) => {
|
|
5628
|
+
const tableEl = renderRtfTableElement(table);
|
|
5629
|
+
let inserted = false;
|
|
5630
|
+
if (table.anchorBefore && table.anchorBefore.length > 10) {
|
|
5631
|
+
const keyword = table.anchorBefore.slice(-35).trim();
|
|
5632
|
+
for (let i = 0; i < contentNodes.length; i++) {
|
|
5633
|
+
if (contentNodes[i].textContent?.includes(keyword)) {
|
|
5634
|
+
contentNodes.splice(i + 1, 0, tableEl);
|
|
5635
|
+
inserted = true;
|
|
5636
|
+
break;
|
|
5637
|
+
}
|
|
5638
|
+
}
|
|
5639
|
+
}
|
|
5640
|
+
if (!inserted && table.anchorAfter && table.anchorAfter.length > 10) {
|
|
5641
|
+
const keyword = table.anchorAfter.slice(0, 35).trim();
|
|
5642
|
+
for (let i = 0; i < contentNodes.length; i++) {
|
|
5643
|
+
if (contentNodes[i].textContent?.includes(keyword)) {
|
|
5644
|
+
contentNodes.splice(i, 0, tableEl);
|
|
5645
|
+
inserted = true;
|
|
5646
|
+
break;
|
|
5647
|
+
}
|
|
5648
|
+
}
|
|
5649
|
+
}
|
|
5650
|
+
if (!inserted) {
|
|
5651
|
+
if (contentNodes.length > 2) {
|
|
5652
|
+
contentNodes.splice(2, 0, tableEl);
|
|
5653
|
+
} else {
|
|
5654
|
+
contentNodes.push(tableEl);
|
|
5655
|
+
}
|
|
5656
|
+
}
|
|
5657
|
+
});
|
|
4676
5658
|
wrapper.innerHTML = "";
|
|
4677
5659
|
contentNodes.forEach((node) => wrapper.appendChild(node));
|
|
4678
5660
|
const childHeights = contentNodes.map((c) => {
|
|
4679
5661
|
const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
|
|
4680
5662
|
const offH = c.offsetHeight || 0;
|
|
5663
|
+
const realH = Math.max(rectH, offH);
|
|
5664
|
+
if (realH > 0) return realH;
|
|
4681
5665
|
const textLen = c.textContent?.trim().length || 0;
|
|
4682
|
-
|
|
4683
|
-
return Math.max(rectH, offH, estH);
|
|
5666
|
+
return Math.max(24, Math.ceil(textLen / 95) * 22 + 12);
|
|
4684
5667
|
});
|
|
4685
5668
|
wrapper.innerHTML = "";
|
|
4686
5669
|
const createRtfCard = () => {
|
|
@@ -4689,35 +5672,49 @@ var RtfPlugin = class {
|
|
|
4689
5672
|
card.style.backgroundColor = "#ffffff";
|
|
4690
5673
|
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
4691
5674
|
card.style.borderRadius = "4px";
|
|
4692
|
-
card.style.padding = "
|
|
5675
|
+
card.style.padding = "64px 56px";
|
|
4693
5676
|
card.style.width = "816px";
|
|
4694
5677
|
card.style.minHeight = "1056px";
|
|
4695
5678
|
card.style.boxSizing = "border-box";
|
|
4696
5679
|
card.style.marginBottom = "24px";
|
|
4697
5680
|
card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4698
5681
|
card.style.lineHeight = "1.6";
|
|
5682
|
+
card.style.color = "#1e293b";
|
|
4699
5683
|
return card;
|
|
4700
5684
|
};
|
|
4701
5685
|
let curCard = createRtfCard();
|
|
4702
5686
|
wrapper.appendChild(curCard);
|
|
4703
5687
|
pageElements = [curCard];
|
|
4704
5688
|
let curH = 0;
|
|
4705
|
-
const maxH =
|
|
5689
|
+
const maxH = 928;
|
|
4706
5690
|
for (let i = 0; i < contentNodes.length; i++) {
|
|
4707
5691
|
const child = contentNodes[i];
|
|
4708
5692
|
const chH = childHeights[i];
|
|
4709
|
-
|
|
4710
|
-
curH
|
|
4711
|
-
|
|
5693
|
+
const isChildEmpty = (child.textContent || "").trim().length === 0 && !child.querySelector("table, img, svg, canvas");
|
|
5694
|
+
if (curH === 0 && isChildEmpty) {
|
|
5695
|
+
continue;
|
|
5696
|
+
}
|
|
5697
|
+
if (curH + chH > maxH && curCard.childNodes.length > 0) {
|
|
4712
5698
|
curCard = createRtfCard();
|
|
4713
5699
|
wrapper.appendChild(curCard);
|
|
4714
5700
|
pageElements.push(curCard);
|
|
4715
5701
|
curH = 0;
|
|
4716
5702
|
}
|
|
5703
|
+
curCard.appendChild(child);
|
|
5704
|
+
curH += chH;
|
|
5705
|
+
}
|
|
5706
|
+
pageElements = pageElements.filter((card) => {
|
|
5707
|
+
const hasText = (card.textContent || "").trim().length > 0;
|
|
5708
|
+
const hasMedia = card.querySelector("table, img, svg, canvas") !== null;
|
|
5709
|
+
return hasText || hasMedia;
|
|
5710
|
+
});
|
|
5711
|
+
if (pageElements.length === 0) {
|
|
5712
|
+
pageElements = [curCard];
|
|
4717
5713
|
}
|
|
4718
5714
|
} catch (err) {
|
|
4719
5715
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
4720
5716
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
5717
|
+
const tables = parseRtfTables(text);
|
|
4721
5718
|
const rawPages = text.split(/\\page\b/).map((segment) => {
|
|
4722
5719
|
return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
|
|
4723
5720
|
}).filter((p) => p.length > 0);
|
|
@@ -4728,47 +5725,26 @@ var RtfPlugin = class {
|
|
|
4728
5725
|
pageCard.style.backgroundColor = "#ffffff";
|
|
4729
5726
|
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4730
5727
|
pageCard.style.borderRadius = "4px";
|
|
4731
|
-
pageCard.style.padding = "
|
|
5728
|
+
pageCard.style.padding = "64px 56px";
|
|
4732
5729
|
pageCard.style.width = "816px";
|
|
4733
5730
|
pageCard.style.minHeight = "1056px";
|
|
4734
|
-
pageCard.style.maxWidth = "100%";
|
|
4735
5731
|
pageCard.style.boxSizing = "border-box";
|
|
4736
|
-
pageCard.style.fontFamily = "serif
|
|
5732
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4737
5733
|
pageCard.style.fontSize = "12pt";
|
|
4738
5734
|
pageCard.style.lineHeight = "1.6";
|
|
4739
5735
|
pageCard.style.color = "#1e293b";
|
|
4740
5736
|
pageCard.style.whiteSpace = "pre-wrap";
|
|
4741
5737
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4742
5738
|
pageCard.textContent = pages[i];
|
|
5739
|
+
if (i === 1 && tables.length > 0) {
|
|
5740
|
+
tables.forEach((tbl) => pageCard.appendChild(renderRtfTableElement(tbl)));
|
|
5741
|
+
}
|
|
4743
5742
|
wrapper.appendChild(pageCard);
|
|
4744
5743
|
pageElements.push(pageCard);
|
|
4745
5744
|
}
|
|
4746
5745
|
}
|
|
4747
5746
|
const totalPages = Math.max(1, pageElements.length);
|
|
4748
5747
|
let currentPage = 1;
|
|
4749
|
-
let indicator = null;
|
|
4750
|
-
if (totalPages > 1) {
|
|
4751
|
-
indicator = document.createElement("div");
|
|
4752
|
-
indicator.className = "fp-rtf-page-indicator";
|
|
4753
|
-
indicator.style.position = "sticky";
|
|
4754
|
-
indicator.style.bottom = "16px";
|
|
4755
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4756
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
4757
|
-
indicator.style.color = "#f8fafc";
|
|
4758
|
-
indicator.style.fontSize = "12px";
|
|
4759
|
-
indicator.style.fontWeight = "600";
|
|
4760
|
-
indicator.style.padding = "5px 14px";
|
|
4761
|
-
indicator.style.borderRadius = "20px";
|
|
4762
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4763
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4764
|
-
indicator.style.zIndex = "10";
|
|
4765
|
-
indicator.style.userSelect = "none";
|
|
4766
|
-
indicator.style.pointerEvents = "none";
|
|
4767
|
-
indicator.style.textAlign = "center";
|
|
4768
|
-
indicator.style.width = "fit-content";
|
|
4769
|
-
indicator.style.margin = "16px auto 0";
|
|
4770
|
-
ctx.container.appendChild(indicator);
|
|
4771
|
-
}
|
|
4772
5748
|
const showPage = (pageNum) => {
|
|
4773
5749
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4774
5750
|
if (totalPages > 1) {
|
|
@@ -4776,9 +5752,6 @@ var RtfPlugin = class {
|
|
|
4776
5752
|
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4777
5753
|
});
|
|
4778
5754
|
}
|
|
4779
|
-
if (indicator) {
|
|
4780
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4781
|
-
}
|
|
4782
5755
|
ctx.container.scrollTop = 0;
|
|
4783
5756
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4784
5757
|
};
|
|
@@ -4786,7 +5759,7 @@ var RtfPlugin = class {
|
|
|
4786
5759
|
showPage(1);
|
|
4787
5760
|
}
|
|
4788
5761
|
const cleanup = () => {
|
|
4789
|
-
|
|
5762
|
+
resizeObserver?.disconnect();
|
|
4790
5763
|
wrapper.remove();
|
|
4791
5764
|
ctx.container.innerHTML = "";
|
|
4792
5765
|
};
|
|
@@ -4796,22 +5769,52 @@ var RtfPlugin = class {
|
|
|
4796
5769
|
getPageCount: () => totalPages,
|
|
4797
5770
|
getCurrentPage: () => currentPage,
|
|
4798
5771
|
goToPage: (page) => showPage(page),
|
|
5772
|
+
getThumbnails: async () => {
|
|
5773
|
+
const items = [];
|
|
5774
|
+
for (let idx = 0; idx < totalPages; idx++) {
|
|
5775
|
+
const pageIdx = idx;
|
|
5776
|
+
items.push({
|
|
5777
|
+
index: pageIdx,
|
|
5778
|
+
label: `Page ${pageIdx + 1}`,
|
|
5779
|
+
render: async (canvas) => {
|
|
5780
|
+
const ctx2d = canvas.getContext("2d");
|
|
5781
|
+
if (!ctx2d) return;
|
|
5782
|
+
canvas.width = 140;
|
|
5783
|
+
canvas.height = 180;
|
|
5784
|
+
ctx2d.fillStyle = "#ffffff";
|
|
5785
|
+
ctx2d.fillRect(0, 0, 140, 180);
|
|
5786
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
5787
|
+
ctx2d.lineWidth = 1;
|
|
5788
|
+
ctx2d.strokeRect(0.5, 0.5, 139, 179);
|
|
5789
|
+
ctx2d.fillStyle = "#334155";
|
|
5790
|
+
ctx2d.font = 'bold 11px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
5791
|
+
ctx2d.textAlign = "center";
|
|
5792
|
+
ctx2d.fillText(`Page ${pageIdx + 1}`, 70, 95);
|
|
5793
|
+
}
|
|
5794
|
+
});
|
|
5795
|
+
}
|
|
5796
|
+
return items;
|
|
5797
|
+
},
|
|
4799
5798
|
zoomIn: () => {
|
|
5799
|
+
isUserZoomed = true;
|
|
4800
5800
|
scale += 0.15;
|
|
4801
5801
|
applyTransform();
|
|
4802
5802
|
},
|
|
4803
5803
|
zoomOut: () => {
|
|
5804
|
+
isUserZoomed = true;
|
|
4804
5805
|
scale = Math.max(0.2, scale - 0.15);
|
|
4805
5806
|
applyTransform();
|
|
4806
5807
|
},
|
|
4807
5808
|
getZoom: () => scale,
|
|
4808
5809
|
setZoom: (level) => {
|
|
5810
|
+
isUserZoomed = true;
|
|
4809
5811
|
scale = level;
|
|
4810
5812
|
applyTransform();
|
|
4811
5813
|
},
|
|
4812
5814
|
fitToPage: () => {
|
|
4813
|
-
|
|
4814
|
-
|
|
5815
|
+
isUserZoomed = false;
|
|
5816
|
+
fitMode = "width";
|
|
5817
|
+
scale = calculateFitScale("width");
|
|
4815
5818
|
rotation = 0;
|
|
4816
5819
|
applyTransform();
|
|
4817
5820
|
},
|
|
@@ -4999,40 +6002,36 @@ var OpenDocumentPlugin = class {
|
|
|
4999
6002
|
const isPresentation = instance.isPresentation;
|
|
5000
6003
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5001
6004
|
const actions = [];
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
max
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
if (
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
instance.goToPage?.(page);
|
|
5030
|
-
} else if (typeof action === "number") {
|
|
5031
|
-
instance.goToPage?.(action);
|
|
5032
|
-
}
|
|
6005
|
+
actions.push({
|
|
6006
|
+
id: "thumbnails",
|
|
6007
|
+
icon: "thumbnails",
|
|
6008
|
+
label: isPresentation ? "Slide Thumbnails" : "Page Thumbnails",
|
|
6009
|
+
type: "button",
|
|
6010
|
+
group: "navigation",
|
|
6011
|
+
execute: () => instance.toggleThumbnails?.()
|
|
6012
|
+
});
|
|
6013
|
+
actions.push({
|
|
6014
|
+
id: "page-nav",
|
|
6015
|
+
icon: "",
|
|
6016
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
6017
|
+
type: "page-nav",
|
|
6018
|
+
group: "navigation",
|
|
6019
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
6020
|
+
max: totalPages,
|
|
6021
|
+
execute: (action, page) => {
|
|
6022
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
6023
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
6024
|
+
if (action === "prev") {
|
|
6025
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
6026
|
+
} else if (action === "next") {
|
|
6027
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
6028
|
+
} else if (typeof page === "number") {
|
|
6029
|
+
instance.goToPage?.(page);
|
|
6030
|
+
} else if (typeof action === "number") {
|
|
6031
|
+
instance.goToPage?.(action);
|
|
5033
6032
|
}
|
|
5034
|
-
}
|
|
5035
|
-
}
|
|
6033
|
+
}
|
|
6034
|
+
});
|
|
5036
6035
|
actions.push(
|
|
5037
6036
|
{
|
|
5038
6037
|
id: "zoom-out",
|
|
@@ -5123,49 +6122,65 @@ var OpenDocumentPlugin = class {
|
|
|
5123
6122
|
container.className = "fp-odf-container";
|
|
5124
6123
|
container.style.width = "100%";
|
|
5125
6124
|
container.style.height = "100%";
|
|
5126
|
-
container.style.
|
|
5127
|
-
container.style.
|
|
6125
|
+
container.style.overflowX = "hidden";
|
|
6126
|
+
container.style.overflowY = "auto";
|
|
6127
|
+
container.style.padding = "16px 8px";
|
|
5128
6128
|
container.style.backgroundColor = "#f1f5f9";
|
|
5129
6129
|
const wrapper = document.createElement("div");
|
|
5130
6130
|
wrapper.className = "fp-odf-wrapper";
|
|
5131
6131
|
wrapper.style.margin = "0 auto";
|
|
6132
|
+
wrapper.style.width = isPresentation ? "960px" : "816px";
|
|
6133
|
+
wrapper.style.boxSizing = "border-box";
|
|
5132
6134
|
wrapper.style.backgroundColor = "#ffffff";
|
|
5133
6135
|
wrapper.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
5134
6136
|
wrapper.style.borderRadius = "4px";
|
|
5135
6137
|
wrapper.style.transformOrigin = "top center";
|
|
5136
|
-
wrapper.style.transition = "transform 0.
|
|
6138
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5137
6139
|
container.appendChild(wrapper);
|
|
5138
6140
|
ctx.container.appendChild(container);
|
|
5139
6141
|
let scale = 1;
|
|
5140
6142
|
let rotation = 0;
|
|
5141
|
-
let
|
|
6143
|
+
let isUserZoomed = false;
|
|
6144
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6145
|
+
let currentPage = 1;
|
|
6146
|
+
let totalPages = 1;
|
|
6147
|
+
let slides = [];
|
|
5142
6148
|
const calculateFitScale = (mode = fitMode) => {
|
|
5143
|
-
const
|
|
5144
|
-
const
|
|
5145
|
-
const
|
|
5146
|
-
const
|
|
6149
|
+
const activeSlide = slides[currentPage - 1];
|
|
6150
|
+
const elW = isPresentation ? 960 : 816;
|
|
6151
|
+
const singlePageH = Math.min(activeSlide?.offsetHeight || wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
6152
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6153
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5147
6154
|
const sW = availW / elW;
|
|
5148
6155
|
const sH = availH / (isPresentation ? 540 : singlePageH);
|
|
5149
6156
|
if (isPresentation) {
|
|
5150
|
-
return Math.min(
|
|
6157
|
+
return Math.min(2.5, Math.min(sW, sH));
|
|
5151
6158
|
}
|
|
5152
6159
|
if (mode === "page") {
|
|
5153
|
-
return Math.max(0.
|
|
6160
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5154
6161
|
}
|
|
5155
|
-
return Math.max(0.
|
|
6162
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5156
6163
|
};
|
|
5157
6164
|
const applyTransform = () => {
|
|
5158
6165
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5159
6166
|
wrapper.style.transformOrigin = "top center";
|
|
6167
|
+
const activeSlide = slides[currentPage - 1];
|
|
6168
|
+
const baseH = activeSlide?.offsetHeight || wrapper.offsetHeight || 1056;
|
|
6169
|
+
const scaledH = baseH * scale;
|
|
6170
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6171
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
5160
6172
|
};
|
|
6173
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6174
|
+
if (!isUserZoomed) {
|
|
6175
|
+
scale = calculateFitScale(fitMode);
|
|
6176
|
+
applyTransform();
|
|
6177
|
+
}
|
|
6178
|
+
}) : null;
|
|
6179
|
+
resizeObserver?.observe(ctx.container);
|
|
5161
6180
|
setTimeout(() => {
|
|
5162
|
-
|
|
5163
|
-
scale = calculateFitScale("width");
|
|
6181
|
+
scale = calculateFitScale(fitMode);
|
|
5164
6182
|
applyTransform();
|
|
5165
6183
|
}, 60);
|
|
5166
|
-
let currentPage = 1;
|
|
5167
|
-
let totalPages = 1;
|
|
5168
|
-
let slides = [];
|
|
5169
6184
|
if (isPresentation) {
|
|
5170
6185
|
wrapper.style.maxWidth = "960px";
|
|
5171
6186
|
wrapper.style.aspectRatio = "16 / 9";
|
|
@@ -5266,24 +6281,9 @@ var OpenDocumentPlugin = class {
|
|
|
5266
6281
|
wrapper.appendChild(page);
|
|
5267
6282
|
slides.push(page);
|
|
5268
6283
|
});
|
|
5269
|
-
const pageIndicator = document.createElement("div");
|
|
5270
|
-
pageIndicator.className = "fp-odt-page-indicator";
|
|
5271
|
-
pageIndicator.style.position = "sticky";
|
|
5272
|
-
pageIndicator.style.bottom = "16px";
|
|
5273
|
-
pageIndicator.style.left = "50%";
|
|
5274
|
-
pageIndicator.style.transform = "translateX(-50%)";
|
|
5275
|
-
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
5276
|
-
pageIndicator.style.color = "#fff";
|
|
5277
|
-
pageIndicator.style.padding = "6px 12px";
|
|
5278
|
-
pageIndicator.style.borderRadius = "16px";
|
|
5279
|
-
pageIndicator.style.fontSize = "12px";
|
|
5280
|
-
pageIndicator.style.zIndex = "100";
|
|
5281
|
-
pageIndicator.style.display = "inline-block";
|
|
5282
|
-
pageIndicator.style.width = "fit-content";
|
|
5283
|
-
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
5284
|
-
container.appendChild(pageIndicator);
|
|
5285
6284
|
}
|
|
5286
6285
|
const cleanup = () => {
|
|
6286
|
+
resizeObserver?.disconnect();
|
|
5287
6287
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
5288
6288
|
container.remove();
|
|
5289
6289
|
ctx.container.innerHTML = "";
|
|
@@ -5295,10 +6295,6 @@ var OpenDocumentPlugin = class {
|
|
|
5295
6295
|
slides.forEach((s, idx) => {
|
|
5296
6296
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
5297
6297
|
});
|
|
5298
|
-
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
5299
|
-
if (indicator) {
|
|
5300
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5301
|
-
}
|
|
5302
6298
|
container.scrollTop = 0;
|
|
5303
6299
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5304
6300
|
};
|
|
@@ -5306,21 +6302,25 @@ var OpenDocumentPlugin = class {
|
|
|
5306
6302
|
destroy: cleanup,
|
|
5307
6303
|
isPresentation,
|
|
5308
6304
|
zoomIn: () => {
|
|
6305
|
+
isUserZoomed = true;
|
|
5309
6306
|
scale += 0.15;
|
|
5310
6307
|
applyTransform();
|
|
5311
6308
|
},
|
|
5312
6309
|
zoomOut: () => {
|
|
6310
|
+
isUserZoomed = true;
|
|
5313
6311
|
scale = Math.max(0.2, scale - 0.15);
|
|
5314
6312
|
applyTransform();
|
|
5315
6313
|
},
|
|
5316
6314
|
getZoom: () => scale,
|
|
5317
6315
|
setZoom: (level) => {
|
|
6316
|
+
isUserZoomed = true;
|
|
5318
6317
|
scale = level;
|
|
5319
6318
|
applyTransform();
|
|
5320
6319
|
},
|
|
5321
6320
|
fitToPage: () => {
|
|
5322
|
-
|
|
5323
|
-
|
|
6321
|
+
isUserZoomed = false;
|
|
6322
|
+
fitMode = "width";
|
|
6323
|
+
scale = calculateFitScale("width");
|
|
5324
6324
|
rotation = 0;
|
|
5325
6325
|
applyTransform();
|
|
5326
6326
|
},
|
|
@@ -5336,23 +6336,45 @@ var OpenDocumentPlugin = class {
|
|
|
5336
6336
|
getPageCount: () => totalPages,
|
|
5337
6337
|
getCurrentPage: () => currentPage,
|
|
5338
6338
|
getThumbnails: async () => {
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
canvas
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
6339
|
+
const count = totalPages || slides.length || 1;
|
|
6340
|
+
const items = [];
|
|
6341
|
+
for (let idx = 0; idx < count; idx++) {
|
|
6342
|
+
const itemIdx = idx;
|
|
6343
|
+
items.push({
|
|
6344
|
+
index: itemIdx,
|
|
6345
|
+
label: isPresentation ? `Slide ${itemIdx + 1}` : `Page ${itemIdx + 1}`,
|
|
6346
|
+
render: async (canvas) => {
|
|
6347
|
+
const ctx2d = canvas.getContext("2d");
|
|
6348
|
+
if (!ctx2d) return;
|
|
6349
|
+
if (isPresentation) {
|
|
6350
|
+
canvas.width = 160;
|
|
6351
|
+
canvas.height = 90;
|
|
6352
|
+
ctx2d.fillStyle = "#f8fafc";
|
|
6353
|
+
ctx2d.fillRect(0, 0, 160, 90);
|
|
6354
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6355
|
+
ctx2d.lineWidth = 1;
|
|
6356
|
+
ctx2d.strokeRect(0.5, 0.5, 159, 89);
|
|
6357
|
+
ctx2d.fillStyle = "#334155";
|
|
6358
|
+
ctx2d.font = "bold 11px sans-serif";
|
|
6359
|
+
ctx2d.textAlign = "center";
|
|
6360
|
+
ctx2d.fillText(`Slide ${itemIdx + 1}`, 80, 50);
|
|
6361
|
+
} else {
|
|
6362
|
+
canvas.width = 140;
|
|
6363
|
+
canvas.height = 180;
|
|
6364
|
+
ctx2d.fillStyle = "#ffffff";
|
|
6365
|
+
ctx2d.fillRect(0, 0, 140, 180);
|
|
6366
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6367
|
+
ctx2d.lineWidth = 1;
|
|
6368
|
+
ctx2d.strokeRect(0.5, 0.5, 139, 179);
|
|
6369
|
+
ctx2d.fillStyle = "#64748b";
|
|
6370
|
+
ctx2d.font = "bold 10px sans-serif";
|
|
6371
|
+
ctx2d.textAlign = "center";
|
|
6372
|
+
ctx2d.fillText(`Page ${itemIdx + 1}`, 70, 90);
|
|
6373
|
+
}
|
|
6374
|
+
}
|
|
6375
|
+
});
|
|
6376
|
+
}
|
|
6377
|
+
return items;
|
|
5356
6378
|
},
|
|
5357
6379
|
download: () => {
|
|
5358
6380
|
const mimeType = this.mimeTypes.find((m) => m.includes(ext.replace(".", ""))) || "application/octet-stream";
|
|
@@ -5457,23 +6479,24 @@ var OpenDocumentPlugin = class {
|
|
|
5457
6479
|
case "h": {
|
|
5458
6480
|
const level = Math.min(6, Math.max(1, Number(node.getAttribute("text:outline-level") || 1)));
|
|
5459
6481
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5460
|
-
html += `<h${level} style="${style}; font-family:
|
|
6482
|
+
html += `<h${level} style="${style}; margin: 18px 0 8px; color: #1e3a8a; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${node.textContent || ""}</h${level}>`;
|
|
5461
6483
|
break;
|
|
5462
6484
|
}
|
|
5463
6485
|
case "p": {
|
|
5464
6486
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5465
6487
|
const inner = this.renderSpans(node, styles, images);
|
|
5466
|
-
|
|
6488
|
+
const isInsideLi = node.parentElement?.localName === "list-item" || node.parentElement?.tagName?.toLowerCase() === "list-item";
|
|
6489
|
+
html += `<p style="${style}; line-height: 1.5; margin: ${isInsideLi ? "0" : "8px 0 12px"}; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${inner}</p>`;
|
|
5467
6490
|
break;
|
|
5468
6491
|
}
|
|
5469
6492
|
case "list": {
|
|
5470
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
6493
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
5471
6494
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5472
6495
|
html += "</ul>";
|
|
5473
6496
|
break;
|
|
5474
6497
|
}
|
|
5475
6498
|
case "list-item": {
|
|
5476
|
-
html +=
|
|
6499
|
+
html += '<li style="margin: 4px 0; font-size: 11pt; line-height: 1.5; color: #1e293b;">';
|
|
5477
6500
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5478
6501
|
html += "</li>";
|
|
5479
6502
|
break;
|
|
@@ -5599,28 +6622,26 @@ var DocPlugin = class {
|
|
|
5599
6622
|
getToolbarActions(instance) {
|
|
5600
6623
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5601
6624
|
const actions = [];
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
if (
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
instance.goToPage?.(page);
|
|
5620
|
-
}
|
|
6625
|
+
actions.push({
|
|
6626
|
+
id: "page-nav",
|
|
6627
|
+
icon: "",
|
|
6628
|
+
label: "Page Navigation",
|
|
6629
|
+
type: "page-nav",
|
|
6630
|
+
group: "navigation",
|
|
6631
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
6632
|
+
max: totalPages,
|
|
6633
|
+
execute: (action, page) => {
|
|
6634
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
6635
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
6636
|
+
if (action === "prev") {
|
|
6637
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
6638
|
+
} else if (action === "next") {
|
|
6639
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
6640
|
+
} else if (typeof page === "number") {
|
|
6641
|
+
instance.goToPage?.(page);
|
|
5621
6642
|
}
|
|
5622
|
-
}
|
|
5623
|
-
}
|
|
6643
|
+
}
|
|
6644
|
+
});
|
|
5624
6645
|
actions.push(
|
|
5625
6646
|
{
|
|
5626
6647
|
id: "zoom-out",
|
|
@@ -5694,8 +6715,9 @@ var DocPlugin = class {
|
|
|
5694
6715
|
container.className = "fp-doc-container";
|
|
5695
6716
|
container.style.width = "100%";
|
|
5696
6717
|
container.style.height = "100%";
|
|
5697
|
-
container.style.
|
|
5698
|
-
container.style.
|
|
6718
|
+
container.style.overflowX = "hidden";
|
|
6719
|
+
container.style.overflowY = "auto";
|
|
6720
|
+
container.style.padding = "16px 8px";
|
|
5699
6721
|
container.style.backgroundColor = "#f1f5f9";
|
|
5700
6722
|
container.style.display = "flex";
|
|
5701
6723
|
container.style.justifyContent = "center";
|
|
@@ -5740,16 +6762,15 @@ var DocPlugin = class {
|
|
|
5740
6762
|
const pageCard = document.createElement("div");
|
|
5741
6763
|
pageCard.className = "fp-doc-page-card";
|
|
5742
6764
|
pageCard.style.width = "816px";
|
|
5743
|
-
pageCard.style.
|
|
6765
|
+
pageCard.style.minHeight = "1056px";
|
|
5744
6766
|
pageCard.style.backgroundColor = "#ffffff";
|
|
5745
|
-
pageCard.style.boxShadow = "0
|
|
6767
|
+
pageCard.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
5746
6768
|
pageCard.style.borderRadius = "4px";
|
|
5747
|
-
pageCard.style.padding = "
|
|
6769
|
+
pageCard.style.padding = "72px 56px";
|
|
5748
6770
|
pageCard.style.boxSizing = "border-box";
|
|
5749
|
-
pageCard.style.overflow = "hidden";
|
|
5750
6771
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5751
6772
|
pageCard.style.transformOrigin = "top center";
|
|
5752
|
-
pageCard.style.transition = "transform 0.
|
|
6773
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
5753
6774
|
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5754
6775
|
pageCard.style.color = "#1e293b";
|
|
5755
6776
|
if (isFallback && i === 0) {
|
|
@@ -5766,34 +6787,15 @@ var DocPlugin = class {
|
|
|
5766
6787
|
container.appendChild(pageCard);
|
|
5767
6788
|
pageCards.push(pageCard);
|
|
5768
6789
|
}
|
|
5769
|
-
let indicator = null;
|
|
5770
|
-
if (totalPages > 1) {
|
|
5771
|
-
indicator = document.createElement("div");
|
|
5772
|
-
indicator.className = "fp-doc-page-indicator";
|
|
5773
|
-
indicator.style.position = "fixed";
|
|
5774
|
-
indicator.style.bottom = "16px";
|
|
5775
|
-
indicator.style.left = "50%";
|
|
5776
|
-
indicator.style.transform = "translateX(-50%)";
|
|
5777
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
5778
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
5779
|
-
indicator.style.color = "#f8fafc";
|
|
5780
|
-
indicator.style.fontSize = "12px";
|
|
5781
|
-
indicator.style.fontWeight = "600";
|
|
5782
|
-
indicator.style.padding = "5px 14px";
|
|
5783
|
-
indicator.style.borderRadius = "20px";
|
|
5784
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
5785
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
5786
|
-
indicator.style.zIndex = "10";
|
|
5787
|
-
indicator.style.userSelect = "none";
|
|
5788
|
-
indicator.style.pointerEvents = "none";
|
|
5789
|
-
indicator.style.textAlign = "center";
|
|
5790
|
-
container.appendChild(indicator);
|
|
5791
|
-
}
|
|
5792
6790
|
let rotation = 0;
|
|
5793
6791
|
const applyTransform = () => {
|
|
5794
6792
|
const activeCard = pageCards[currentPage - 1];
|
|
5795
6793
|
if (activeCard) {
|
|
5796
6794
|
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
6795
|
+
const baseH = activeCard.offsetHeight || 1056;
|
|
6796
|
+
const scaledH = baseH * scale;
|
|
6797
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6798
|
+
activeCard.style.marginBottom = `${extraH + 32}px`;
|
|
5797
6799
|
}
|
|
5798
6800
|
};
|
|
5799
6801
|
const showPage = (pageNum) => {
|
|
@@ -5806,35 +6808,39 @@ var DocPlugin = class {
|
|
|
5806
6808
|
card.style.display = "none";
|
|
5807
6809
|
}
|
|
5808
6810
|
});
|
|
5809
|
-
if (indicator) {
|
|
5810
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5811
|
-
}
|
|
5812
6811
|
container.scrollTop = 0;
|
|
5813
6812
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5814
6813
|
};
|
|
5815
6814
|
if (totalPages > 1) {
|
|
5816
6815
|
showPage(1);
|
|
5817
6816
|
}
|
|
5818
|
-
let fitMode = "width";
|
|
6817
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6818
|
+
let isUserZoomed = false;
|
|
5819
6819
|
const calculateFitScale = (mode = fitMode) => {
|
|
5820
6820
|
const elW = 816;
|
|
5821
6821
|
const elH = 1056;
|
|
5822
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
5823
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
6822
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6823
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5824
6824
|
const sW = availW / elW;
|
|
5825
6825
|
const sH = availH / elH;
|
|
5826
6826
|
if (mode === "page") {
|
|
5827
|
-
return Math.max(0.
|
|
6827
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5828
6828
|
}
|
|
5829
|
-
return Math.max(0.
|
|
6829
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5830
6830
|
};
|
|
6831
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6832
|
+
if (!isUserZoomed) {
|
|
6833
|
+
scale = calculateFitScale(fitMode);
|
|
6834
|
+
applyTransform();
|
|
6835
|
+
}
|
|
6836
|
+
}) : null;
|
|
6837
|
+
resizeObserver?.observe(ctx.container);
|
|
5831
6838
|
setTimeout(() => {
|
|
5832
|
-
|
|
5833
|
-
scale = calculateFitScale("width");
|
|
6839
|
+
scale = calculateFitScale(fitMode);
|
|
5834
6840
|
applyTransform();
|
|
5835
6841
|
}, 60);
|
|
5836
6842
|
const cleanup = () => {
|
|
5837
|
-
|
|
6843
|
+
resizeObserver?.disconnect();
|
|
5838
6844
|
container.remove();
|
|
5839
6845
|
ctx.container.innerHTML = "";
|
|
5840
6846
|
};
|
|
@@ -5845,21 +6851,25 @@ var DocPlugin = class {
|
|
|
5845
6851
|
getCurrentPage: () => currentPage,
|
|
5846
6852
|
goToPage: (page) => showPage(page),
|
|
5847
6853
|
zoomIn: () => {
|
|
6854
|
+
isUserZoomed = true;
|
|
5848
6855
|
scale += 0.15;
|
|
5849
6856
|
applyTransform();
|
|
5850
6857
|
},
|
|
5851
6858
|
zoomOut: () => {
|
|
6859
|
+
isUserZoomed = true;
|
|
5852
6860
|
scale = Math.max(0.2, scale - 0.15);
|
|
5853
6861
|
applyTransform();
|
|
5854
6862
|
},
|
|
5855
6863
|
getZoom: () => scale,
|
|
5856
6864
|
setZoom: (level) => {
|
|
6865
|
+
isUserZoomed = true;
|
|
5857
6866
|
scale = level;
|
|
5858
6867
|
applyTransform();
|
|
5859
6868
|
},
|
|
5860
6869
|
fitToPage: () => {
|
|
5861
|
-
|
|
5862
|
-
|
|
6870
|
+
isUserZoomed = false;
|
|
6871
|
+
fitMode = "width";
|
|
6872
|
+
scale = calculateFitScale("width");
|
|
5863
6873
|
rotation = 0;
|
|
5864
6874
|
applyTransform();
|
|
5865
6875
|
},
|
|
@@ -6236,25 +7246,31 @@ ${chartSvg}
|
|
|
6236
7246
|
i++;
|
|
6237
7247
|
continue;
|
|
6238
7248
|
}
|
|
6239
|
-
if (
|
|
7249
|
+
if (/^\d{1,2}$/.test(line.trim())) {
|
|
7250
|
+
i++;
|
|
7251
|
+
continue;
|
|
7252
|
+
}
|
|
7253
|
+
const isShortLine = line.length < 60 && !line.endsWith(".") && !line.endsWith(",");
|
|
7254
|
+
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));
|
|
7255
|
+
if (isTitleLike) {
|
|
6240
7256
|
if (inList) {
|
|
6241
7257
|
html += "</ul>";
|
|
6242
7258
|
inList = false;
|
|
6243
7259
|
}
|
|
6244
|
-
html += `<h2 style="font-size:
|
|
7260
|
+
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>`;
|
|
6245
7261
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
6246
7262
|
if (!inList) {
|
|
6247
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
7263
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
6248
7264
|
inList = true;
|
|
6249
7265
|
}
|
|
6250
7266
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
6251
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
7267
|
+
html += `<li style="margin: 4px 0; line-height: 1.5; font-size: 11pt; color: #1e293b;">${DOMPurify6__default.default.sanitize(bulletText, sanitizeOptions)}</li>`;
|
|
6252
7268
|
} else {
|
|
6253
7269
|
if (inList) {
|
|
6254
7270
|
html += "</ul>";
|
|
6255
7271
|
inList = false;
|
|
6256
7272
|
}
|
|
6257
|
-
html += `<p style="line-height: 1.
|
|
7273
|
+
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>`;
|
|
6258
7274
|
}
|
|
6259
7275
|
i++;
|
|
6260
7276
|
}
|
|
@@ -6824,7 +7840,7 @@ var FilePreview = vue.defineComponent({
|
|
|
6824
7840
|
default: () => ({})
|
|
6825
7841
|
}
|
|
6826
7842
|
},
|
|
6827
|
-
emits: ["loading", "loaded", "error", "page-change", "zoom-change"],
|
|
7843
|
+
emits: ["loading", "loaded", "error", "page-change", "zoom-change", "rotate", "destroy"],
|
|
6828
7844
|
setup(props, { emit, expose }) {
|
|
6829
7845
|
const containerRef = vue.ref(null);
|
|
6830
7846
|
let viewer = null;
|
|
@@ -6848,6 +7864,8 @@ var FilePreview = vue.defineComponent({
|
|
|
6848
7864
|
viewer.on("error", (data) => emit("error", data));
|
|
6849
7865
|
viewer.on("page-change", (data) => emit("page-change", data));
|
|
6850
7866
|
viewer.on("zoom-change", (data) => emit("zoom-change", data));
|
|
7867
|
+
viewer.on("rotate", (data) => emit("rotate", data));
|
|
7868
|
+
viewer.on("destroy", (data) => emit("destroy", data));
|
|
6851
7869
|
renderPreview();
|
|
6852
7870
|
});
|
|
6853
7871
|
vue.watch(() => props.src, renderPreview);
|