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