@files-preview-app/preview-file 1.3.1 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -3
- package/dist/angular.cjs +1552 -520
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.d.cts +6 -1
- package/dist/angular.d.ts +6 -1
- package/dist/angular.js +1552 -520
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +1535 -519
- package/dist/index.cjs.map +1 -1
- package/dist/index.d-B79v0jxi.d.cts +570 -0
- package/dist/index.d-B79v0jxi.d.ts +570 -0
- package/dist/index.d.cts +3227 -19
- package/dist/index.d.ts +3227 -19
- package/dist/index.js +1535 -519
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +1539 -519
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +5 -16
- package/dist/react.d.ts +5 -16
- package/dist/react.js +1539 -519
- package/dist/react.js.map +1 -1
- package/dist/styles.css +195 -14
- package/dist/vue.cjs +1538 -520
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.d.cts +4 -2
- package/dist/vue.d.ts +4 -2
- package/dist/vue.js +1538 -520
- package/dist/vue.js.map +1 -1
- package/package.json +2 -2
package/dist/angular.js
CHANGED
|
@@ -542,8 +542,7 @@ var ICON_FULLSCREEN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="non
|
|
|
542
542
|
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>`;
|
|
543
543
|
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>`;
|
|
544
544
|
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>`;
|
|
545
|
-
var
|
|
546
|
-
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>`;
|
|
545
|
+
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>`;
|
|
547
546
|
var ICON_MAP = {
|
|
548
547
|
"zoom-in": ICON_ZOOM_IN,
|
|
549
548
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -570,28 +569,177 @@ var ICON_MAP = {
|
|
|
570
569
|
"forward-10": ICON_FAST_FORWARD,
|
|
571
570
|
"rewind": ICON_REWIND,
|
|
572
571
|
"replay-10": ICON_REWIND,
|
|
573
|
-
"speed": ICON_SPEED,
|
|
574
572
|
"open-window": ICON_EXTERNAL_WINDOW,
|
|
575
|
-
"external-window": ICON_EXTERNAL_WINDOW
|
|
573
|
+
"external-window": ICON_EXTERNAL_WINDOW,
|
|
574
|
+
"openWindow": ICON_EXTERNAL_WINDOW,
|
|
575
|
+
"openSeparateWindow": ICON_EXTERNAL_WINDOW
|
|
576
576
|
};
|
|
577
577
|
var ToolbarController = class {
|
|
578
578
|
el;
|
|
579
579
|
toolbarEl;
|
|
580
580
|
actions = [];
|
|
581
|
+
config = {};
|
|
581
582
|
pageInputEl = null;
|
|
582
583
|
pageLabelEl = null;
|
|
583
|
-
|
|
584
|
+
prevPageBtn = null;
|
|
585
|
+
nextPageBtn = null;
|
|
586
|
+
constructor(container, config) {
|
|
584
587
|
this.el = container;
|
|
588
|
+
if (config) this.config = { ...config };
|
|
585
589
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
586
590
|
this.el.appendChild(this.toolbarEl);
|
|
587
591
|
}
|
|
592
|
+
setConfig(config) {
|
|
593
|
+
this.config = { ...config };
|
|
594
|
+
this.render();
|
|
595
|
+
}
|
|
596
|
+
getConfig() {
|
|
597
|
+
return { ...this.config };
|
|
598
|
+
}
|
|
599
|
+
hideAction(actionId) {
|
|
600
|
+
this.config[actionId] = false;
|
|
601
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = false;
|
|
602
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = false;
|
|
603
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
604
|
+
this.config.fitPage = false;
|
|
605
|
+
this.config.fitToPage = false;
|
|
606
|
+
this.config.fitWidth = false;
|
|
607
|
+
}
|
|
608
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = false;
|
|
609
|
+
if (actionId === "fullscreen") this.config.fullscreen = false;
|
|
610
|
+
if (actionId === "download") this.config.download = false;
|
|
611
|
+
if (actionId === "print") this.config.print = false;
|
|
612
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
613
|
+
this.config.openWindow = false;
|
|
614
|
+
this.config.openSeparateWindow = false;
|
|
615
|
+
}
|
|
616
|
+
if (actionId === "copy") this.config.copy = false;
|
|
617
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
618
|
+
this.config.pageNav = false;
|
|
619
|
+
this.config.pagination = false;
|
|
620
|
+
}
|
|
621
|
+
this.render();
|
|
622
|
+
}
|
|
623
|
+
showAction(actionId) {
|
|
624
|
+
this.config[actionId] = true;
|
|
625
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = true;
|
|
626
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = true;
|
|
627
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
628
|
+
this.config.fitPage = true;
|
|
629
|
+
this.config.fitToPage = true;
|
|
630
|
+
this.config.fitWidth = true;
|
|
631
|
+
}
|
|
632
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = true;
|
|
633
|
+
if (actionId === "fullscreen") this.config.fullscreen = true;
|
|
634
|
+
if (actionId === "download") this.config.download = true;
|
|
635
|
+
if (actionId === "print") this.config.print = true;
|
|
636
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
637
|
+
this.config.openWindow = true;
|
|
638
|
+
this.config.openSeparateWindow = true;
|
|
639
|
+
}
|
|
640
|
+
if (actionId === "copy") this.config.copy = true;
|
|
641
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
642
|
+
this.config.pageNav = true;
|
|
643
|
+
this.config.pagination = true;
|
|
644
|
+
}
|
|
645
|
+
this.render();
|
|
646
|
+
}
|
|
647
|
+
normalizeActionId(actionId) {
|
|
648
|
+
if (actionId === "zoomIn") return "zoom-in";
|
|
649
|
+
if (actionId === "zoomOut") return "zoom-out";
|
|
650
|
+
if (actionId === "fitPage" || actionId === "fitToPage" || actionId === "fitWidth") return "fit-page";
|
|
651
|
+
if (actionId === "rotateCW") return "rotate-cw";
|
|
652
|
+
if (actionId === "rotateCCW") return "rotate-ccw";
|
|
653
|
+
if (actionId === "openWindow" || actionId === "openSeparateWindow") return "open-window";
|
|
654
|
+
if (actionId === "pageNav") return "page-nav";
|
|
655
|
+
return actionId;
|
|
656
|
+
}
|
|
657
|
+
enableAction(actionId) {
|
|
658
|
+
const norm = this.normalizeActionId(actionId);
|
|
659
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
660
|
+
if (btn) {
|
|
661
|
+
btn.disabled = false;
|
|
662
|
+
btn.classList.remove("disabled");
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
disableAction(actionId) {
|
|
666
|
+
const norm = this.normalizeActionId(actionId);
|
|
667
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
668
|
+
if (btn) {
|
|
669
|
+
btn.disabled = true;
|
|
670
|
+
btn.classList.add("disabled");
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
setActionActive(actionId, active) {
|
|
674
|
+
const norm = this.normalizeActionId(actionId);
|
|
675
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
676
|
+
if (btn) {
|
|
677
|
+
if (active) {
|
|
678
|
+
btn.classList.add("active");
|
|
679
|
+
} else {
|
|
680
|
+
btn.classList.remove("active");
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
isActionEnabled(action) {
|
|
685
|
+
const c = this.config;
|
|
686
|
+
const id = action.id;
|
|
687
|
+
if (c[id] === false) return false;
|
|
688
|
+
if (id === "zoom-in" && (c.zoomIn === false || c["zoom-in"] === false)) return false;
|
|
689
|
+
if (id === "zoom-out" && (c.zoomOut === false || c["zoom-out"] === false)) return false;
|
|
690
|
+
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)) {
|
|
691
|
+
return false;
|
|
692
|
+
}
|
|
693
|
+
if ((id === "rotate-cw" || id === "rotate-ccw" || id === "rotate") && (c.rotate === false || c.rotateCW === false || c.rotateCCW === false || c["rotate-cw"] === false)) {
|
|
694
|
+
return false;
|
|
695
|
+
}
|
|
696
|
+
if (id === "fullscreen" && c.fullscreen === false) return false;
|
|
697
|
+
if (id === "download" && c.download === false) return false;
|
|
698
|
+
if (id === "print" && c.print === false) return false;
|
|
699
|
+
if ((id === "open-window" || id === "external-window") && (c.openWindow === false || c.openSeparateWindow === false || c["open-window"] === false)) {
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
702
|
+
if (id === "copy" && c.copy === false) return false;
|
|
703
|
+
if (id === "thumbnails" && c.thumbnails === false) return false;
|
|
704
|
+
if (id === "page-nav" && (c.pageNav === false || c.pagination === false || c["page-nav"] === false)) {
|
|
705
|
+
return false;
|
|
706
|
+
}
|
|
707
|
+
if ((id === "prev" || id === "page-prev") && (c.prevPage === false || c.prev === false || c["prev"] === false || c.pageNav === false || c.pagination === false)) {
|
|
708
|
+
return false;
|
|
709
|
+
}
|
|
710
|
+
if ((id === "next" || id === "page-next") && (c.nextPage === false || c.next === false || c["next"] === false || c.pageNav === false || c.pagination === false)) {
|
|
711
|
+
return false;
|
|
712
|
+
}
|
|
713
|
+
if (id === "play" && c.play === false) return false;
|
|
714
|
+
if (id === "pause" && c.pause === false) return false;
|
|
715
|
+
if ((id === "fast-forward" || id === "forward-10") && (c.fastForward === false || c["fast-forward"] === false)) {
|
|
716
|
+
return false;
|
|
717
|
+
}
|
|
718
|
+
if ((id === "rewind" || id === "replay-10") && (c.rewind === false || c["rewind"] === false)) {
|
|
719
|
+
return false;
|
|
720
|
+
}
|
|
721
|
+
if (id === "speed" && c.speed === false) return false;
|
|
722
|
+
return true;
|
|
723
|
+
}
|
|
588
724
|
setPage(page, max) {
|
|
589
725
|
if (this.pageInputEl) {
|
|
590
726
|
this.pageInputEl.value = page.toString();
|
|
727
|
+
if (max !== void 0) {
|
|
728
|
+
this.pageInputEl.max = max.toString();
|
|
729
|
+
}
|
|
591
730
|
}
|
|
592
731
|
if (max !== void 0 && this.pageLabelEl) {
|
|
593
732
|
this.pageLabelEl.textContent = ` / ${max}`;
|
|
594
733
|
}
|
|
734
|
+
const currentMax = max !== void 0 ? max : parseInt(this.pageInputEl?.max || "1", 10) || 1;
|
|
735
|
+
if (this.prevPageBtn) {
|
|
736
|
+
this.prevPageBtn.disabled = page <= 1;
|
|
737
|
+
this.prevPageBtn.style.opacity = page <= 1 ? "0.4" : "1";
|
|
738
|
+
}
|
|
739
|
+
if (this.nextPageBtn) {
|
|
740
|
+
this.nextPageBtn.disabled = page >= currentMax;
|
|
741
|
+
this.nextPageBtn.style.opacity = page >= currentMax ? "0.4" : "1";
|
|
742
|
+
}
|
|
595
743
|
}
|
|
596
744
|
update(actions) {
|
|
597
745
|
this.actions = actions;
|
|
@@ -614,8 +762,9 @@ var ToolbarController = class {
|
|
|
614
762
|
view: [],
|
|
615
763
|
actions: []
|
|
616
764
|
};
|
|
617
|
-
const
|
|
618
|
-
const
|
|
765
|
+
const enabledActions = this.actions.filter((a) => this.isActionEnabled(a));
|
|
766
|
+
const hasPageNav = enabledActions.some((a) => a.type === "page-nav");
|
|
767
|
+
const effectiveActions = hasPageNav ? enabledActions.filter((a) => a.id !== "page-prev" && a.id !== "page-next" && a.id !== "prev" && a.id !== "next") : enabledActions;
|
|
619
768
|
for (const action of effectiveActions) {
|
|
620
769
|
if (groups[action.group]) {
|
|
621
770
|
groups[action.group].push(action);
|
|
@@ -675,6 +824,13 @@ var ToolbarController = class {
|
|
|
675
824
|
action.execute("go", val);
|
|
676
825
|
});
|
|
677
826
|
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
827
|
+
const curVal = action.value ?? 1;
|
|
828
|
+
prevBtn.disabled = curVal <= 1;
|
|
829
|
+
prevBtn.style.opacity = curVal <= 1 ? "0.4" : "1";
|
|
830
|
+
nextBtn.disabled = curVal >= max;
|
|
831
|
+
nextBtn.style.opacity = curVal >= max ? "0.4" : "1";
|
|
832
|
+
this.prevPageBtn = prevBtn;
|
|
833
|
+
this.nextPageBtn = nextBtn;
|
|
678
834
|
this.pageInputEl = input;
|
|
679
835
|
this.pageLabelEl = label;
|
|
680
836
|
groupEl.appendChild(prevBtn);
|
|
@@ -730,25 +886,63 @@ var ToolbarController = class {
|
|
|
730
886
|
var ThumbnailPanel = class {
|
|
731
887
|
el;
|
|
732
888
|
panelEl;
|
|
889
|
+
listEl;
|
|
890
|
+
headerEl;
|
|
733
891
|
thumbnails = [];
|
|
734
892
|
onSelect;
|
|
893
|
+
onToggleCallback;
|
|
735
894
|
activeIndex = 0;
|
|
736
|
-
|
|
895
|
+
observer;
|
|
896
|
+
renderedIndices = /* @__PURE__ */ new Set();
|
|
897
|
+
constructor(container, onToggle) {
|
|
737
898
|
this.el = container;
|
|
899
|
+
this.onToggleCallback = onToggle;
|
|
738
900
|
this.panelEl = createElement("div", { className: "fp-thumbnail-panel hidden" });
|
|
901
|
+
this.panelEl.style.width = "0px";
|
|
902
|
+
this.panelEl.style.minWidth = "0px";
|
|
903
|
+
this.panelEl.style.opacity = "0";
|
|
904
|
+
this.headerEl = createElement("div", { className: "fp-thumbnail-header" });
|
|
905
|
+
const title = createElement("span", { className: "fp-thumbnail-title" }, "Pages");
|
|
906
|
+
const closeBtn = createElement("button", {
|
|
907
|
+
className: "fp-thumbnail-close-btn",
|
|
908
|
+
title: "Close Thumbnails",
|
|
909
|
+
type: "button"
|
|
910
|
+
});
|
|
911
|
+
closeBtn.innerHTML = ICON_CLOSE;
|
|
912
|
+
closeBtn.addEventListener("click", (e) => {
|
|
913
|
+
e.stopPropagation();
|
|
914
|
+
this.hide();
|
|
915
|
+
});
|
|
916
|
+
this.headerEl.appendChild(title);
|
|
917
|
+
this.headerEl.appendChild(closeBtn);
|
|
918
|
+
this.listEl = createElement("div", { className: "fp-thumbnail-list" });
|
|
919
|
+
this.panelEl.appendChild(this.headerEl);
|
|
920
|
+
this.panelEl.appendChild(this.listEl);
|
|
739
921
|
this.el.appendChild(this.panelEl);
|
|
740
922
|
}
|
|
923
|
+
isOpen() {
|
|
924
|
+
return !this.panelEl.classList.contains("hidden") && this.panelEl.style.width !== "0px";
|
|
925
|
+
}
|
|
741
926
|
update(thumbnails, onSelect) {
|
|
742
927
|
this.thumbnails = thumbnails;
|
|
743
928
|
this.onSelect = onSelect;
|
|
929
|
+
this.renderedIndices.clear();
|
|
930
|
+
const titleEl = this.headerEl.querySelector(".fp-thumbnail-title");
|
|
931
|
+
if (titleEl) {
|
|
932
|
+
titleEl.textContent = `Pages (${thumbnails.length})`;
|
|
933
|
+
}
|
|
744
934
|
this.render();
|
|
935
|
+
if (this.isOpen()) {
|
|
936
|
+
this.renderAllVisible();
|
|
937
|
+
}
|
|
745
938
|
}
|
|
746
939
|
setActive(index) {
|
|
747
940
|
this.activeIndex = index;
|
|
748
|
-
const items = this.
|
|
941
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
749
942
|
items.forEach((item, i) => {
|
|
750
943
|
if (i === index) {
|
|
751
944
|
item.classList.add("active");
|
|
945
|
+
item.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
752
946
|
} else {
|
|
753
947
|
item.classList.remove("active");
|
|
754
948
|
}
|
|
@@ -756,37 +950,102 @@ var ThumbnailPanel = class {
|
|
|
756
950
|
}
|
|
757
951
|
show() {
|
|
758
952
|
this.panelEl.classList.remove("hidden");
|
|
953
|
+
this.panelEl.style.width = "200px";
|
|
954
|
+
this.panelEl.style.minWidth = "200px";
|
|
955
|
+
this.panelEl.style.opacity = "1";
|
|
956
|
+
this.panelEl.style.display = "flex";
|
|
957
|
+
this.onToggleCallback?.(true);
|
|
958
|
+
this.renderAllVisible();
|
|
759
959
|
}
|
|
760
960
|
hide() {
|
|
761
961
|
this.panelEl.classList.add("hidden");
|
|
962
|
+
this.panelEl.style.width = "0px";
|
|
963
|
+
this.panelEl.style.minWidth = "0px";
|
|
964
|
+
this.panelEl.style.opacity = "0";
|
|
965
|
+
this.onToggleCallback?.(false);
|
|
762
966
|
}
|
|
763
967
|
toggle() {
|
|
764
|
-
this.
|
|
968
|
+
if (this.isOpen()) {
|
|
969
|
+
this.hide();
|
|
970
|
+
} else {
|
|
971
|
+
this.show();
|
|
972
|
+
}
|
|
765
973
|
}
|
|
766
974
|
destroy() {
|
|
975
|
+
if (this.observer) {
|
|
976
|
+
this.observer.disconnect();
|
|
977
|
+
this.observer = void 0;
|
|
978
|
+
}
|
|
979
|
+
this.renderedIndices.clear();
|
|
767
980
|
this.el.innerHTML = "";
|
|
768
981
|
}
|
|
769
|
-
|
|
770
|
-
this.
|
|
982
|
+
renderAllVisible() {
|
|
983
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
984
|
+
items.forEach((item) => {
|
|
985
|
+
const idx = parseInt(item.dataset.thumbIndex || "-1", 10);
|
|
986
|
+
if (idx >= 0 && !this.renderedIndices.has(idx)) {
|
|
987
|
+
this.renderThumbnailItem(idx, item);
|
|
988
|
+
}
|
|
989
|
+
});
|
|
990
|
+
}
|
|
991
|
+
renderThumbnailItem(idx, itemEl) {
|
|
992
|
+
if (this.renderedIndices.has(idx)) return;
|
|
993
|
+
this.renderedIndices.add(idx);
|
|
994
|
+
const canvas = itemEl.querySelector("canvas");
|
|
995
|
+
const thumb = this.thumbnails[idx];
|
|
996
|
+
if (canvas && thumb) {
|
|
997
|
+
Promise.resolve(thumb.render(canvas)).catch((err) => {
|
|
998
|
+
console.warn(`[FilePreview] Error rendering thumbnail ${idx}:`, err);
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
render() {
|
|
1003
|
+
if (this.observer) {
|
|
1004
|
+
this.observer.disconnect();
|
|
1005
|
+
}
|
|
1006
|
+
this.listEl.innerHTML = "";
|
|
1007
|
+
const useObserver = typeof IntersectionObserver !== "undefined";
|
|
1008
|
+
if (useObserver) {
|
|
1009
|
+
this.observer = new IntersectionObserver(
|
|
1010
|
+
(entries) => {
|
|
1011
|
+
for (const entry of entries) {
|
|
1012
|
+
if (entry.isIntersecting) {
|
|
1013
|
+
const target = entry.target;
|
|
1014
|
+
const idx = parseInt(target.dataset.thumbIndex || "-1", 10);
|
|
1015
|
+
if (idx >= 0) {
|
|
1016
|
+
this.renderThumbnailItem(idx, target);
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
},
|
|
1021
|
+
{
|
|
1022
|
+
root: this.listEl,
|
|
1023
|
+
rootMargin: "120px 0px 120px 0px"
|
|
1024
|
+
}
|
|
1025
|
+
);
|
|
1026
|
+
}
|
|
771
1027
|
for (let i = 0; i < this.thumbnails.length; i++) {
|
|
772
1028
|
const thumb = this.thumbnails[i];
|
|
773
|
-
const itemEl = createElement("div", {
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
1029
|
+
const itemEl = createElement("div", {
|
|
1030
|
+
className: "fp-thumbnail-item" + (i === this.activeIndex ? " active" : "")
|
|
1031
|
+
});
|
|
1032
|
+
itemEl.dataset.thumbIndex = i.toString();
|
|
777
1033
|
itemEl.addEventListener("click", () => {
|
|
778
1034
|
this.setActive(i);
|
|
779
1035
|
this.onSelect?.(i);
|
|
780
1036
|
});
|
|
781
|
-
const
|
|
782
|
-
const
|
|
783
|
-
|
|
1037
|
+
const canvasWrapper = createElement("div", { className: "fp-thumbnail-canvas-wrapper" });
|
|
1038
|
+
const canvas = createElement("canvas", { width: "130", height: "170" });
|
|
1039
|
+
canvasWrapper.appendChild(canvas);
|
|
1040
|
+
const label = createElement("span", { className: "fp-thumbnail-label" }, thumb.label || `Page ${i + 1}`);
|
|
1041
|
+
itemEl.appendChild(canvasWrapper);
|
|
784
1042
|
itemEl.appendChild(label);
|
|
785
|
-
this.
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
}
|
|
789
|
-
|
|
1043
|
+
this.listEl.appendChild(itemEl);
|
|
1044
|
+
if (this.observer) {
|
|
1045
|
+
this.observer.observe(itemEl);
|
|
1046
|
+
}
|
|
1047
|
+
if (i < 4) {
|
|
1048
|
+
this.renderThumbnailItem(i, itemEl);
|
|
790
1049
|
}
|
|
791
1050
|
}
|
|
792
1051
|
}
|
|
@@ -807,6 +1066,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
807
1066
|
currentOptions = {};
|
|
808
1067
|
resizeObserver = null;
|
|
809
1068
|
fullscreenHandler = null;
|
|
1069
|
+
titleBarEl = null;
|
|
810
1070
|
/**
|
|
811
1071
|
* Register a preview plugin.
|
|
812
1072
|
*/
|
|
@@ -843,6 +1103,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
843
1103
|
}
|
|
844
1104
|
this.currentBuffer = buffer.slice(0);
|
|
845
1105
|
this.currentMetadata = metadata;
|
|
1106
|
+
this.updateTitleBar(options, metadata);
|
|
846
1107
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
847
1108
|
const fileInfo = { metadata, buffer };
|
|
848
1109
|
const matchedPlugin = await this.findPlugin(fileInfo);
|
|
@@ -866,15 +1127,21 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
866
1127
|
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
867
1128
|
const total = payload.total ?? payload.totalPages;
|
|
868
1129
|
this.toolbar?.setPage(payload.page, total);
|
|
1130
|
+
this.thumbnailPanel?.setActive(payload.page - 1);
|
|
869
1131
|
}
|
|
870
1132
|
this.eventEmitter.emit(event, payload);
|
|
871
|
-
}
|
|
1133
|
+
},
|
|
1134
|
+
toggleThumbnails: () => this.toggleThumbnails()
|
|
872
1135
|
});
|
|
873
1136
|
this.activeInstance = instance;
|
|
874
1137
|
instance.openInSeparateWindow = () => this.openInSeparateWindow();
|
|
1138
|
+
instance.toggleThumbnails = () => this.toggleThumbnails();
|
|
875
1139
|
this.hideLoading();
|
|
876
1140
|
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
877
|
-
|
|
1141
|
+
const isToolbarVisible = options.showToolbar !== false && options.toolbar !== false;
|
|
1142
|
+
if (isToolbarVisible && this.toolbar) {
|
|
1143
|
+
const toolbarConfig = this.extractToolbarConfig(options);
|
|
1144
|
+
this.toolbar.setConfig(toolbarConfig);
|
|
878
1145
|
const actions = matchedPlugin.getToolbarActions(instance);
|
|
879
1146
|
const hasFullscreen = actions.some((a) => a.id === "fullscreen");
|
|
880
1147
|
if (!hasFullscreen && this.wrapperEl) {
|
|
@@ -924,6 +1191,12 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
924
1191
|
}
|
|
925
1192
|
});
|
|
926
1193
|
}
|
|
1194
|
+
const thumbAction = actions.find((a) => a.id === "thumbnails");
|
|
1195
|
+
if (thumbAction) {
|
|
1196
|
+
thumbAction.execute = () => {
|
|
1197
|
+
this.toggleThumbnails();
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
927
1200
|
this.toolbar.update(actions);
|
|
928
1201
|
this.toolbar.show();
|
|
929
1202
|
}
|
|
@@ -1008,7 +1281,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1008
1281
|
if (targetUrl) {
|
|
1009
1282
|
const newWin2 = window.open(targetUrl, "_blank");
|
|
1010
1283
|
if (!newWin2) {
|
|
1011
|
-
|
|
1284
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
1012
1285
|
return null;
|
|
1013
1286
|
}
|
|
1014
1287
|
return newWin2;
|
|
@@ -1016,7 +1289,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1016
1289
|
const title = (this.currentMetadata?.name || "Document Preview") + " - Full Preview";
|
|
1017
1290
|
const newWin = window.open("", "_blank");
|
|
1018
1291
|
if (!newWin) {
|
|
1019
|
-
|
|
1292
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
1020
1293
|
return null;
|
|
1021
1294
|
}
|
|
1022
1295
|
newWin.document.title = title;
|
|
@@ -1093,6 +1366,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1093
1366
|
this.currentBuffer = null;
|
|
1094
1367
|
this.currentMetadata = null;
|
|
1095
1368
|
this.currentContainer = null;
|
|
1369
|
+
this.titleBarEl = null;
|
|
1096
1370
|
}
|
|
1097
1371
|
/**
|
|
1098
1372
|
* Get the currently active preview instance.
|
|
@@ -1100,7 +1374,218 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1100
1374
|
getInstance() {
|
|
1101
1375
|
return this.activeInstance;
|
|
1102
1376
|
}
|
|
1377
|
+
// --- Toolbar Configuration & Feature Toggles ---
|
|
1378
|
+
/**
|
|
1379
|
+
* Configure toolbar features dynamically through options or methods.
|
|
1380
|
+
* e.g. viewer.setToolbarConfig({ zoomIn: false, print: false })
|
|
1381
|
+
*/
|
|
1382
|
+
setToolbarConfig(config) {
|
|
1383
|
+
this.toolbar?.setConfig(config);
|
|
1384
|
+
}
|
|
1385
|
+
/**
|
|
1386
|
+
* Get current toolbar configuration.
|
|
1387
|
+
*/
|
|
1388
|
+
getToolbarConfig() {
|
|
1389
|
+
return this.toolbar?.getConfig() ?? {};
|
|
1390
|
+
}
|
|
1391
|
+
/**
|
|
1392
|
+
* Hide a specific toolbar action by ID or alias (e.g. 'zoom-in', 'print', 'download').
|
|
1393
|
+
*/
|
|
1394
|
+
hideToolbarAction(actionId) {
|
|
1395
|
+
this.toolbar?.hideAction(actionId);
|
|
1396
|
+
}
|
|
1397
|
+
/**
|
|
1398
|
+
* Show a specific toolbar action by ID or alias.
|
|
1399
|
+
*/
|
|
1400
|
+
showToolbarAction(actionId) {
|
|
1401
|
+
this.toolbar?.showAction(actionId);
|
|
1402
|
+
}
|
|
1403
|
+
/**
|
|
1404
|
+
* Enable a specific toolbar action button.
|
|
1405
|
+
*/
|
|
1406
|
+
enableToolbarAction(actionId) {
|
|
1407
|
+
this.toolbar?.enableAction(actionId);
|
|
1408
|
+
}
|
|
1409
|
+
/**
|
|
1410
|
+
* Disable a specific toolbar action button.
|
|
1411
|
+
*/
|
|
1412
|
+
disableToolbarAction(actionId) {
|
|
1413
|
+
this.toolbar?.disableAction(actionId);
|
|
1414
|
+
}
|
|
1415
|
+
// --- Programmatic Toolbar Action Methods ---
|
|
1416
|
+
/**
|
|
1417
|
+
* Fit document to page so it fills the frame width with minimal margins.
|
|
1418
|
+
*/
|
|
1419
|
+
fitToPage() {
|
|
1420
|
+
this.activeInstance?.fitToPage?.();
|
|
1421
|
+
}
|
|
1422
|
+
/**
|
|
1423
|
+
* Zoom in.
|
|
1424
|
+
*/
|
|
1425
|
+
zoomIn() {
|
|
1426
|
+
this.activeInstance?.zoomIn?.();
|
|
1427
|
+
}
|
|
1428
|
+
/**
|
|
1429
|
+
* Zoom out.
|
|
1430
|
+
*/
|
|
1431
|
+
zoomOut() {
|
|
1432
|
+
this.activeInstance?.zoomOut?.();
|
|
1433
|
+
}
|
|
1434
|
+
/**
|
|
1435
|
+
* Set specific zoom level.
|
|
1436
|
+
*/
|
|
1437
|
+
setZoom(level) {
|
|
1438
|
+
this.activeInstance?.setZoom?.(level);
|
|
1439
|
+
}
|
|
1440
|
+
/**
|
|
1441
|
+
* Get current zoom level.
|
|
1442
|
+
*/
|
|
1443
|
+
getZoom() {
|
|
1444
|
+
return this.activeInstance?.getZoom?.() ?? 1;
|
|
1445
|
+
}
|
|
1446
|
+
/**
|
|
1447
|
+
* Rotate 90 degrees clockwise.
|
|
1448
|
+
*/
|
|
1449
|
+
rotateCW() {
|
|
1450
|
+
this.activeInstance?.rotateCW?.();
|
|
1451
|
+
}
|
|
1452
|
+
/**
|
|
1453
|
+
* Rotate 90 degrees counter-clockwise.
|
|
1454
|
+
*/
|
|
1455
|
+
rotateCCW() {
|
|
1456
|
+
this.activeInstance?.rotateCCW?.();
|
|
1457
|
+
}
|
|
1458
|
+
/**
|
|
1459
|
+
* Navigate to a specific page number.
|
|
1460
|
+
*/
|
|
1461
|
+
goToPage(page) {
|
|
1462
|
+
this.activeInstance?.goToPage?.(page);
|
|
1463
|
+
this.toolbar?.setPage(page);
|
|
1464
|
+
}
|
|
1465
|
+
/**
|
|
1466
|
+
* Navigate to next page.
|
|
1467
|
+
*/
|
|
1468
|
+
nextPage() {
|
|
1469
|
+
const cur = this.getCurrentPage();
|
|
1470
|
+
const max = this.getPageCount();
|
|
1471
|
+
if (cur < max) {
|
|
1472
|
+
this.goToPage(cur + 1);
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
/**
|
|
1476
|
+
* Navigate to previous page.
|
|
1477
|
+
*/
|
|
1478
|
+
prevPage() {
|
|
1479
|
+
const cur = this.getCurrentPage();
|
|
1480
|
+
if (cur > 1) {
|
|
1481
|
+
this.goToPage(cur - 1);
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
/**
|
|
1485
|
+
* Get total page count.
|
|
1486
|
+
*/
|
|
1487
|
+
getPageCount() {
|
|
1488
|
+
return this.activeInstance?.getPageCount?.() ?? 1;
|
|
1489
|
+
}
|
|
1490
|
+
/**
|
|
1491
|
+
* Get current page number.
|
|
1492
|
+
*/
|
|
1493
|
+
getCurrentPage() {
|
|
1494
|
+
return this.activeInstance?.getCurrentPage?.() ?? 1;
|
|
1495
|
+
}
|
|
1496
|
+
/**
|
|
1497
|
+
* Download the current document.
|
|
1498
|
+
*/
|
|
1499
|
+
download() {
|
|
1500
|
+
this.activeInstance?.download?.();
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1503
|
+
* Print the current document.
|
|
1504
|
+
*/
|
|
1505
|
+
print() {
|
|
1506
|
+
this.activeInstance?.print?.();
|
|
1507
|
+
}
|
|
1508
|
+
/**
|
|
1509
|
+
* Toggle fullscreen mode.
|
|
1510
|
+
*/
|
|
1511
|
+
toggleFullscreen() {
|
|
1512
|
+
try {
|
|
1513
|
+
if (!document.fullscreenElement) {
|
|
1514
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
1515
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
1516
|
+
} else {
|
|
1517
|
+
document.exitFullscreen?.();
|
|
1518
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
1519
|
+
}
|
|
1520
|
+
} catch {
|
|
1521
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
1522
|
+
}
|
|
1523
|
+
setTimeout(() => {
|
|
1524
|
+
this.activeInstance?.fitToPage?.();
|
|
1525
|
+
}, 120);
|
|
1526
|
+
}
|
|
1527
|
+
/**
|
|
1528
|
+
* Toggle thumbnails sidebar panel.
|
|
1529
|
+
*/
|
|
1530
|
+
toggleThumbnails() {
|
|
1531
|
+
if (!this.thumbnailPanel) return;
|
|
1532
|
+
this.thumbnailPanel.toggle();
|
|
1533
|
+
const isOpen = this.thumbnailPanel.isOpen();
|
|
1534
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1535
|
+
setTimeout(() => {
|
|
1536
|
+
this.activeInstance?.fitToPage?.();
|
|
1537
|
+
}, 260);
|
|
1538
|
+
}
|
|
1539
|
+
/**
|
|
1540
|
+
* Set whether to display the file name / title bar above the toolbar.
|
|
1541
|
+
*/
|
|
1542
|
+
setShowFileName(show) {
|
|
1543
|
+
if (this.currentOptions) {
|
|
1544
|
+
this.currentOptions.showFileName = show;
|
|
1545
|
+
}
|
|
1546
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1547
|
+
}
|
|
1548
|
+
/**
|
|
1549
|
+
* Set or override the displayed file name in the preview panel.
|
|
1550
|
+
*/
|
|
1551
|
+
setFileName(name) {
|
|
1552
|
+
if (this.currentOptions) {
|
|
1553
|
+
this.currentOptions.fileName = name;
|
|
1554
|
+
}
|
|
1555
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1556
|
+
}
|
|
1103
1557
|
// --- Private methods ---
|
|
1558
|
+
updateTitleBar(options, metadata) {
|
|
1559
|
+
if (!this.titleBarEl) return;
|
|
1560
|
+
const show = options?.showFileName !== false;
|
|
1561
|
+
if (!show) {
|
|
1562
|
+
this.titleBarEl.style.display = "none";
|
|
1563
|
+
return;
|
|
1564
|
+
}
|
|
1565
|
+
const name = options?.fileName || metadata?.name || this.currentMetadata?.name || "";
|
|
1566
|
+
if (!name) {
|
|
1567
|
+
this.titleBarEl.style.display = "none";
|
|
1568
|
+
return;
|
|
1569
|
+
}
|
|
1570
|
+
this.titleBarEl.style.display = "flex";
|
|
1571
|
+
const ext = metadata?.extension || (name.includes(".") ? "." + name.split(".").pop() : "");
|
|
1572
|
+
const badge = ext ? ext.replace(".", "").toUpperCase() : "";
|
|
1573
|
+
this.titleBarEl.innerHTML = `
|
|
1574
|
+
<div class="fp-titlebar-info">
|
|
1575
|
+
<span class="fp-titlebar-icon">\u{1F4C4}</span>
|
|
1576
|
+
<span class="fp-titlebar-name" title="${name}">${name}</span>
|
|
1577
|
+
${badge ? `<span class="fp-titlebar-badge">${badge}</span>` : ""}
|
|
1578
|
+
</div>
|
|
1579
|
+
`;
|
|
1580
|
+
}
|
|
1581
|
+
extractToolbarConfig(options) {
|
|
1582
|
+
if (!options) return {};
|
|
1583
|
+
const nested = typeof options.toolbar === "object" ? options.toolbar : {};
|
|
1584
|
+
return {
|
|
1585
|
+
...options,
|
|
1586
|
+
...nested
|
|
1587
|
+
};
|
|
1588
|
+
}
|
|
1104
1589
|
abort() {
|
|
1105
1590
|
if (this.abortController) {
|
|
1106
1591
|
this.abortController.abort();
|
|
@@ -1143,17 +1628,29 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1143
1628
|
bodyEl.className = "fp-body";
|
|
1144
1629
|
bodyEl.appendChild(thumbnailEl);
|
|
1145
1630
|
bodyEl.appendChild(this.contentEl);
|
|
1631
|
+
const titleBarEl = document.createElement("div");
|
|
1632
|
+
titleBarEl.className = "fp-titlebar";
|
|
1633
|
+
this.titleBarEl = titleBarEl;
|
|
1634
|
+
this.updateTitleBar(options, this.currentMetadata);
|
|
1146
1635
|
if (toolbarPos === "top") {
|
|
1636
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1147
1637
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1148
1638
|
this.wrapperEl.appendChild(bodyEl);
|
|
1149
1639
|
} else {
|
|
1640
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1150
1641
|
this.wrapperEl.appendChild(bodyEl);
|
|
1151
1642
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1152
1643
|
}
|
|
1153
1644
|
container.innerHTML = "";
|
|
1154
1645
|
container.appendChild(this.wrapperEl);
|
|
1155
|
-
|
|
1156
|
-
this.
|
|
1646
|
+
const initialToolbarConfig = this.extractToolbarConfig(options);
|
|
1647
|
+
this.toolbar = new ToolbarController(toolbarEl, initialToolbarConfig);
|
|
1648
|
+
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl, (isOpen) => {
|
|
1649
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1650
|
+
setTimeout(() => {
|
|
1651
|
+
this.activeInstance?.fitToPage?.();
|
|
1652
|
+
}, 260);
|
|
1653
|
+
});
|
|
1157
1654
|
this.setupKeyboardShortcuts();
|
|
1158
1655
|
this.setupDragAndDrop(container, options);
|
|
1159
1656
|
this.setupResizeAndFullscreenListeners();
|
|
@@ -1543,6 +2040,14 @@ var PdfPlugin = class {
|
|
|
1543
2040
|
group: "zoom",
|
|
1544
2041
|
execute: () => instance.fitToPage?.()
|
|
1545
2042
|
},
|
|
2043
|
+
{
|
|
2044
|
+
id: "fit-width",
|
|
2045
|
+
icon: "fit-width",
|
|
2046
|
+
label: "Fit to Width",
|
|
2047
|
+
type: "button",
|
|
2048
|
+
group: "zoom",
|
|
2049
|
+
execute: () => instance.fitToWidth?.()
|
|
2050
|
+
},
|
|
1546
2051
|
{
|
|
1547
2052
|
id: "rotate-cw",
|
|
1548
2053
|
icon: "rotate-cw",
|
|
@@ -1551,6 +2056,14 @@ var PdfPlugin = class {
|
|
|
1551
2056
|
group: "view",
|
|
1552
2057
|
execute: () => instance.rotateCW?.()
|
|
1553
2058
|
},
|
|
2059
|
+
{
|
|
2060
|
+
id: "rotate-ccw",
|
|
2061
|
+
icon: "rotate-ccw",
|
|
2062
|
+
label: "Rotate Counter-Clockwise",
|
|
2063
|
+
type: "button",
|
|
2064
|
+
group: "view",
|
|
2065
|
+
execute: () => instance.rotateCCW?.()
|
|
2066
|
+
},
|
|
1554
2067
|
{
|
|
1555
2068
|
id: "download",
|
|
1556
2069
|
icon: "download",
|
|
@@ -1582,12 +2095,13 @@ var PdfPlugin = class {
|
|
|
1582
2095
|
container.className = "fp-pdf-container";
|
|
1583
2096
|
container.style.width = "100%";
|
|
1584
2097
|
container.style.height = "100%";
|
|
1585
|
-
container.style.
|
|
2098
|
+
container.style.overflowX = "hidden";
|
|
2099
|
+
container.style.overflowY = "auto";
|
|
1586
2100
|
container.style.display = "flex";
|
|
1587
2101
|
container.style.flexDirection = "column";
|
|
1588
2102
|
container.style.alignItems = "center";
|
|
1589
2103
|
container.style.justifyContent = "flex-start";
|
|
1590
|
-
container.style.padding = "
|
|
2104
|
+
container.style.padding = "16px 8px";
|
|
1591
2105
|
container.style.backgroundColor = "#0f172a";
|
|
1592
2106
|
container.style.boxSizing = "border-box";
|
|
1593
2107
|
container.style.position = "relative";
|
|
@@ -1598,30 +2112,12 @@ var PdfPlugin = class {
|
|
|
1598
2112
|
pageCard.style.borderRadius = "4px";
|
|
1599
2113
|
pageCard.style.overflow = "hidden";
|
|
1600
2114
|
pageCard.style.lineHeight = "0";
|
|
1601
|
-
pageCard.style.transition = "transform 0.15s ease";
|
|
1602
2115
|
pageCard.style.position = "relative";
|
|
1603
2116
|
pageCard.style.flexShrink = "0";
|
|
2117
|
+
pageCard.style.transition = "box-shadow 0.2s ease";
|
|
1604
2118
|
let canvas = document.createElement("canvas");
|
|
1605
2119
|
pageCard.appendChild(canvas);
|
|
1606
2120
|
container.appendChild(pageCard);
|
|
1607
|
-
const indicator = document.createElement("div");
|
|
1608
|
-
indicator.className = "fp-pdf-page-indicator";
|
|
1609
|
-
indicator.style.position = "sticky";
|
|
1610
|
-
indicator.style.bottom = "16px";
|
|
1611
|
-
indicator.style.marginTop = "16px";
|
|
1612
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1613
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
1614
|
-
indicator.style.color = "#f8fafc";
|
|
1615
|
-
indicator.style.fontSize = "12px";
|
|
1616
|
-
indicator.style.fontWeight = "600";
|
|
1617
|
-
indicator.style.padding = "5px 14px";
|
|
1618
|
-
indicator.style.borderRadius = "20px";
|
|
1619
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1620
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1621
|
-
indicator.style.zIndex = "10";
|
|
1622
|
-
indicator.style.userSelect = "none";
|
|
1623
|
-
indicator.style.pointerEvents = "none";
|
|
1624
|
-
container.appendChild(indicator);
|
|
1625
2121
|
ctx.container.appendChild(container);
|
|
1626
2122
|
const standardFontsUrl = typeof window !== "undefined" && window.__PDF_STANDARD_FONTS_URL__ || "./standard_fonts/";
|
|
1627
2123
|
const cmapsUrl = typeof window !== "undefined" && window.__PDF_CMAPS_URL__ || "./cmaps/";
|
|
@@ -1637,8 +2133,9 @@ var PdfPlugin = class {
|
|
|
1637
2133
|
let currentPage = 1;
|
|
1638
2134
|
let zoomScale = 1;
|
|
1639
2135
|
let rotation = 0;
|
|
1640
|
-
let fitMode = "
|
|
2136
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
1641
2137
|
let currentRenderTask = null;
|
|
2138
|
+
let textLayerDiv = null;
|
|
1642
2139
|
const renderPage = async (pageNum) => {
|
|
1643
2140
|
if (currentRenderTask) {
|
|
1644
2141
|
try {
|
|
@@ -1650,30 +2147,37 @@ var PdfPlugin = class {
|
|
|
1650
2147
|
const newCanvas = document.createElement("canvas");
|
|
1651
2148
|
pageCard.replaceChild(newCanvas, canvas);
|
|
1652
2149
|
canvas = newCanvas;
|
|
2150
|
+
if (textLayerDiv) {
|
|
2151
|
+
textLayerDiv.remove();
|
|
2152
|
+
textLayerDiv = null;
|
|
2153
|
+
}
|
|
1653
2154
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1654
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1655
2155
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1656
2156
|
const page = await pdfDoc.getPage(currentPage);
|
|
1657
2157
|
const containerWidth = container.clientWidth || 900;
|
|
1658
2158
|
const containerHeight = container.clientHeight || 700;
|
|
1659
2159
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1660
|
-
const availWidth = Math.max(
|
|
1661
|
-
const availHeight = Math.max(
|
|
2160
|
+
const availWidth = Math.max(280, containerWidth - 36);
|
|
2161
|
+
const availHeight = Math.max(280, containerHeight - 32);
|
|
1662
2162
|
const scaleW = availWidth / unscaledVp.width;
|
|
1663
2163
|
const scaleH = availHeight / unscaledVp.height;
|
|
1664
2164
|
let fitScale;
|
|
1665
2165
|
if (fitMode === "page") {
|
|
1666
|
-
fitScale = Math.max(0.4, Math.min(scaleW, scaleH));
|
|
2166
|
+
fitScale = Math.max(0.2, Math.min(4, Math.min(scaleW, scaleH)));
|
|
1667
2167
|
} else {
|
|
1668
|
-
fitScale = Math.max(0.
|
|
2168
|
+
fitScale = Math.max(0.2, Math.min(4, scaleW));
|
|
1669
2169
|
}
|
|
1670
2170
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1671
2171
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1672
2172
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
2173
|
+
const displayWidth = Math.floor(viewport.width);
|
|
2174
|
+
const displayHeight = Math.floor(viewport.height);
|
|
1673
2175
|
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1674
2176
|
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1675
|
-
canvas.style.width = `${
|
|
1676
|
-
canvas.style.height = `${
|
|
2177
|
+
canvas.style.width = `${displayWidth}px`;
|
|
2178
|
+
canvas.style.height = `${displayHeight}px`;
|
|
2179
|
+
pageCard.style.width = `${displayWidth}px`;
|
|
2180
|
+
pageCard.style.height = `${displayHeight}px`;
|
|
1677
2181
|
const canvasCtx = canvas.getContext("2d");
|
|
1678
2182
|
if (!canvasCtx) return;
|
|
1679
2183
|
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
@@ -1687,9 +2191,31 @@ var PdfPlugin = class {
|
|
|
1687
2191
|
if (err?.name !== "RenderingCancelledException") {
|
|
1688
2192
|
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1689
2193
|
}
|
|
2194
|
+
return;
|
|
1690
2195
|
} finally {
|
|
1691
2196
|
currentRenderTask = null;
|
|
1692
2197
|
}
|
|
2198
|
+
try {
|
|
2199
|
+
textLayerDiv = document.createElement("div");
|
|
2200
|
+
textLayerDiv.className = "textLayer";
|
|
2201
|
+
textLayerDiv.style.width = `${displayWidth}px`;
|
|
2202
|
+
textLayerDiv.style.height = `${displayHeight}px`;
|
|
2203
|
+
textLayerDiv.style.position = "absolute";
|
|
2204
|
+
textLayerDiv.style.top = "0";
|
|
2205
|
+
textLayerDiv.style.left = "0";
|
|
2206
|
+
textLayerDiv.style.lineHeight = "1";
|
|
2207
|
+
pageCard.appendChild(textLayerDiv);
|
|
2208
|
+
if (pdfjsLib.TextLayer) {
|
|
2209
|
+
const textLayer = new pdfjsLib.TextLayer({
|
|
2210
|
+
textContentSource: page.streamTextContent(),
|
|
2211
|
+
container: textLayerDiv,
|
|
2212
|
+
viewport
|
|
2213
|
+
});
|
|
2214
|
+
await textLayer.render();
|
|
2215
|
+
}
|
|
2216
|
+
} catch (err) {
|
|
2217
|
+
console.debug("[PdfPlugin] TextLayer notice:", err);
|
|
2218
|
+
}
|
|
1693
2219
|
};
|
|
1694
2220
|
renderPage(1);
|
|
1695
2221
|
let resizeTimer = null;
|
|
@@ -1699,11 +2225,48 @@ var PdfPlugin = class {
|
|
|
1699
2225
|
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1700
2226
|
renderPage(currentPage);
|
|
1701
2227
|
}
|
|
1702
|
-
},
|
|
2228
|
+
}, 120);
|
|
1703
2229
|
});
|
|
1704
2230
|
resizeObserver.observe(container);
|
|
2231
|
+
const onWheel = (e) => {
|
|
2232
|
+
if (e.ctrlKey || e.metaKey) {
|
|
2233
|
+
e.preventDefault();
|
|
2234
|
+
const delta = e.deltaY > 0 ? -0.15 : 0.15;
|
|
2235
|
+
zoomScale = Math.max(0.25, Math.min(4, Math.round((zoomScale + delta) * 100) / 100));
|
|
2236
|
+
renderPage(currentPage);
|
|
2237
|
+
}
|
|
2238
|
+
};
|
|
2239
|
+
container.addEventListener("wheel", onWheel, { passive: false });
|
|
2240
|
+
const onKeyDown = (e) => {
|
|
2241
|
+
const tag = e.target?.tagName?.toLowerCase();
|
|
2242
|
+
if (tag === "input" || tag === "textarea" || tag === "select") return;
|
|
2243
|
+
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
2244
|
+
if (currentPage < totalPages) {
|
|
2245
|
+
e.preventDefault();
|
|
2246
|
+
container.scrollTop = 0;
|
|
2247
|
+
renderPage(currentPage + 1);
|
|
2248
|
+
}
|
|
2249
|
+
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
2250
|
+
if (currentPage > 1) {
|
|
2251
|
+
e.preventDefault();
|
|
2252
|
+
container.scrollTop = 0;
|
|
2253
|
+
renderPage(currentPage - 1);
|
|
2254
|
+
}
|
|
2255
|
+
} else if (e.key === "Home") {
|
|
2256
|
+
e.preventDefault();
|
|
2257
|
+
container.scrollTop = 0;
|
|
2258
|
+
renderPage(1);
|
|
2259
|
+
} else if (e.key === "End") {
|
|
2260
|
+
e.preventDefault();
|
|
2261
|
+
container.scrollTop = 0;
|
|
2262
|
+
renderPage(totalPages);
|
|
2263
|
+
}
|
|
2264
|
+
};
|
|
2265
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1705
2266
|
const cleanup = () => {
|
|
1706
2267
|
resizeObserver.disconnect();
|
|
2268
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
2269
|
+
container.removeEventListener("wheel", onWheel);
|
|
1707
2270
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1708
2271
|
if (currentRenderTask) {
|
|
1709
2272
|
try {
|
|
@@ -1722,22 +2285,26 @@ var PdfPlugin = class {
|
|
|
1722
2285
|
const instance = {
|
|
1723
2286
|
destroy: cleanup,
|
|
1724
2287
|
zoomIn: () => {
|
|
1725
|
-
zoomScale = Math.min(
|
|
2288
|
+
zoomScale = Math.min(4, Math.round((zoomScale + 0.2) * 10) / 10);
|
|
1726
2289
|
renderPage(currentPage);
|
|
1727
2290
|
},
|
|
1728
2291
|
zoomOut: () => {
|
|
1729
|
-
zoomScale = Math.max(0.
|
|
2292
|
+
zoomScale = Math.max(0.25, Math.round((zoomScale - 0.2) * 10) / 10);
|
|
1730
2293
|
renderPage(currentPage);
|
|
1731
2294
|
},
|
|
1732
2295
|
getZoom: () => zoomScale,
|
|
1733
2296
|
setZoom: (level) => {
|
|
1734
|
-
zoomScale = Math.max(0.
|
|
2297
|
+
zoomScale = Math.max(0.25, Math.min(4, level));
|
|
1735
2298
|
renderPage(currentPage);
|
|
1736
2299
|
},
|
|
1737
2300
|
fitToPage: () => {
|
|
1738
|
-
fitMode =
|
|
2301
|
+
fitMode = "page";
|
|
2302
|
+
zoomScale = 1;
|
|
2303
|
+
renderPage(currentPage);
|
|
2304
|
+
},
|
|
2305
|
+
fitToWidth: () => {
|
|
2306
|
+
fitMode = "width";
|
|
1739
2307
|
zoomScale = 1;
|
|
1740
|
-
rotation = 0;
|
|
1741
2308
|
renderPage(currentPage);
|
|
1742
2309
|
},
|
|
1743
2310
|
rotateCW: () => {
|
|
@@ -1755,6 +2322,9 @@ var PdfPlugin = class {
|
|
|
1755
2322
|
container.scrollTop = 0;
|
|
1756
2323
|
renderPage(page);
|
|
1757
2324
|
},
|
|
2325
|
+
toggleThumbnails: () => {
|
|
2326
|
+
ctx?.toggleThumbnails?.();
|
|
2327
|
+
},
|
|
1758
2328
|
download: () => {
|
|
1759
2329
|
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1760
2330
|
const url = URL.createObjectURL(blob);
|
|
@@ -1788,7 +2358,7 @@ var PdfPlugin = class {
|
|
|
1788
2358
|
},
|
|
1789
2359
|
getThumbnails: async () => {
|
|
1790
2360
|
const thumbnails = [];
|
|
1791
|
-
const count =
|
|
2361
|
+
const count = totalPages;
|
|
1792
2362
|
for (let i = 1; i <= count; i++) {
|
|
1793
2363
|
thumbnails.push({
|
|
1794
2364
|
index: i,
|
|
@@ -1796,9 +2366,10 @@ var PdfPlugin = class {
|
|
|
1796
2366
|
render: async (thumbCanvas) => {
|
|
1797
2367
|
try {
|
|
1798
2368
|
const p = await pdfDoc.getPage(i);
|
|
1799
|
-
const baseVp = p.getViewport({ scale: 1 });
|
|
1800
|
-
const
|
|
1801
|
-
const
|
|
2369
|
+
const baseVp = p.getViewport({ scale: 1, rotation });
|
|
2370
|
+
const targetW = thumbCanvas.width || 130;
|
|
2371
|
+
const thumbScale = targetW / baseVp.width;
|
|
2372
|
+
const thumbVp = p.getViewport({ scale: thumbScale, rotation });
|
|
1802
2373
|
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1803
2374
|
const tCtx = thumbCanvas.getContext("2d");
|
|
1804
2375
|
if (tCtx) {
|
|
@@ -2142,28 +2713,26 @@ var DocxPlugin = class {
|
|
|
2142
2713
|
getToolbarActions(instance) {
|
|
2143
2714
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2144
2715
|
const actions = [];
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
if (
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
instance.goToPage?.(page);
|
|
2163
|
-
}
|
|
2716
|
+
actions.push({
|
|
2717
|
+
id: "page-nav",
|
|
2718
|
+
icon: "",
|
|
2719
|
+
label: "Page Navigation",
|
|
2720
|
+
type: "page-nav",
|
|
2721
|
+
group: "navigation",
|
|
2722
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2723
|
+
max: totalPages,
|
|
2724
|
+
execute: (action, page) => {
|
|
2725
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2726
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2727
|
+
if (action === "prev") {
|
|
2728
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2729
|
+
} else if (action === "next") {
|
|
2730
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2731
|
+
} else if (typeof page === "number") {
|
|
2732
|
+
instance.goToPage?.(page);
|
|
2164
2733
|
}
|
|
2165
|
-
}
|
|
2166
|
-
}
|
|
2734
|
+
}
|
|
2735
|
+
});
|
|
2167
2736
|
actions.push(
|
|
2168
2737
|
{
|
|
2169
2738
|
id: "zoom-out",
|
|
@@ -2229,11 +2798,17 @@ var DocxPlugin = class {
|
|
|
2229
2798
|
wrapper.className = "fp-docx-wrapper";
|
|
2230
2799
|
wrapper.style.transformOrigin = "top center";
|
|
2231
2800
|
wrapper.style.transition = "transform 0.2s ease";
|
|
2232
|
-
wrapper.style.padding = "
|
|
2233
|
-
wrapper.style.maxWidth = "
|
|
2801
|
+
wrapper.style.padding = "0";
|
|
2802
|
+
wrapper.style.maxWidth = "none";
|
|
2803
|
+
wrapper.style.width = "816px";
|
|
2234
2804
|
wrapper.style.margin = "0 auto";
|
|
2805
|
+
wrapper.style.display = "flex";
|
|
2806
|
+
wrapper.style.flexDirection = "column";
|
|
2807
|
+
wrapper.style.alignItems = "center";
|
|
2235
2808
|
wrapper.style.boxSizing = "border-box";
|
|
2236
|
-
ctx.container.style.
|
|
2809
|
+
ctx.container.style.overflowX = "hidden";
|
|
2810
|
+
ctx.container.style.overflowY = "auto";
|
|
2811
|
+
ctx.container.style.padding = "16px 8px";
|
|
2237
2812
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
2238
2813
|
ctx.container.appendChild(wrapper);
|
|
2239
2814
|
const styleOverride = document.createElement("style");
|
|
@@ -2407,39 +2982,13 @@ var DocxPlugin = class {
|
|
|
2407
2982
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2408
2983
|
const totalPages = Math.max(1, pageElements.length);
|
|
2409
2984
|
let currentPage = 1;
|
|
2410
|
-
let indicator = null;
|
|
2411
|
-
if (totalPages > 1) {
|
|
2412
|
-
indicator = document.createElement("div");
|
|
2413
|
-
indicator.className = "fp-docx-page-indicator";
|
|
2414
|
-
indicator.style.position = "sticky";
|
|
2415
|
-
indicator.style.bottom = "16px";
|
|
2416
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2417
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
2418
|
-
indicator.style.color = "#f8fafc";
|
|
2419
|
-
indicator.style.fontSize = "12px";
|
|
2420
|
-
indicator.style.fontWeight = "600";
|
|
2421
|
-
indicator.style.padding = "5px 14px";
|
|
2422
|
-
indicator.style.borderRadius = "20px";
|
|
2423
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2424
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2425
|
-
indicator.style.zIndex = "10";
|
|
2426
|
-
indicator.style.userSelect = "none";
|
|
2427
|
-
indicator.style.pointerEvents = "none";
|
|
2428
|
-
indicator.style.textAlign = "center";
|
|
2429
|
-
indicator.style.width = "fit-content";
|
|
2430
|
-
indicator.style.margin = "16px auto 0";
|
|
2431
|
-
ctx.container.appendChild(indicator);
|
|
2432
|
-
}
|
|
2433
2985
|
const showPage = (pageNum) => {
|
|
2434
2986
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2435
2987
|
if (pageElements.length > 1) {
|
|
2436
2988
|
pageElements.forEach((sec, idx) => {
|
|
2437
|
-
sec.style.display = idx + 1 === currentPage ? "
|
|
2989
|
+
sec.style.display = idx + 1 === currentPage ? "" : "none";
|
|
2438
2990
|
});
|
|
2439
2991
|
}
|
|
2440
|
-
if (indicator) {
|
|
2441
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2442
|
-
}
|
|
2443
2992
|
ctx.container.scrollTop = 0;
|
|
2444
2993
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2445
2994
|
};
|
|
@@ -2448,31 +2997,46 @@ var DocxPlugin = class {
|
|
|
2448
2997
|
}
|
|
2449
2998
|
scale = 1;
|
|
2450
2999
|
let rotation = 0;
|
|
2451
|
-
let fitMode = "
|
|
2452
|
-
|
|
2453
|
-
|
|
3000
|
+
let fitMode = "page";
|
|
3001
|
+
let isUserZoomed = false;
|
|
3002
|
+
const calculateFitScale = (_mode = fitMode) => {
|
|
3003
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
2454
3004
|
const elW = activeEl.offsetWidth || 816;
|
|
2455
|
-
const
|
|
2456
|
-
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
2457
|
-
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
3005
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
2458
3006
|
const sW = availW / elW;
|
|
2459
|
-
|
|
2460
|
-
if (mode === "page") {
|
|
2461
|
-
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
2462
|
-
}
|
|
2463
|
-
return Math.max(0.65, Math.min(1.05, sW));
|
|
3007
|
+
return Math.max(0.35, Math.min(3, sW));
|
|
2464
3008
|
};
|
|
2465
3009
|
const applyTransform = () => {
|
|
2466
3010
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2467
3011
|
wrapper.style.transformOrigin = "top center";
|
|
3012
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
3013
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
3014
|
+
if (scale > 1) {
|
|
3015
|
+
wrapper.style.marginBottom = `${Math.round(elH * scale - elH + 32)}px`;
|
|
3016
|
+
} else {
|
|
3017
|
+
wrapper.style.marginBottom = "32px";
|
|
3018
|
+
}
|
|
2468
3019
|
};
|
|
3020
|
+
let resizeObserver = null;
|
|
3021
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
3022
|
+
resizeObserver = new ResizeObserver(() => {
|
|
3023
|
+
if (!isUserZoomed) {
|
|
3024
|
+
const newFit = calculateFitScale("page");
|
|
3025
|
+
if (Math.abs(scale - newFit) > 0.015) {
|
|
3026
|
+
scale = newFit;
|
|
3027
|
+
applyTransform();
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
});
|
|
3031
|
+
resizeObserver.observe(ctx.container);
|
|
3032
|
+
}
|
|
2469
3033
|
setTimeout(() => {
|
|
2470
|
-
|
|
2471
|
-
scale = calculateFitScale("width");
|
|
3034
|
+
scale = calculateFitScale("page");
|
|
2472
3035
|
applyTransform();
|
|
2473
|
-
},
|
|
3036
|
+
}, 40);
|
|
2474
3037
|
const cleanup = () => {
|
|
2475
|
-
|
|
3038
|
+
resizeObserver?.disconnect();
|
|
3039
|
+
resizeObserver = null;
|
|
2476
3040
|
for (const url of createdBlobUrls) {
|
|
2477
3041
|
URL.revokeObjectURL(url);
|
|
2478
3042
|
}
|
|
@@ -2489,21 +3053,24 @@ var DocxPlugin = class {
|
|
|
2489
3053
|
showPage(page);
|
|
2490
3054
|
},
|
|
2491
3055
|
zoomIn: () => {
|
|
2492
|
-
|
|
3056
|
+
isUserZoomed = true;
|
|
3057
|
+
scale = Math.min(3.5, scale + 0.15);
|
|
2493
3058
|
applyTransform();
|
|
2494
3059
|
},
|
|
2495
3060
|
zoomOut: () => {
|
|
3061
|
+
isUserZoomed = true;
|
|
2496
3062
|
scale = Math.max(0.2, scale - 0.15);
|
|
2497
3063
|
applyTransform();
|
|
2498
3064
|
},
|
|
2499
3065
|
getZoom: () => scale,
|
|
2500
3066
|
setZoom: (level) => {
|
|
3067
|
+
isUserZoomed = true;
|
|
2501
3068
|
scale = level;
|
|
2502
3069
|
applyTransform();
|
|
2503
3070
|
},
|
|
2504
3071
|
fitToPage: () => {
|
|
2505
|
-
|
|
2506
|
-
scale = calculateFitScale(
|
|
3072
|
+
isUserZoomed = false;
|
|
3073
|
+
scale = calculateFitScale("page");
|
|
2507
3074
|
rotation = 0;
|
|
2508
3075
|
applyTransform();
|
|
2509
3076
|
},
|
|
@@ -2893,7 +3460,7 @@ var ExcelPlugin = class {
|
|
|
2893
3460
|
"application/vnd.ms-excel.template.macroEnabled.12",
|
|
2894
3461
|
"application/vnd.oasis.opendocument.spreadsheet"
|
|
2895
3462
|
];
|
|
2896
|
-
weight =
|
|
3463
|
+
weight = 85;
|
|
2897
3464
|
supports(file) {
|
|
2898
3465
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2899
3466
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
@@ -2905,6 +3472,14 @@ var ExcelPlugin = class {
|
|
|
2905
3472
|
getToolbarActions(instance) {
|
|
2906
3473
|
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2907
3474
|
const actions = [];
|
|
3475
|
+
actions.push({
|
|
3476
|
+
id: "thumbnails",
|
|
3477
|
+
icon: "thumbnails",
|
|
3478
|
+
label: "Sheet Thumbnails",
|
|
3479
|
+
type: "button",
|
|
3480
|
+
group: "navigation",
|
|
3481
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3482
|
+
});
|
|
2908
3483
|
if (totalSheets > 1) {
|
|
2909
3484
|
actions.push({
|
|
2910
3485
|
id: "page-nav",
|
|
@@ -2948,26 +3523,6 @@ var ExcelPlugin = class {
|
|
|
2948
3523
|
instance.zoomIn?.();
|
|
2949
3524
|
}
|
|
2950
3525
|
},
|
|
2951
|
-
{
|
|
2952
|
-
id: "fit-page",
|
|
2953
|
-
icon: "fit-page",
|
|
2954
|
-
label: "Fit to View",
|
|
2955
|
-
type: "button",
|
|
2956
|
-
group: "zoom",
|
|
2957
|
-
execute: () => {
|
|
2958
|
-
instance.fitToPage?.();
|
|
2959
|
-
}
|
|
2960
|
-
},
|
|
2961
|
-
{
|
|
2962
|
-
id: "rotate-cw",
|
|
2963
|
-
icon: "rotate-cw",
|
|
2964
|
-
label: "Rotate",
|
|
2965
|
-
type: "button",
|
|
2966
|
-
group: "view",
|
|
2967
|
-
execute: () => {
|
|
2968
|
-
instance.rotateCW?.();
|
|
2969
|
-
}
|
|
2970
|
-
},
|
|
2971
3526
|
{
|
|
2972
3527
|
id: "download",
|
|
2973
3528
|
icon: "download",
|
|
@@ -2987,6 +3542,16 @@ var ExcelPlugin = class {
|
|
|
2987
3542
|
execute: () => {
|
|
2988
3543
|
instance.print?.();
|
|
2989
3544
|
}
|
|
3545
|
+
},
|
|
3546
|
+
{
|
|
3547
|
+
id: "open-window",
|
|
3548
|
+
icon: "open-window",
|
|
3549
|
+
label: "Open in Separate Full Window",
|
|
3550
|
+
type: "button",
|
|
3551
|
+
group: "actions",
|
|
3552
|
+
execute: () => {
|
|
3553
|
+
instance.openInSeparateWindow?.();
|
|
3554
|
+
}
|
|
2990
3555
|
}
|
|
2991
3556
|
);
|
|
2992
3557
|
return actions;
|
|
@@ -3018,12 +3583,11 @@ var ExcelPlugin = class {
|
|
|
3018
3583
|
container.appendChild(tabsArea);
|
|
3019
3584
|
ctx.container.appendChild(container);
|
|
3020
3585
|
let scale = 1;
|
|
3021
|
-
let rotation = 0;
|
|
3022
3586
|
let currentSheetIndex = 1;
|
|
3023
3587
|
let sheetNames = [];
|
|
3024
3588
|
let wb = null;
|
|
3025
3589
|
const applyTransform = () => {
|
|
3026
|
-
contentArea.style.transform = `scale(${scale})
|
|
3590
|
+
contentArea.style.transform = `scale(${scale})`;
|
|
3027
3591
|
contentArea.style.transformOrigin = "top left";
|
|
3028
3592
|
};
|
|
3029
3593
|
const calculateFitScale = () => {
|
|
@@ -3031,7 +3595,7 @@ var ExcelPlugin = class {
|
|
|
3031
3595
|
if (!table) return 1;
|
|
3032
3596
|
const availW = Math.max(280, container.clientWidth - 48);
|
|
3033
3597
|
const tW = table.offsetWidth || 800;
|
|
3034
|
-
return Math.max(0.
|
|
3598
|
+
return Math.max(0.4, Math.min(1, availW / tW));
|
|
3035
3599
|
};
|
|
3036
3600
|
try {
|
|
3037
3601
|
wb = XLSX.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
|
|
@@ -3086,7 +3650,16 @@ var ExcelPlugin = class {
|
|
|
3086
3650
|
}
|
|
3087
3651
|
});
|
|
3088
3652
|
ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
|
|
3653
|
+
requestAnimationFrame(() => {
|
|
3654
|
+
scale = calculateFitScale();
|
|
3655
|
+
applyTransform();
|
|
3656
|
+
});
|
|
3089
3657
|
};
|
|
3658
|
+
const ro = new ResizeObserver(() => {
|
|
3659
|
+
scale = calculateFitScale();
|
|
3660
|
+
applyTransform();
|
|
3661
|
+
});
|
|
3662
|
+
ro.observe(container);
|
|
3090
3663
|
if (sheetNames.length > 0) {
|
|
3091
3664
|
sheetNames.forEach((name, idx) => {
|
|
3092
3665
|
const btn = document.createElement("button");
|
|
@@ -3113,6 +3686,7 @@ var ExcelPlugin = class {
|
|
|
3113
3686
|
`;
|
|
3114
3687
|
}
|
|
3115
3688
|
const cleanup = () => {
|
|
3689
|
+
ro.disconnect();
|
|
3116
3690
|
container.remove();
|
|
3117
3691
|
ctx.container.innerHTML = "";
|
|
3118
3692
|
};
|
|
@@ -3134,16 +3708,11 @@ var ExcelPlugin = class {
|
|
|
3134
3708
|
},
|
|
3135
3709
|
fitToPage: () => {
|
|
3136
3710
|
scale = calculateFitScale();
|
|
3137
|
-
rotation = 0;
|
|
3138
3711
|
applyTransform();
|
|
3139
3712
|
},
|
|
3140
3713
|
rotateCW: () => {
|
|
3141
|
-
rotation = (rotation + 90) % 360;
|
|
3142
|
-
applyTransform();
|
|
3143
3714
|
},
|
|
3144
3715
|
rotateCCW: () => {
|
|
3145
|
-
rotation = (rotation - 90 + 360) % 360;
|
|
3146
|
-
applyTransform();
|
|
3147
3716
|
},
|
|
3148
3717
|
goToPage: (page) => {
|
|
3149
3718
|
if (page > 0 && page <= sheetNames.length) {
|
|
@@ -3152,6 +3721,63 @@ var ExcelPlugin = class {
|
|
|
3152
3721
|
},
|
|
3153
3722
|
getPageCount: () => sheetNames.length,
|
|
3154
3723
|
getCurrentPage: () => currentSheetIndex,
|
|
3724
|
+
getThumbnails: () => {
|
|
3725
|
+
return sheetNames.map((name, idx) => ({
|
|
3726
|
+
index: idx,
|
|
3727
|
+
label: name,
|
|
3728
|
+
render: async (canvas) => {
|
|
3729
|
+
canvas.width = 140;
|
|
3730
|
+
canvas.height = 100;
|
|
3731
|
+
const c = canvas.getContext("2d");
|
|
3732
|
+
if (!c) return;
|
|
3733
|
+
c.fillStyle = "#ffffff";
|
|
3734
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
3735
|
+
c.fillStyle = "#107c41";
|
|
3736
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
3737
|
+
c.fillStyle = "#ffffff";
|
|
3738
|
+
c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
3739
|
+
c.fillText(`\u{1F4CA} ${name.slice(0, 16)}`, 6, 11);
|
|
3740
|
+
const startY = 17;
|
|
3741
|
+
const rowH = 13;
|
|
3742
|
+
const colW = 30;
|
|
3743
|
+
const colHeaders = ["A", "B", "C", "D"];
|
|
3744
|
+
c.fillStyle = "#f1f5f9";
|
|
3745
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
3746
|
+
c.strokeStyle = "#cbd5e1";
|
|
3747
|
+
c.lineWidth = 0.8;
|
|
3748
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
3749
|
+
c.fillStyle = "#64748b";
|
|
3750
|
+
c.font = "bold 7px sans-serif";
|
|
3751
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3752
|
+
c.fillText(colHeaders[ci], 14 + ci * colW, startY + 9);
|
|
3753
|
+
}
|
|
3754
|
+
const ws = wb?.Sheets[name];
|
|
3755
|
+
for (let ri = 1; ri <= 5; ri++) {
|
|
3756
|
+
const y = startY + ri * rowH;
|
|
3757
|
+
if (y > canvas.height - 2) break;
|
|
3758
|
+
c.fillStyle = "#f8fafc";
|
|
3759
|
+
c.fillRect(0, y, 12, rowH);
|
|
3760
|
+
c.fillStyle = "#94a3b8";
|
|
3761
|
+
c.font = "6px sans-serif";
|
|
3762
|
+
c.fillText(String(ri), 3, y + 9);
|
|
3763
|
+
c.strokeStyle = "#e2e8f0";
|
|
3764
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
3765
|
+
c.fillStyle = "#334155";
|
|
3766
|
+
c.font = "6px sans-serif";
|
|
3767
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3768
|
+
const cellRef = `${colHeaders[ci]}${ri}`;
|
|
3769
|
+
const cellVal = ws?.[cellRef]?.w || ws?.[cellRef]?.v;
|
|
3770
|
+
if (cellVal !== void 0) {
|
|
3771
|
+
c.fillText(String(cellVal).slice(0, 6), 14 + ci * colW, y + 9);
|
|
3772
|
+
}
|
|
3773
|
+
}
|
|
3774
|
+
}
|
|
3775
|
+
c.strokeStyle = "#cbd5e1";
|
|
3776
|
+
c.lineWidth = 1;
|
|
3777
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
3778
|
+
}
|
|
3779
|
+
}));
|
|
3780
|
+
},
|
|
3155
3781
|
download: () => {
|
|
3156
3782
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
3157
3783
|
const url = URL.createObjectURL(blob);
|
|
@@ -3184,7 +3810,16 @@ var CsvPlugin = class {
|
|
|
3184
3810
|
return ext === ".csv" || ext === ".tsv" || mime === "text/csv" || mime === "text/tab-separated-values";
|
|
3185
3811
|
}
|
|
3186
3812
|
getToolbarActions(instance) {
|
|
3187
|
-
|
|
3813
|
+
const actions = [];
|
|
3814
|
+
actions.push({
|
|
3815
|
+
id: "thumbnails",
|
|
3816
|
+
icon: "thumbnails",
|
|
3817
|
+
label: "Sheet Thumbnails",
|
|
3818
|
+
type: "button",
|
|
3819
|
+
group: "navigation",
|
|
3820
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3821
|
+
});
|
|
3822
|
+
actions.push(
|
|
3188
3823
|
{
|
|
3189
3824
|
id: "zoom-out",
|
|
3190
3825
|
icon: "zoom-out",
|
|
@@ -3224,8 +3859,19 @@ var CsvPlugin = class {
|
|
|
3224
3859
|
execute: () => {
|
|
3225
3860
|
instance.print?.();
|
|
3226
3861
|
}
|
|
3862
|
+
},
|
|
3863
|
+
{
|
|
3864
|
+
id: "open-window",
|
|
3865
|
+
icon: "open-window",
|
|
3866
|
+
label: "Open in Separate Full Window",
|
|
3867
|
+
type: "button",
|
|
3868
|
+
group: "actions",
|
|
3869
|
+
execute: () => {
|
|
3870
|
+
instance.openInSeparateWindow?.();
|
|
3871
|
+
}
|
|
3227
3872
|
}
|
|
3228
|
-
|
|
3873
|
+
);
|
|
3874
|
+
return actions;
|
|
3229
3875
|
}
|
|
3230
3876
|
async render(ctx) {
|
|
3231
3877
|
const decoder = new TextDecoder("utf-8");
|
|
@@ -3236,57 +3882,156 @@ var CsvPlugin = class {
|
|
|
3236
3882
|
container.style.overflow = "auto";
|
|
3237
3883
|
container.style.padding = "16px";
|
|
3238
3884
|
container.style.boxSizing = "border-box";
|
|
3239
|
-
|
|
3885
|
+
const tableWrapper = document.createElement("div");
|
|
3886
|
+
tableWrapper.style.transformOrigin = "top left";
|
|
3887
|
+
const delimiter = ctx.metadata.extension === ".tsv" ? " " : ",";
|
|
3888
|
+
const allLines = text.split(/\r?\n/).filter((r) => r.trim().length > 0);
|
|
3889
|
+
const headerLine = allLines[0] || "";
|
|
3890
|
+
const headerCells = headerLine.split(delimiter);
|
|
3891
|
+
const dataLines = allLines.slice(1);
|
|
3240
3892
|
const table = document.createElement("table");
|
|
3241
3893
|
table.style.borderCollapse = "collapse";
|
|
3242
|
-
table.style.
|
|
3243
|
-
table.style.fontFamily = "monospace
|
|
3894
|
+
table.style.minWidth = "100%";
|
|
3895
|
+
table.style.fontFamily = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace';
|
|
3244
3896
|
table.style.fontSize = "13px";
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3897
|
+
table.style.background = "#ffffff";
|
|
3898
|
+
table.style.border = "1px solid #d0d7de";
|
|
3899
|
+
const headerTr = document.createElement("tr");
|
|
3900
|
+
headerCells.forEach((cell) => {
|
|
3901
|
+
const th = document.createElement("th");
|
|
3902
|
+
th.textContent = cell.trim();
|
|
3903
|
+
th.style.border = "1px solid #d0d7de";
|
|
3904
|
+
th.style.padding = "8px 12px";
|
|
3905
|
+
th.style.backgroundColor = "#f6f8fa";
|
|
3906
|
+
th.style.fontWeight = "600";
|
|
3907
|
+
th.style.whiteSpace = "nowrap";
|
|
3908
|
+
headerTr.appendChild(th);
|
|
3909
|
+
});
|
|
3910
|
+
table.appendChild(headerTr);
|
|
3911
|
+
dataLines.forEach((row, idx) => {
|
|
3249
3912
|
const tr = document.createElement("tr");
|
|
3913
|
+
if (idx % 2 === 1) tr.style.backgroundColor = "#f8fafc";
|
|
3250
3914
|
const cells = row.split(delimiter);
|
|
3251
3915
|
cells.forEach((cell) => {
|
|
3252
|
-
const td = document.createElement(
|
|
3916
|
+
const td = document.createElement("td");
|
|
3253
3917
|
td.textContent = cell.trim();
|
|
3254
3918
|
td.style.border = "1px solid #d0d7de";
|
|
3255
3919
|
td.style.padding = "6px 12px";
|
|
3256
|
-
|
|
3257
|
-
td.style.backgroundColor = "#f6f8fa";
|
|
3258
|
-
td.style.fontWeight = "bold";
|
|
3259
|
-
}
|
|
3920
|
+
td.style.whiteSpace = "nowrap";
|
|
3260
3921
|
tr.appendChild(td);
|
|
3261
3922
|
});
|
|
3262
3923
|
table.appendChild(tr);
|
|
3263
3924
|
});
|
|
3264
|
-
|
|
3925
|
+
tableWrapper.appendChild(table);
|
|
3926
|
+
container.appendChild(tableWrapper);
|
|
3265
3927
|
ctx.container.appendChild(container);
|
|
3266
3928
|
let scale = 1;
|
|
3929
|
+
const calculateFitScale = () => {
|
|
3930
|
+
const availW = Math.max(280, container.clientWidth - 48);
|
|
3931
|
+
const tW = table.offsetWidth || 800;
|
|
3932
|
+
return Math.max(0.4, Math.min(1, availW / tW));
|
|
3933
|
+
};
|
|
3934
|
+
const applyScale = () => {
|
|
3935
|
+
tableWrapper.style.transform = `scale(${scale})`;
|
|
3936
|
+
};
|
|
3937
|
+
requestAnimationFrame(() => {
|
|
3938
|
+
scale = calculateFitScale();
|
|
3939
|
+
applyScale();
|
|
3940
|
+
});
|
|
3941
|
+
const ro = new ResizeObserver(() => {
|
|
3942
|
+
scale = calculateFitScale();
|
|
3943
|
+
applyScale();
|
|
3944
|
+
});
|
|
3945
|
+
ro.observe(container);
|
|
3267
3946
|
const cleanup = () => {
|
|
3947
|
+
ro.disconnect();
|
|
3268
3948
|
container.remove();
|
|
3269
3949
|
ctx.container.innerHTML = "";
|
|
3270
3950
|
};
|
|
3271
3951
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3272
3952
|
return {
|
|
3273
3953
|
destroy: cleanup,
|
|
3954
|
+
getPageCount: () => 1,
|
|
3955
|
+
getCurrentPage: () => 1,
|
|
3956
|
+
goToPage: () => {
|
|
3957
|
+
},
|
|
3958
|
+
getThumbnails: () => {
|
|
3959
|
+
const sheetName = ctx.metadata.name?.replace(/\.[^/.]+$/, "") || "Sheet1";
|
|
3960
|
+
return [{
|
|
3961
|
+
index: 0,
|
|
3962
|
+
label: sheetName,
|
|
3963
|
+
render: async (canvas) => {
|
|
3964
|
+
canvas.width = 140;
|
|
3965
|
+
canvas.height = 100;
|
|
3966
|
+
const c = canvas.getContext("2d");
|
|
3967
|
+
if (!c) return;
|
|
3968
|
+
c.fillStyle = "#ffffff";
|
|
3969
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
3970
|
+
c.fillStyle = "#107c41";
|
|
3971
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
3972
|
+
c.fillStyle = "#ffffff";
|
|
3973
|
+
c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
3974
|
+
c.fillText(`\u{1F4CA} ${sheetName.slice(0, 16)}`, 6, 11);
|
|
3975
|
+
const startY = 17;
|
|
3976
|
+
const rowH = 13;
|
|
3977
|
+
const colW = 30;
|
|
3978
|
+
const cols = headerCells.slice(0, 4).map((h) => h.trim() || "Col");
|
|
3979
|
+
c.fillStyle = "#f1f5f9";
|
|
3980
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
3981
|
+
c.strokeStyle = "#cbd5e1";
|
|
3982
|
+
c.lineWidth = 0.8;
|
|
3983
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
3984
|
+
c.fillStyle = "#64748b";
|
|
3985
|
+
c.font = "bold 7px sans-serif";
|
|
3986
|
+
for (let ci = 0; ci < cols.length; ci++) {
|
|
3987
|
+
c.fillText(cols[ci].slice(0, 5), 14 + ci * colW, startY + 9);
|
|
3988
|
+
}
|
|
3989
|
+
for (let ri = 0; ri < Math.min(5, dataLines.length); ri++) {
|
|
3990
|
+
const y = startY + (ri + 1) * rowH;
|
|
3991
|
+
if (y > canvas.height - 2) break;
|
|
3992
|
+
c.fillStyle = "#f8fafc";
|
|
3993
|
+
c.fillRect(0, y, 12, rowH);
|
|
3994
|
+
c.fillStyle = "#94a3b8";
|
|
3995
|
+
c.font = "6px sans-serif";
|
|
3996
|
+
c.fillText(String(ri + 1), 3, y + 9);
|
|
3997
|
+
c.strokeStyle = "#e2e8f0";
|
|
3998
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
3999
|
+
const rowCells = dataLines[ri].split(delimiter);
|
|
4000
|
+
c.fillStyle = "#334155";
|
|
4001
|
+
c.font = "6px sans-serif";
|
|
4002
|
+
for (let ci = 0; ci < cols.length; ci++) {
|
|
4003
|
+
const val = (rowCells[ci] || "").trim();
|
|
4004
|
+
if (val) {
|
|
4005
|
+
c.fillText(val.slice(0, 6), 14 + ci * colW, y + 9);
|
|
4006
|
+
}
|
|
4007
|
+
}
|
|
4008
|
+
}
|
|
4009
|
+
c.strokeStyle = "#cbd5e1";
|
|
4010
|
+
c.lineWidth = 1;
|
|
4011
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4012
|
+
}
|
|
4013
|
+
}];
|
|
4014
|
+
},
|
|
3274
4015
|
zoomIn: () => {
|
|
3275
4016
|
scale += 0.1;
|
|
3276
|
-
|
|
4017
|
+
applyScale();
|
|
3277
4018
|
},
|
|
3278
4019
|
zoomOut: () => {
|
|
3279
4020
|
scale = Math.max(0.2, scale - 0.1);
|
|
3280
|
-
|
|
4021
|
+
applyScale();
|
|
3281
4022
|
},
|
|
3282
4023
|
getZoom: () => scale,
|
|
3283
4024
|
setZoom: (level) => {
|
|
3284
4025
|
scale = level;
|
|
3285
|
-
|
|
4026
|
+
applyScale();
|
|
3286
4027
|
},
|
|
3287
4028
|
fitToPage: () => {
|
|
3288
|
-
scale =
|
|
3289
|
-
|
|
4029
|
+
scale = calculateFitScale();
|
|
4030
|
+
applyScale();
|
|
4031
|
+
},
|
|
4032
|
+
rotateCW: () => {
|
|
4033
|
+
},
|
|
4034
|
+
rotateCCW: () => {
|
|
3290
4035
|
},
|
|
3291
4036
|
download: () => {
|
|
3292
4037
|
const blob = new Blob([ctx.buffer], { type: "text/csv" });
|
|
@@ -3350,28 +4095,34 @@ var CodePlugin = class {
|
|
|
3350
4095
|
getToolbarActions(instance) {
|
|
3351
4096
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3352
4097
|
const actions = [];
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
4098
|
+
actions.push({
|
|
4099
|
+
id: "thumbnails",
|
|
4100
|
+
icon: "thumbnails",
|
|
4101
|
+
label: "Page Thumbnails",
|
|
4102
|
+
type: "button",
|
|
4103
|
+
group: "navigation",
|
|
4104
|
+
execute: () => instance.toggleThumbnails?.()
|
|
4105
|
+
});
|
|
4106
|
+
actions.push({
|
|
4107
|
+
id: "page-nav",
|
|
4108
|
+
icon: "",
|
|
4109
|
+
label: "Page Navigation",
|
|
4110
|
+
type: "page-nav",
|
|
4111
|
+
group: "navigation",
|
|
4112
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4113
|
+
max: totalPages,
|
|
4114
|
+
execute: (action, page) => {
|
|
4115
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4116
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4117
|
+
if (action === "prev") {
|
|
4118
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4119
|
+
} else if (action === "next") {
|
|
4120
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4121
|
+
} else if (typeof page === "number") {
|
|
4122
|
+
instance.goToPage?.(page);
|
|
3372
4123
|
}
|
|
3373
|
-
}
|
|
3374
|
-
}
|
|
4124
|
+
}
|
|
4125
|
+
});
|
|
3375
4126
|
actions.push(
|
|
3376
4127
|
{
|
|
3377
4128
|
id: "zoom-out",
|
|
@@ -3393,26 +4144,6 @@ var CodePlugin = class {
|
|
|
3393
4144
|
instance.zoomIn?.();
|
|
3394
4145
|
}
|
|
3395
4146
|
},
|
|
3396
|
-
{
|
|
3397
|
-
id: "fit-page",
|
|
3398
|
-
icon: "fit-page",
|
|
3399
|
-
label: "Fit to View",
|
|
3400
|
-
type: "button",
|
|
3401
|
-
group: "zoom",
|
|
3402
|
-
execute: () => {
|
|
3403
|
-
instance.fitToPage?.();
|
|
3404
|
-
}
|
|
3405
|
-
},
|
|
3406
|
-
{
|
|
3407
|
-
id: "rotate-cw",
|
|
3408
|
-
icon: "rotate-cw",
|
|
3409
|
-
label: "Rotate",
|
|
3410
|
-
type: "button",
|
|
3411
|
-
group: "view",
|
|
3412
|
-
execute: () => {
|
|
3413
|
-
instance.rotateCW?.();
|
|
3414
|
-
}
|
|
3415
|
-
},
|
|
3416
4147
|
{
|
|
3417
4148
|
id: "copy",
|
|
3418
4149
|
icon: "copy",
|
|
@@ -3515,16 +4246,19 @@ var CodePlugin = class {
|
|
|
3515
4246
|
let fontSize = 13;
|
|
3516
4247
|
let rotation = 0;
|
|
3517
4248
|
let zoomLevel = 1;
|
|
4249
|
+
let isUserZoomed = false;
|
|
3518
4250
|
const pre = document.createElement("pre");
|
|
3519
4251
|
const code = document.createElement("code");
|
|
3520
4252
|
if (isTxt) {
|
|
4253
|
+
container.style.overflowX = "hidden";
|
|
4254
|
+
container.style.overflowY = "auto";
|
|
3521
4255
|
container.style.backgroundColor = "#f1f5f9";
|
|
3522
|
-
container.style.padding = "
|
|
4256
|
+
container.style.padding = "16px 8px";
|
|
3523
4257
|
container.style.boxSizing = "border-box";
|
|
3524
4258
|
container.style.display = "flex";
|
|
3525
4259
|
container.style.flexDirection = "column";
|
|
3526
4260
|
container.style.alignItems = "center";
|
|
3527
|
-
pre.style.margin = "0";
|
|
4261
|
+
pre.style.margin = "0 auto";
|
|
3528
4262
|
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3529
4263
|
pre.style.fontSize = "13px";
|
|
3530
4264
|
pre.style.color = "#1e293b";
|
|
@@ -3536,10 +4270,12 @@ var CodePlugin = class {
|
|
|
3536
4270
|
pre.style.minHeight = "1056px";
|
|
3537
4271
|
pre.style.padding = "72px 56px";
|
|
3538
4272
|
pre.style.boxSizing = "border-box";
|
|
3539
|
-
pre.style.boxShadow = "0 4px
|
|
4273
|
+
pre.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
3540
4274
|
pre.style.borderRadius = "4px";
|
|
3541
4275
|
pre.style.transformOrigin = "top center";
|
|
4276
|
+
pre.style.transition = "transform 0.15s ease";
|
|
3542
4277
|
} else {
|
|
4278
|
+
container.style.overflow = "auto";
|
|
3543
4279
|
container.style.backgroundColor = "#1e1e1e";
|
|
3544
4280
|
container.style.color = "#d4d4d4";
|
|
3545
4281
|
container.style.padding = "16px";
|
|
@@ -3571,42 +4307,9 @@ var CodePlugin = class {
|
|
|
3571
4307
|
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
3572
4308
|
pre.appendChild(code);
|
|
3573
4309
|
container.appendChild(pre);
|
|
3574
|
-
let indicator = null;
|
|
3575
|
-
if (totalPages > 1) {
|
|
3576
|
-
indicator = document.createElement("div");
|
|
3577
|
-
indicator.className = "fp-code-page-indicator";
|
|
3578
|
-
indicator.style.position = "sticky";
|
|
3579
|
-
indicator.style.bottom = "16px";
|
|
3580
|
-
if (isTxt) {
|
|
3581
|
-
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3582
|
-
indicator.style.color = "#334155";
|
|
3583
|
-
indicator.style.border = "1px solid #e2e8f0";
|
|
3584
|
-
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3585
|
-
} else {
|
|
3586
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3587
|
-
indicator.style.color = "#f8fafc";
|
|
3588
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3589
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3590
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
3591
|
-
}
|
|
3592
|
-
indicator.style.fontSize = "12px";
|
|
3593
|
-
indicator.style.fontWeight = "600";
|
|
3594
|
-
indicator.style.padding = "5px 14px";
|
|
3595
|
-
indicator.style.borderRadius = "20px";
|
|
3596
|
-
indicator.style.zIndex = "10";
|
|
3597
|
-
indicator.style.userSelect = "none";
|
|
3598
|
-
indicator.style.pointerEvents = "none";
|
|
3599
|
-
indicator.style.textAlign = "center";
|
|
3600
|
-
indicator.style.width = "fit-content";
|
|
3601
|
-
indicator.style.margin = "16px auto 0";
|
|
3602
|
-
container.appendChild(indicator);
|
|
3603
|
-
}
|
|
3604
4310
|
const showPage = (pageNum) => {
|
|
3605
4311
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3606
4312
|
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
3607
|
-
if (indicator) {
|
|
3608
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3609
|
-
}
|
|
3610
4313
|
container.scrollTop = 0;
|
|
3611
4314
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3612
4315
|
};
|
|
@@ -3614,36 +4317,90 @@ var CodePlugin = class {
|
|
|
3614
4317
|
showPage(1);
|
|
3615
4318
|
}
|
|
3616
4319
|
ctx.container.appendChild(container);
|
|
3617
|
-
const
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
ctx.container.innerHTML = "";
|
|
4320
|
+
const calculateTxtFit = () => {
|
|
4321
|
+
const availW = Math.max(280, container.clientWidth - 32);
|
|
4322
|
+
return Math.max(0.4, Math.min(3, availW / 816));
|
|
3621
4323
|
};
|
|
3622
|
-
ctx.signal.addEventListener("abort", cleanup);
|
|
3623
4324
|
const updateTransform = () => {
|
|
3624
4325
|
if (isTxt) {
|
|
3625
4326
|
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
4327
|
+
const scaledH = 1056 * zoomLevel;
|
|
4328
|
+
const extraH = Math.max(0, scaledH - 1056);
|
|
4329
|
+
pre.style.marginBottom = `${extraH + 32}px`;
|
|
3626
4330
|
} else {
|
|
3627
4331
|
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3628
4332
|
pre.style.fontSize = `${fontSize}px`;
|
|
3629
4333
|
}
|
|
3630
4334
|
};
|
|
4335
|
+
let resizeObserver = null;
|
|
4336
|
+
if (isTxt) {
|
|
4337
|
+
setTimeout(() => {
|
|
4338
|
+
zoomLevel = calculateTxtFit();
|
|
4339
|
+
updateTransform();
|
|
4340
|
+
}, 60);
|
|
4341
|
+
resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
4342
|
+
if (!isUserZoomed) {
|
|
4343
|
+
zoomLevel = calculateTxtFit();
|
|
4344
|
+
updateTransform();
|
|
4345
|
+
}
|
|
4346
|
+
}) : null;
|
|
4347
|
+
resizeObserver?.observe(container);
|
|
4348
|
+
}
|
|
4349
|
+
const cleanup = () => {
|
|
4350
|
+
resizeObserver?.disconnect();
|
|
4351
|
+
container.remove();
|
|
4352
|
+
ctx.container.innerHTML = "";
|
|
4353
|
+
};
|
|
4354
|
+
ctx.signal.addEventListener("abort", cleanup);
|
|
3631
4355
|
return {
|
|
3632
4356
|
destroy: cleanup,
|
|
3633
4357
|
getPageCount: () => totalPages,
|
|
3634
4358
|
getCurrentPage: () => currentPage,
|
|
3635
4359
|
goToPage: (page) => showPage(page),
|
|
4360
|
+
getThumbnails: () => {
|
|
4361
|
+
return rawPages.map((pageText, idx) => ({
|
|
4362
|
+
index: idx,
|
|
4363
|
+
label: `Page ${idx + 1}`,
|
|
4364
|
+
render: async (canvas) => {
|
|
4365
|
+
canvas.width = 140;
|
|
4366
|
+
canvas.height = 180;
|
|
4367
|
+
const c = canvas.getContext("2d");
|
|
4368
|
+
if (!c) return;
|
|
4369
|
+
c.fillStyle = "#ffffff";
|
|
4370
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4371
|
+
c.strokeStyle = "#cbd5e1";
|
|
4372
|
+
c.lineWidth = 1;
|
|
4373
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4374
|
+
c.fillStyle = "#64748b";
|
|
4375
|
+
const lines = (pageText || "").split("\n").slice(0, 24);
|
|
4376
|
+
const lineH = 6;
|
|
4377
|
+
const startY = 14;
|
|
4378
|
+
const startX = 12;
|
|
4379
|
+
const maxW = canvas.width - 24;
|
|
4380
|
+
c.font = "5px monospace";
|
|
4381
|
+
for (let li = 0; li < lines.length; li++) {
|
|
4382
|
+
const l = lines[li].trim();
|
|
4383
|
+
if (!l) continue;
|
|
4384
|
+
const y = startY + li * lineH;
|
|
4385
|
+
if (y > canvas.height - 12) break;
|
|
4386
|
+
c.fillText(l.slice(0, 30), startX, y, maxW);
|
|
4387
|
+
}
|
|
4388
|
+
}
|
|
4389
|
+
}));
|
|
4390
|
+
},
|
|
3636
4391
|
zoomIn: () => {
|
|
4392
|
+
isUserZoomed = true;
|
|
3637
4393
|
if (isTxt) {
|
|
3638
|
-
zoomLevel = Math.min(3, zoomLevel + 0.
|
|
4394
|
+
zoomLevel = Math.min(3.5, zoomLevel + 0.15);
|
|
3639
4395
|
} else {
|
|
3640
4396
|
fontSize = Math.min(32, fontSize + 2);
|
|
3641
4397
|
}
|
|
3642
4398
|
updateTransform();
|
|
3643
4399
|
},
|
|
3644
4400
|
zoomOut: () => {
|
|
4401
|
+
isUserZoomed = true;
|
|
3645
4402
|
if (isTxt) {
|
|
3646
|
-
zoomLevel = Math.max(0.1, zoomLevel - 0.
|
|
4403
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.15);
|
|
3647
4404
|
} else {
|
|
3648
4405
|
fontSize = Math.max(8, fontSize - 2);
|
|
3649
4406
|
}
|
|
@@ -3651,6 +4408,7 @@ var CodePlugin = class {
|
|
|
3651
4408
|
},
|
|
3652
4409
|
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
3653
4410
|
setZoom: (level) => {
|
|
4411
|
+
isUserZoomed = true;
|
|
3654
4412
|
if (isTxt) {
|
|
3655
4413
|
zoomLevel = level;
|
|
3656
4414
|
} else {
|
|
@@ -3659,9 +4417,10 @@ var CodePlugin = class {
|
|
|
3659
4417
|
updateTransform();
|
|
3660
4418
|
},
|
|
3661
4419
|
fitToPage: () => {
|
|
4420
|
+
isUserZoomed = false;
|
|
3662
4421
|
fontSize = 13;
|
|
3663
4422
|
rotation = 0;
|
|
3664
|
-
zoomLevel = isTxt ?
|
|
4423
|
+
zoomLevel = isTxt ? calculateTxtFit() : 1;
|
|
3665
4424
|
updateTransform();
|
|
3666
4425
|
},
|
|
3667
4426
|
rotateCW: () => {
|
|
@@ -4528,6 +5287,148 @@ var ThreeDPlugin = class {
|
|
|
4528
5287
|
function threeDPlugin() {
|
|
4529
5288
|
return new ThreeDPlugin();
|
|
4530
5289
|
}
|
|
5290
|
+
function cleanRtfText(raw) {
|
|
5291
|
+
return raw.replace(/\\bin\d+\s/g, "").replace(/{\\\*[^}]+}/g, "").replace(/\\u(-?\d+)\??/g, (_, code) => {
|
|
5292
|
+
let num = parseInt(code, 10);
|
|
5293
|
+
if (num < 0) num += 65536;
|
|
5294
|
+
return String.fromCharCode(num);
|
|
5295
|
+
}).replace(/\\'([0-9a-fA-F]{2})/g, (_, hex) => {
|
|
5296
|
+
return String.fromCharCode(parseInt(hex, 16));
|
|
5297
|
+
}).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();
|
|
5298
|
+
}
|
|
5299
|
+
function parseRtfTables(rtfText) {
|
|
5300
|
+
const rowSegments = rtfText.split(/\\row\b/);
|
|
5301
|
+
if (rowSegments.length <= 1) return [];
|
|
5302
|
+
const rawTables = [];
|
|
5303
|
+
let currentTable = null;
|
|
5304
|
+
let charOffset = 0;
|
|
5305
|
+
for (let i = 0; i < rowSegments.length - 1; i++) {
|
|
5306
|
+
const segment = rowSegments[i];
|
|
5307
|
+
const segmentStart = charOffset;
|
|
5308
|
+
const segmentEnd = charOffset + segment.length + 4;
|
|
5309
|
+
const cellParts = segment.split(/\\cell\b/);
|
|
5310
|
+
if (cellParts.length > 1) {
|
|
5311
|
+
const cellxMatches = [...segment.matchAll(/\\cellx(\d+)/g)].map((m) => parseInt(m[1], 10));
|
|
5312
|
+
let cellWidths = [];
|
|
5313
|
+
if (cellxMatches.length > 0) {
|
|
5314
|
+
let seq = [cellxMatches[0]];
|
|
5315
|
+
for (let k = 1; k < cellxMatches.length; k++) {
|
|
5316
|
+
if (cellxMatches[k] > cellxMatches[k - 1]) seq.push(cellxMatches[k]);
|
|
5317
|
+
else break;
|
|
5318
|
+
}
|
|
5319
|
+
let prev = 0;
|
|
5320
|
+
cellWidths = seq.map((x) => {
|
|
5321
|
+
const w = x - prev;
|
|
5322
|
+
prev = x;
|
|
5323
|
+
return w;
|
|
5324
|
+
});
|
|
5325
|
+
}
|
|
5326
|
+
const cells = [];
|
|
5327
|
+
for (let c = 0; c < cellParts.length - 1; c++) {
|
|
5328
|
+
let rawCell = cellParts[c];
|
|
5329
|
+
if (c === 0) {
|
|
5330
|
+
const lastTrowd = rawCell.lastIndexOf("\\trowd");
|
|
5331
|
+
if (lastTrowd !== -1) rawCell = rawCell.slice(lastTrowd);
|
|
5332
|
+
}
|
|
5333
|
+
cells.push(cleanRtfText(rawCell));
|
|
5334
|
+
}
|
|
5335
|
+
const isNewTable = !currentTable || segmentStart - currentTable.lastEnd > 2500;
|
|
5336
|
+
if (isNewTable) {
|
|
5337
|
+
const prevTextSlice = rtfText.slice(Math.max(0, segmentStart - 4e3), segmentStart);
|
|
5338
|
+
const cleanPrev = cleanRtfText(prevTextSlice);
|
|
5339
|
+
const anchorBefore = cleanPrev.slice(-80).trim();
|
|
5340
|
+
currentTable = {
|
|
5341
|
+
id: `RTF_TABLE_${rawTables.length}`,
|
|
5342
|
+
startPos: segmentStart,
|
|
5343
|
+
lastEnd: segmentEnd,
|
|
5344
|
+
rows: [],
|
|
5345
|
+
columnWidths: cellWidths,
|
|
5346
|
+
anchorBefore,
|
|
5347
|
+
anchorAfter: ""
|
|
5348
|
+
};
|
|
5349
|
+
rawTables.push(currentTable);
|
|
5350
|
+
}
|
|
5351
|
+
if (currentTable) {
|
|
5352
|
+
currentTable.rows.push({
|
|
5353
|
+
cells,
|
|
5354
|
+
widths: cellWidths.length === cells.length ? cellWidths : currentTable.columnWidths
|
|
5355
|
+
});
|
|
5356
|
+
currentTable.lastEnd = segmentEnd;
|
|
5357
|
+
}
|
|
5358
|
+
}
|
|
5359
|
+
charOffset += segment.length + 4;
|
|
5360
|
+
}
|
|
5361
|
+
rawTables.forEach((tbl) => {
|
|
5362
|
+
const afterSlice = rtfText.slice(tbl.lastEnd, Math.min(rtfText.length, tbl.lastEnd + 2e3));
|
|
5363
|
+
const cleanAfter = cleanRtfText(afterSlice);
|
|
5364
|
+
tbl.anchorAfter = cleanAfter.slice(0, 80).trim();
|
|
5365
|
+
});
|
|
5366
|
+
return rawTables.map((tbl) => {
|
|
5367
|
+
const totalW = (tbl.columnWidths || []).reduce((a, b) => a + b, 0);
|
|
5368
|
+
const colPercents = totalW > 0 ? tbl.columnWidths.map((w) => Math.round(w / totalW * 100)) : [];
|
|
5369
|
+
return {
|
|
5370
|
+
id: tbl.id,
|
|
5371
|
+
rows: tbl.rows.map((r) => r.cells),
|
|
5372
|
+
colPercents,
|
|
5373
|
+
anchorBefore: tbl.anchorBefore,
|
|
5374
|
+
anchorAfter: tbl.anchorAfter
|
|
5375
|
+
};
|
|
5376
|
+
});
|
|
5377
|
+
}
|
|
5378
|
+
function renderRtfTableElement(table) {
|
|
5379
|
+
const tableEl = document.createElement("table");
|
|
5380
|
+
tableEl.className = "fp-rtf-table";
|
|
5381
|
+
tableEl.style.width = "100%";
|
|
5382
|
+
tableEl.style.borderCollapse = "collapse";
|
|
5383
|
+
tableEl.style.margin = "16px 0 20px";
|
|
5384
|
+
tableEl.style.fontSize = "10pt";
|
|
5385
|
+
tableEl.style.lineHeight = "1.5";
|
|
5386
|
+
tableEl.style.border = "1px solid #cbd5e1";
|
|
5387
|
+
tableEl.style.borderRadius = "4px";
|
|
5388
|
+
tableEl.style.boxSizing = "border-box";
|
|
5389
|
+
tableEl.style.backgroundColor = "#ffffff";
|
|
5390
|
+
const thead = document.createElement("thead");
|
|
5391
|
+
const tbody = document.createElement("tbody");
|
|
5392
|
+
table.rows.forEach((rowCells, rIdx) => {
|
|
5393
|
+
const tr = document.createElement("tr");
|
|
5394
|
+
const isHeader = rIdx === 0;
|
|
5395
|
+
if (isHeader) {
|
|
5396
|
+
tr.style.backgroundColor = "#f8fafc";
|
|
5397
|
+
tr.style.borderBottom = "2px solid #cbd5e1";
|
|
5398
|
+
} else {
|
|
5399
|
+
tr.style.borderBottom = "1px solid #e2e8f0";
|
|
5400
|
+
if (rIdx % 2 === 0) {
|
|
5401
|
+
tr.style.backgroundColor = "#fcfdfe";
|
|
5402
|
+
}
|
|
5403
|
+
}
|
|
5404
|
+
rowCells.forEach((cellText, cIdx) => {
|
|
5405
|
+
const cellEl = document.createElement(isHeader ? "th" : "td");
|
|
5406
|
+
cellEl.style.padding = "8px 12px";
|
|
5407
|
+
cellEl.style.border = "1px solid #cbd5e1";
|
|
5408
|
+
cellEl.style.verticalAlign = "top";
|
|
5409
|
+
cellEl.style.color = isHeader ? "#0f172a" : "#1e293b";
|
|
5410
|
+
cellEl.style.fontWeight = isHeader ? "600" : "normal";
|
|
5411
|
+
if (table.colPercents && table.colPercents[cIdx]) {
|
|
5412
|
+
cellEl.style.width = `${table.colPercents[cIdx]}%`;
|
|
5413
|
+
}
|
|
5414
|
+
if (/^\d+$/.test(cellText.trim()) || cellText.trim() === "#") {
|
|
5415
|
+
cellEl.style.textAlign = "center";
|
|
5416
|
+
} else {
|
|
5417
|
+
cellEl.style.textAlign = "left";
|
|
5418
|
+
}
|
|
5419
|
+
cellEl.textContent = cellText;
|
|
5420
|
+
tr.appendChild(cellEl);
|
|
5421
|
+
});
|
|
5422
|
+
if (isHeader) {
|
|
5423
|
+
thead.appendChild(tr);
|
|
5424
|
+
} else {
|
|
5425
|
+
tbody.appendChild(tr);
|
|
5426
|
+
}
|
|
5427
|
+
});
|
|
5428
|
+
tableEl.appendChild(thead);
|
|
5429
|
+
tableEl.appendChild(tbody);
|
|
5430
|
+
return tableEl;
|
|
5431
|
+
}
|
|
4531
5432
|
var RtfPlugin = class {
|
|
4532
5433
|
id = "rtf";
|
|
4533
5434
|
name = "Rich Text Format (RTF)";
|
|
@@ -4542,29 +5443,35 @@ var RtfPlugin = class {
|
|
|
4542
5443
|
getToolbarActions(instance) {
|
|
4543
5444
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4544
5445
|
const actions = [];
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
if (
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
instance.goToPage?.(page);
|
|
4563
|
-
}
|
|
5446
|
+
actions.push({
|
|
5447
|
+
id: "page-nav",
|
|
5448
|
+
icon: "",
|
|
5449
|
+
label: "Page Navigation",
|
|
5450
|
+
type: "page-nav",
|
|
5451
|
+
group: "navigation",
|
|
5452
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5453
|
+
max: totalPages,
|
|
5454
|
+
execute: (action, page) => {
|
|
5455
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5456
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5457
|
+
if (action === "prev") {
|
|
5458
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5459
|
+
} else if (action === "next") {
|
|
5460
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5461
|
+
} else if (typeof page === "number") {
|
|
5462
|
+
instance.goToPage?.(page);
|
|
4564
5463
|
}
|
|
4565
|
-
}
|
|
4566
|
-
}
|
|
5464
|
+
}
|
|
5465
|
+
});
|
|
4567
5466
|
actions.push(
|
|
5467
|
+
{
|
|
5468
|
+
id: "thumbnails",
|
|
5469
|
+
icon: "thumbnails",
|
|
5470
|
+
label: "Thumbnails",
|
|
5471
|
+
type: "button",
|
|
5472
|
+
group: "view",
|
|
5473
|
+
execute: () => instance.toggleThumbnails?.()
|
|
5474
|
+
},
|
|
4568
5475
|
{
|
|
4569
5476
|
id: "zoom-out",
|
|
4570
5477
|
icon: "zoom-out",
|
|
@@ -4635,67 +5542,143 @@ var RtfPlugin = class {
|
|
|
4635
5542
|
async render(ctx) {
|
|
4636
5543
|
const wrapper = document.createElement("div");
|
|
4637
5544
|
wrapper.className = "fp-rtf-wrapper";
|
|
4638
|
-
wrapper.style.padding = "
|
|
4639
|
-
wrapper.style.
|
|
5545
|
+
wrapper.style.padding = "0";
|
|
5546
|
+
wrapper.style.width = "816px";
|
|
4640
5547
|
wrapper.style.margin = "0 auto";
|
|
4641
|
-
wrapper.style.
|
|
4642
|
-
wrapper.style.
|
|
4643
|
-
wrapper.style.
|
|
4644
|
-
wrapper.style.
|
|
5548
|
+
wrapper.style.boxSizing = "border-box";
|
|
5549
|
+
wrapper.style.display = "flex";
|
|
5550
|
+
wrapper.style.flexDirection = "column";
|
|
5551
|
+
wrapper.style.alignItems = "center";
|
|
5552
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4645
5553
|
wrapper.style.transformOrigin = "top center";
|
|
4646
|
-
wrapper.style.transition = "transform 0.
|
|
4647
|
-
ctx.container.style.
|
|
4648
|
-
ctx.container.style.
|
|
5554
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5555
|
+
ctx.container.style.overflowX = "hidden";
|
|
5556
|
+
ctx.container.style.overflowY = "auto";
|
|
5557
|
+
ctx.container.style.padding = "16px 8px";
|
|
4649
5558
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
4650
5559
|
ctx.container.appendChild(wrapper);
|
|
4651
5560
|
let scale = 1;
|
|
4652
5561
|
let rotation = 0;
|
|
4653
5562
|
let pageElements = [];
|
|
4654
|
-
let
|
|
5563
|
+
let isUserZoomed = false;
|
|
5564
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
4655
5565
|
const calculateFitScale = (mode = fitMode) => {
|
|
4656
5566
|
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4657
|
-
const elW =
|
|
4658
|
-
const singlePageH =
|
|
4659
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
4660
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
5567
|
+
const elW = 816;
|
|
5568
|
+
const singlePageH = activeEl?.offsetHeight || 1056;
|
|
5569
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
5570
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
4661
5571
|
const sW = availW / elW;
|
|
4662
5572
|
const sH = availH / singlePageH;
|
|
4663
5573
|
if (mode === "page") {
|
|
4664
|
-
return Math.max(0.
|
|
5574
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
4665
5575
|
}
|
|
4666
|
-
return Math.max(0.
|
|
5576
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
4667
5577
|
};
|
|
4668
5578
|
const applyTransform = () => {
|
|
4669
5579
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4670
5580
|
wrapper.style.transformOrigin = "top center";
|
|
5581
|
+
const activeEl = pageElements[currentPage - 1];
|
|
5582
|
+
const baseH = activeEl?.offsetHeight || 1056;
|
|
5583
|
+
const scaledH = baseH * scale;
|
|
5584
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
5585
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
4671
5586
|
};
|
|
5587
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
5588
|
+
if (!isUserZoomed) {
|
|
5589
|
+
scale = calculateFitScale(fitMode);
|
|
5590
|
+
applyTransform();
|
|
5591
|
+
}
|
|
5592
|
+
}) : null;
|
|
5593
|
+
resizeObserver?.observe(ctx.container);
|
|
4672
5594
|
setTimeout(() => {
|
|
4673
|
-
|
|
4674
|
-
scale = calculateFitScale("width");
|
|
5595
|
+
scale = calculateFitScale(fitMode);
|
|
4675
5596
|
applyTransform();
|
|
4676
5597
|
}, 60);
|
|
4677
5598
|
try {
|
|
4678
5599
|
if (typeof RTFJS.loggingEnabled === "function") {
|
|
4679
5600
|
RTFJS.loggingEnabled(false);
|
|
4680
5601
|
}
|
|
5602
|
+
const rawText = new TextDecoder("latin1").decode(ctx.buffer);
|
|
5603
|
+
const tables = parseRtfTables(rawText);
|
|
4681
5604
|
const doc = new RTFJS.Document(ctx.buffer, {});
|
|
4682
5605
|
const htmlElements = await doc.render();
|
|
4683
5606
|
const contentNodes = [];
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
5607
|
+
const extractBlocks = (nodes) => {
|
|
5608
|
+
for (const item of nodes) {
|
|
5609
|
+
if (!item || !(item instanceof HTMLElement)) continue;
|
|
5610
|
+
const tag = item.tagName.toLowerCase();
|
|
5611
|
+
const hasChildBlocks = Array.from(item.children).some((c) => {
|
|
5612
|
+
const ct = c.tagName.toLowerCase();
|
|
5613
|
+
return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
|
|
5614
|
+
});
|
|
5615
|
+
if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
|
|
5616
|
+
extractBlocks(Array.from(item.children));
|
|
5617
|
+
} else {
|
|
5618
|
+
const svgs = item.querySelectorAll("svg, img");
|
|
5619
|
+
svgs.forEach((s) => {
|
|
5620
|
+
const el = s;
|
|
5621
|
+
el.style.maxWidth = "100%";
|
|
5622
|
+
el.style.maxHeight = "360px";
|
|
5623
|
+
el.style.display = "block";
|
|
5624
|
+
el.style.margin = "12px auto";
|
|
5625
|
+
if (s.tagName.toLowerCase() === "svg") {
|
|
5626
|
+
s.removeAttribute("width");
|
|
5627
|
+
s.removeAttribute("height");
|
|
5628
|
+
el.style.width = "100%";
|
|
5629
|
+
el.style.maxHeight = "360px";
|
|
5630
|
+
}
|
|
5631
|
+
});
|
|
5632
|
+
if (tag === "p" || tag === "div") {
|
|
5633
|
+
item.style.display = "block";
|
|
5634
|
+
item.style.marginBottom = "12px";
|
|
5635
|
+
item.style.lineHeight = "1.6";
|
|
5636
|
+
}
|
|
5637
|
+
contentNodes.push(item);
|
|
5638
|
+
}
|
|
4689
5639
|
}
|
|
4690
|
-
}
|
|
5640
|
+
};
|
|
5641
|
+
extractBlocks(htmlElements);
|
|
5642
|
+
tables.forEach((table) => {
|
|
5643
|
+
const tableEl = renderRtfTableElement(table);
|
|
5644
|
+
let inserted = false;
|
|
5645
|
+
if (table.anchorBefore && table.anchorBefore.length > 10) {
|
|
5646
|
+
const keyword = table.anchorBefore.slice(-35).trim();
|
|
5647
|
+
for (let i = 0; i < contentNodes.length; i++) {
|
|
5648
|
+
if (contentNodes[i].textContent?.includes(keyword)) {
|
|
5649
|
+
contentNodes.splice(i + 1, 0, tableEl);
|
|
5650
|
+
inserted = true;
|
|
5651
|
+
break;
|
|
5652
|
+
}
|
|
5653
|
+
}
|
|
5654
|
+
}
|
|
5655
|
+
if (!inserted && table.anchorAfter && table.anchorAfter.length > 10) {
|
|
5656
|
+
const keyword = table.anchorAfter.slice(0, 35).trim();
|
|
5657
|
+
for (let i = 0; i < contentNodes.length; i++) {
|
|
5658
|
+
if (contentNodes[i].textContent?.includes(keyword)) {
|
|
5659
|
+
contentNodes.splice(i, 0, tableEl);
|
|
5660
|
+
inserted = true;
|
|
5661
|
+
break;
|
|
5662
|
+
}
|
|
5663
|
+
}
|
|
5664
|
+
}
|
|
5665
|
+
if (!inserted) {
|
|
5666
|
+
if (contentNodes.length > 2) {
|
|
5667
|
+
contentNodes.splice(2, 0, tableEl);
|
|
5668
|
+
} else {
|
|
5669
|
+
contentNodes.push(tableEl);
|
|
5670
|
+
}
|
|
5671
|
+
}
|
|
5672
|
+
});
|
|
4691
5673
|
wrapper.innerHTML = "";
|
|
4692
5674
|
contentNodes.forEach((node) => wrapper.appendChild(node));
|
|
4693
5675
|
const childHeights = contentNodes.map((c) => {
|
|
4694
5676
|
const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
|
|
4695
5677
|
const offH = c.offsetHeight || 0;
|
|
5678
|
+
const realH = Math.max(rectH, offH);
|
|
5679
|
+
if (realH > 0) return realH;
|
|
4696
5680
|
const textLen = c.textContent?.trim().length || 0;
|
|
4697
|
-
|
|
4698
|
-
return Math.max(rectH, offH, estH);
|
|
5681
|
+
return Math.max(24, Math.ceil(textLen / 95) * 22 + 12);
|
|
4699
5682
|
});
|
|
4700
5683
|
wrapper.innerHTML = "";
|
|
4701
5684
|
const createRtfCard = () => {
|
|
@@ -4704,35 +5687,49 @@ var RtfPlugin = class {
|
|
|
4704
5687
|
card.style.backgroundColor = "#ffffff";
|
|
4705
5688
|
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
4706
5689
|
card.style.borderRadius = "4px";
|
|
4707
|
-
card.style.padding = "
|
|
5690
|
+
card.style.padding = "64px 56px";
|
|
4708
5691
|
card.style.width = "816px";
|
|
4709
5692
|
card.style.minHeight = "1056px";
|
|
4710
5693
|
card.style.boxSizing = "border-box";
|
|
4711
5694
|
card.style.marginBottom = "24px";
|
|
4712
5695
|
card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4713
5696
|
card.style.lineHeight = "1.6";
|
|
5697
|
+
card.style.color = "#1e293b";
|
|
4714
5698
|
return card;
|
|
4715
5699
|
};
|
|
4716
5700
|
let curCard = createRtfCard();
|
|
4717
5701
|
wrapper.appendChild(curCard);
|
|
4718
5702
|
pageElements = [curCard];
|
|
4719
5703
|
let curH = 0;
|
|
4720
|
-
const maxH =
|
|
5704
|
+
const maxH = 928;
|
|
4721
5705
|
for (let i = 0; i < contentNodes.length; i++) {
|
|
4722
5706
|
const child = contentNodes[i];
|
|
4723
5707
|
const chH = childHeights[i];
|
|
4724
|
-
|
|
4725
|
-
curH
|
|
4726
|
-
|
|
5708
|
+
const isChildEmpty = (child.textContent || "").trim().length === 0 && !child.querySelector("table, img, svg, canvas");
|
|
5709
|
+
if (curH === 0 && isChildEmpty) {
|
|
5710
|
+
continue;
|
|
5711
|
+
}
|
|
5712
|
+
if (curH + chH > maxH && curCard.childNodes.length > 0) {
|
|
4727
5713
|
curCard = createRtfCard();
|
|
4728
5714
|
wrapper.appendChild(curCard);
|
|
4729
5715
|
pageElements.push(curCard);
|
|
4730
5716
|
curH = 0;
|
|
4731
5717
|
}
|
|
5718
|
+
curCard.appendChild(child);
|
|
5719
|
+
curH += chH;
|
|
5720
|
+
}
|
|
5721
|
+
pageElements = pageElements.filter((card) => {
|
|
5722
|
+
const hasText = (card.textContent || "").trim().length > 0;
|
|
5723
|
+
const hasMedia = card.querySelector("table, img, svg, canvas") !== null;
|
|
5724
|
+
return hasText || hasMedia;
|
|
5725
|
+
});
|
|
5726
|
+
if (pageElements.length === 0) {
|
|
5727
|
+
pageElements = [curCard];
|
|
4732
5728
|
}
|
|
4733
5729
|
} catch (err) {
|
|
4734
5730
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
4735
5731
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
5732
|
+
const tables = parseRtfTables(text);
|
|
4736
5733
|
const rawPages = text.split(/\\page\b/).map((segment) => {
|
|
4737
5734
|
return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
|
|
4738
5735
|
}).filter((p) => p.length > 0);
|
|
@@ -4743,47 +5740,26 @@ var RtfPlugin = class {
|
|
|
4743
5740
|
pageCard.style.backgroundColor = "#ffffff";
|
|
4744
5741
|
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4745
5742
|
pageCard.style.borderRadius = "4px";
|
|
4746
|
-
pageCard.style.padding = "
|
|
5743
|
+
pageCard.style.padding = "64px 56px";
|
|
4747
5744
|
pageCard.style.width = "816px";
|
|
4748
5745
|
pageCard.style.minHeight = "1056px";
|
|
4749
|
-
pageCard.style.maxWidth = "100%";
|
|
4750
5746
|
pageCard.style.boxSizing = "border-box";
|
|
4751
|
-
pageCard.style.fontFamily = "serif
|
|
5747
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4752
5748
|
pageCard.style.fontSize = "12pt";
|
|
4753
5749
|
pageCard.style.lineHeight = "1.6";
|
|
4754
5750
|
pageCard.style.color = "#1e293b";
|
|
4755
5751
|
pageCard.style.whiteSpace = "pre-wrap";
|
|
4756
5752
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4757
5753
|
pageCard.textContent = pages[i];
|
|
5754
|
+
if (i === 1 && tables.length > 0) {
|
|
5755
|
+
tables.forEach((tbl) => pageCard.appendChild(renderRtfTableElement(tbl)));
|
|
5756
|
+
}
|
|
4758
5757
|
wrapper.appendChild(pageCard);
|
|
4759
5758
|
pageElements.push(pageCard);
|
|
4760
5759
|
}
|
|
4761
5760
|
}
|
|
4762
5761
|
const totalPages = Math.max(1, pageElements.length);
|
|
4763
5762
|
let currentPage = 1;
|
|
4764
|
-
let indicator = null;
|
|
4765
|
-
if (totalPages > 1) {
|
|
4766
|
-
indicator = document.createElement("div");
|
|
4767
|
-
indicator.className = "fp-rtf-page-indicator";
|
|
4768
|
-
indicator.style.position = "sticky";
|
|
4769
|
-
indicator.style.bottom = "16px";
|
|
4770
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4771
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
4772
|
-
indicator.style.color = "#f8fafc";
|
|
4773
|
-
indicator.style.fontSize = "12px";
|
|
4774
|
-
indicator.style.fontWeight = "600";
|
|
4775
|
-
indicator.style.padding = "5px 14px";
|
|
4776
|
-
indicator.style.borderRadius = "20px";
|
|
4777
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4778
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4779
|
-
indicator.style.zIndex = "10";
|
|
4780
|
-
indicator.style.userSelect = "none";
|
|
4781
|
-
indicator.style.pointerEvents = "none";
|
|
4782
|
-
indicator.style.textAlign = "center";
|
|
4783
|
-
indicator.style.width = "fit-content";
|
|
4784
|
-
indicator.style.margin = "16px auto 0";
|
|
4785
|
-
ctx.container.appendChild(indicator);
|
|
4786
|
-
}
|
|
4787
5763
|
const showPage = (pageNum) => {
|
|
4788
5764
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4789
5765
|
if (totalPages > 1) {
|
|
@@ -4791,9 +5767,6 @@ var RtfPlugin = class {
|
|
|
4791
5767
|
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4792
5768
|
});
|
|
4793
5769
|
}
|
|
4794
|
-
if (indicator) {
|
|
4795
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4796
|
-
}
|
|
4797
5770
|
ctx.container.scrollTop = 0;
|
|
4798
5771
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4799
5772
|
};
|
|
@@ -4801,7 +5774,7 @@ var RtfPlugin = class {
|
|
|
4801
5774
|
showPage(1);
|
|
4802
5775
|
}
|
|
4803
5776
|
const cleanup = () => {
|
|
4804
|
-
|
|
5777
|
+
resizeObserver?.disconnect();
|
|
4805
5778
|
wrapper.remove();
|
|
4806
5779
|
ctx.container.innerHTML = "";
|
|
4807
5780
|
};
|
|
@@ -4811,22 +5784,52 @@ var RtfPlugin = class {
|
|
|
4811
5784
|
getPageCount: () => totalPages,
|
|
4812
5785
|
getCurrentPage: () => currentPage,
|
|
4813
5786
|
goToPage: (page) => showPage(page),
|
|
5787
|
+
getThumbnails: async () => {
|
|
5788
|
+
const items = [];
|
|
5789
|
+
for (let idx = 0; idx < totalPages; idx++) {
|
|
5790
|
+
const pageIdx = idx;
|
|
5791
|
+
items.push({
|
|
5792
|
+
index: pageIdx,
|
|
5793
|
+
label: `Page ${pageIdx + 1}`,
|
|
5794
|
+
render: async (canvas) => {
|
|
5795
|
+
const ctx2d = canvas.getContext("2d");
|
|
5796
|
+
if (!ctx2d) return;
|
|
5797
|
+
canvas.width = 140;
|
|
5798
|
+
canvas.height = 180;
|
|
5799
|
+
ctx2d.fillStyle = "#ffffff";
|
|
5800
|
+
ctx2d.fillRect(0, 0, 140, 180);
|
|
5801
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
5802
|
+
ctx2d.lineWidth = 1;
|
|
5803
|
+
ctx2d.strokeRect(0.5, 0.5, 139, 179);
|
|
5804
|
+
ctx2d.fillStyle = "#334155";
|
|
5805
|
+
ctx2d.font = 'bold 11px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
5806
|
+
ctx2d.textAlign = "center";
|
|
5807
|
+
ctx2d.fillText(`Page ${pageIdx + 1}`, 70, 95);
|
|
5808
|
+
}
|
|
5809
|
+
});
|
|
5810
|
+
}
|
|
5811
|
+
return items;
|
|
5812
|
+
},
|
|
4814
5813
|
zoomIn: () => {
|
|
5814
|
+
isUserZoomed = true;
|
|
4815
5815
|
scale += 0.15;
|
|
4816
5816
|
applyTransform();
|
|
4817
5817
|
},
|
|
4818
5818
|
zoomOut: () => {
|
|
5819
|
+
isUserZoomed = true;
|
|
4819
5820
|
scale = Math.max(0.2, scale - 0.15);
|
|
4820
5821
|
applyTransform();
|
|
4821
5822
|
},
|
|
4822
5823
|
getZoom: () => scale,
|
|
4823
5824
|
setZoom: (level) => {
|
|
5825
|
+
isUserZoomed = true;
|
|
4824
5826
|
scale = level;
|
|
4825
5827
|
applyTransform();
|
|
4826
5828
|
},
|
|
4827
5829
|
fitToPage: () => {
|
|
4828
|
-
|
|
4829
|
-
|
|
5830
|
+
isUserZoomed = false;
|
|
5831
|
+
fitMode = "width";
|
|
5832
|
+
scale = calculateFitScale("width");
|
|
4830
5833
|
rotation = 0;
|
|
4831
5834
|
applyTransform();
|
|
4832
5835
|
},
|
|
@@ -5014,40 +6017,36 @@ var OpenDocumentPlugin = class {
|
|
|
5014
6017
|
const isPresentation = instance.isPresentation;
|
|
5015
6018
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5016
6019
|
const actions = [];
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
max
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
if (
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
instance.goToPage?.(page);
|
|
5045
|
-
} else if (typeof action === "number") {
|
|
5046
|
-
instance.goToPage?.(action);
|
|
5047
|
-
}
|
|
6020
|
+
actions.push({
|
|
6021
|
+
id: "thumbnails",
|
|
6022
|
+
icon: "thumbnails",
|
|
6023
|
+
label: isPresentation ? "Slide Thumbnails" : "Page Thumbnails",
|
|
6024
|
+
type: "button",
|
|
6025
|
+
group: "navigation",
|
|
6026
|
+
execute: () => instance.toggleThumbnails?.()
|
|
6027
|
+
});
|
|
6028
|
+
actions.push({
|
|
6029
|
+
id: "page-nav",
|
|
6030
|
+
icon: "",
|
|
6031
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
6032
|
+
type: "page-nav",
|
|
6033
|
+
group: "navigation",
|
|
6034
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
6035
|
+
max: totalPages,
|
|
6036
|
+
execute: (action, page) => {
|
|
6037
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
6038
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
6039
|
+
if (action === "prev") {
|
|
6040
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
6041
|
+
} else if (action === "next") {
|
|
6042
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
6043
|
+
} else if (typeof page === "number") {
|
|
6044
|
+
instance.goToPage?.(page);
|
|
6045
|
+
} else if (typeof action === "number") {
|
|
6046
|
+
instance.goToPage?.(action);
|
|
5048
6047
|
}
|
|
5049
|
-
}
|
|
5050
|
-
}
|
|
6048
|
+
}
|
|
6049
|
+
});
|
|
5051
6050
|
actions.push(
|
|
5052
6051
|
{
|
|
5053
6052
|
id: "zoom-out",
|
|
@@ -5138,49 +6137,65 @@ var OpenDocumentPlugin = class {
|
|
|
5138
6137
|
container.className = "fp-odf-container";
|
|
5139
6138
|
container.style.width = "100%";
|
|
5140
6139
|
container.style.height = "100%";
|
|
5141
|
-
container.style.
|
|
5142
|
-
container.style.
|
|
6140
|
+
container.style.overflowX = "hidden";
|
|
6141
|
+
container.style.overflowY = "auto";
|
|
6142
|
+
container.style.padding = "16px 8px";
|
|
5143
6143
|
container.style.backgroundColor = "#f1f5f9";
|
|
5144
6144
|
const wrapper = document.createElement("div");
|
|
5145
6145
|
wrapper.className = "fp-odf-wrapper";
|
|
5146
6146
|
wrapper.style.margin = "0 auto";
|
|
6147
|
+
wrapper.style.width = isPresentation ? "960px" : "816px";
|
|
6148
|
+
wrapper.style.boxSizing = "border-box";
|
|
5147
6149
|
wrapper.style.backgroundColor = "#ffffff";
|
|
5148
6150
|
wrapper.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
5149
6151
|
wrapper.style.borderRadius = "4px";
|
|
5150
6152
|
wrapper.style.transformOrigin = "top center";
|
|
5151
|
-
wrapper.style.transition = "transform 0.
|
|
6153
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5152
6154
|
container.appendChild(wrapper);
|
|
5153
6155
|
ctx.container.appendChild(container);
|
|
5154
6156
|
let scale = 1;
|
|
5155
6157
|
let rotation = 0;
|
|
5156
|
-
let
|
|
6158
|
+
let isUserZoomed = false;
|
|
6159
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6160
|
+
let currentPage = 1;
|
|
6161
|
+
let totalPages = 1;
|
|
6162
|
+
let slides = [];
|
|
5157
6163
|
const calculateFitScale = (mode = fitMode) => {
|
|
5158
|
-
const
|
|
5159
|
-
const
|
|
5160
|
-
const
|
|
5161
|
-
const
|
|
6164
|
+
const activeSlide = slides[currentPage - 1];
|
|
6165
|
+
const elW = isPresentation ? 960 : 816;
|
|
6166
|
+
const singlePageH = Math.min(activeSlide?.offsetHeight || wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
6167
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6168
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5162
6169
|
const sW = availW / elW;
|
|
5163
6170
|
const sH = availH / (isPresentation ? 540 : singlePageH);
|
|
5164
6171
|
if (isPresentation) {
|
|
5165
|
-
return Math.min(
|
|
6172
|
+
return Math.min(2.5, Math.min(sW, sH));
|
|
5166
6173
|
}
|
|
5167
6174
|
if (mode === "page") {
|
|
5168
|
-
return Math.max(0.
|
|
6175
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5169
6176
|
}
|
|
5170
|
-
return Math.max(0.
|
|
6177
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5171
6178
|
};
|
|
5172
6179
|
const applyTransform = () => {
|
|
5173
6180
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5174
6181
|
wrapper.style.transformOrigin = "top center";
|
|
6182
|
+
const activeSlide = slides[currentPage - 1];
|
|
6183
|
+
const baseH = activeSlide?.offsetHeight || wrapper.offsetHeight || 1056;
|
|
6184
|
+
const scaledH = baseH * scale;
|
|
6185
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6186
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
5175
6187
|
};
|
|
6188
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6189
|
+
if (!isUserZoomed) {
|
|
6190
|
+
scale = calculateFitScale(fitMode);
|
|
6191
|
+
applyTransform();
|
|
6192
|
+
}
|
|
6193
|
+
}) : null;
|
|
6194
|
+
resizeObserver?.observe(ctx.container);
|
|
5176
6195
|
setTimeout(() => {
|
|
5177
|
-
|
|
5178
|
-
scale = calculateFitScale("width");
|
|
6196
|
+
scale = calculateFitScale(fitMode);
|
|
5179
6197
|
applyTransform();
|
|
5180
6198
|
}, 60);
|
|
5181
|
-
let currentPage = 1;
|
|
5182
|
-
let totalPages = 1;
|
|
5183
|
-
let slides = [];
|
|
5184
6199
|
if (isPresentation) {
|
|
5185
6200
|
wrapper.style.maxWidth = "960px";
|
|
5186
6201
|
wrapper.style.aspectRatio = "16 / 9";
|
|
@@ -5281,24 +6296,9 @@ var OpenDocumentPlugin = class {
|
|
|
5281
6296
|
wrapper.appendChild(page);
|
|
5282
6297
|
slides.push(page);
|
|
5283
6298
|
});
|
|
5284
|
-
const pageIndicator = document.createElement("div");
|
|
5285
|
-
pageIndicator.className = "fp-odt-page-indicator";
|
|
5286
|
-
pageIndicator.style.position = "sticky";
|
|
5287
|
-
pageIndicator.style.bottom = "16px";
|
|
5288
|
-
pageIndicator.style.left = "50%";
|
|
5289
|
-
pageIndicator.style.transform = "translateX(-50%)";
|
|
5290
|
-
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
5291
|
-
pageIndicator.style.color = "#fff";
|
|
5292
|
-
pageIndicator.style.padding = "6px 12px";
|
|
5293
|
-
pageIndicator.style.borderRadius = "16px";
|
|
5294
|
-
pageIndicator.style.fontSize = "12px";
|
|
5295
|
-
pageIndicator.style.zIndex = "100";
|
|
5296
|
-
pageIndicator.style.display = "inline-block";
|
|
5297
|
-
pageIndicator.style.width = "fit-content";
|
|
5298
|
-
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
5299
|
-
container.appendChild(pageIndicator);
|
|
5300
6299
|
}
|
|
5301
6300
|
const cleanup = () => {
|
|
6301
|
+
resizeObserver?.disconnect();
|
|
5302
6302
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
5303
6303
|
container.remove();
|
|
5304
6304
|
ctx.container.innerHTML = "";
|
|
@@ -5310,10 +6310,6 @@ var OpenDocumentPlugin = class {
|
|
|
5310
6310
|
slides.forEach((s, idx) => {
|
|
5311
6311
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
5312
6312
|
});
|
|
5313
|
-
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
5314
|
-
if (indicator) {
|
|
5315
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5316
|
-
}
|
|
5317
6313
|
container.scrollTop = 0;
|
|
5318
6314
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5319
6315
|
};
|
|
@@ -5321,21 +6317,25 @@ var OpenDocumentPlugin = class {
|
|
|
5321
6317
|
destroy: cleanup,
|
|
5322
6318
|
isPresentation,
|
|
5323
6319
|
zoomIn: () => {
|
|
6320
|
+
isUserZoomed = true;
|
|
5324
6321
|
scale += 0.15;
|
|
5325
6322
|
applyTransform();
|
|
5326
6323
|
},
|
|
5327
6324
|
zoomOut: () => {
|
|
6325
|
+
isUserZoomed = true;
|
|
5328
6326
|
scale = Math.max(0.2, scale - 0.15);
|
|
5329
6327
|
applyTransform();
|
|
5330
6328
|
},
|
|
5331
6329
|
getZoom: () => scale,
|
|
5332
6330
|
setZoom: (level) => {
|
|
6331
|
+
isUserZoomed = true;
|
|
5333
6332
|
scale = level;
|
|
5334
6333
|
applyTransform();
|
|
5335
6334
|
},
|
|
5336
6335
|
fitToPage: () => {
|
|
5337
|
-
|
|
5338
|
-
|
|
6336
|
+
isUserZoomed = false;
|
|
6337
|
+
fitMode = "width";
|
|
6338
|
+
scale = calculateFitScale("width");
|
|
5339
6339
|
rotation = 0;
|
|
5340
6340
|
applyTransform();
|
|
5341
6341
|
},
|
|
@@ -5351,23 +6351,45 @@ var OpenDocumentPlugin = class {
|
|
|
5351
6351
|
getPageCount: () => totalPages,
|
|
5352
6352
|
getCurrentPage: () => currentPage,
|
|
5353
6353
|
getThumbnails: async () => {
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
canvas
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
6354
|
+
const count = totalPages || slides.length || 1;
|
|
6355
|
+
const items = [];
|
|
6356
|
+
for (let idx = 0; idx < count; idx++) {
|
|
6357
|
+
const itemIdx = idx;
|
|
6358
|
+
items.push({
|
|
6359
|
+
index: itemIdx,
|
|
6360
|
+
label: isPresentation ? `Slide ${itemIdx + 1}` : `Page ${itemIdx + 1}`,
|
|
6361
|
+
render: async (canvas) => {
|
|
6362
|
+
const ctx2d = canvas.getContext("2d");
|
|
6363
|
+
if (!ctx2d) return;
|
|
6364
|
+
if (isPresentation) {
|
|
6365
|
+
canvas.width = 160;
|
|
6366
|
+
canvas.height = 90;
|
|
6367
|
+
ctx2d.fillStyle = "#f8fafc";
|
|
6368
|
+
ctx2d.fillRect(0, 0, 160, 90);
|
|
6369
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6370
|
+
ctx2d.lineWidth = 1;
|
|
6371
|
+
ctx2d.strokeRect(0.5, 0.5, 159, 89);
|
|
6372
|
+
ctx2d.fillStyle = "#334155";
|
|
6373
|
+
ctx2d.font = "bold 11px sans-serif";
|
|
6374
|
+
ctx2d.textAlign = "center";
|
|
6375
|
+
ctx2d.fillText(`Slide ${itemIdx + 1}`, 80, 50);
|
|
6376
|
+
} else {
|
|
6377
|
+
canvas.width = 140;
|
|
6378
|
+
canvas.height = 180;
|
|
6379
|
+
ctx2d.fillStyle = "#ffffff";
|
|
6380
|
+
ctx2d.fillRect(0, 0, 140, 180);
|
|
6381
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6382
|
+
ctx2d.lineWidth = 1;
|
|
6383
|
+
ctx2d.strokeRect(0.5, 0.5, 139, 179);
|
|
6384
|
+
ctx2d.fillStyle = "#64748b";
|
|
6385
|
+
ctx2d.font = "bold 10px sans-serif";
|
|
6386
|
+
ctx2d.textAlign = "center";
|
|
6387
|
+
ctx2d.fillText(`Page ${itemIdx + 1}`, 70, 90);
|
|
6388
|
+
}
|
|
6389
|
+
}
|
|
6390
|
+
});
|
|
6391
|
+
}
|
|
6392
|
+
return items;
|
|
5371
6393
|
},
|
|
5372
6394
|
download: () => {
|
|
5373
6395
|
const mimeType = this.mimeTypes.find((m) => m.includes(ext.replace(".", ""))) || "application/octet-stream";
|
|
@@ -5472,23 +6494,24 @@ var OpenDocumentPlugin = class {
|
|
|
5472
6494
|
case "h": {
|
|
5473
6495
|
const level = Math.min(6, Math.max(1, Number(node.getAttribute("text:outline-level") || 1)));
|
|
5474
6496
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5475
|
-
html += `<h${level} style="${style}; font-family:
|
|
6497
|
+
html += `<h${level} style="${style}; margin: 18px 0 8px; color: #1e3a8a; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${node.textContent || ""}</h${level}>`;
|
|
5476
6498
|
break;
|
|
5477
6499
|
}
|
|
5478
6500
|
case "p": {
|
|
5479
6501
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5480
6502
|
const inner = this.renderSpans(node, styles, images);
|
|
5481
|
-
|
|
6503
|
+
const isInsideLi = node.parentElement?.localName === "list-item" || node.parentElement?.tagName?.toLowerCase() === "list-item";
|
|
6504
|
+
html += `<p style="${style}; line-height: 1.5; margin: ${isInsideLi ? "0" : "8px 0 12px"}; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${inner}</p>`;
|
|
5482
6505
|
break;
|
|
5483
6506
|
}
|
|
5484
6507
|
case "list": {
|
|
5485
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
6508
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
5486
6509
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5487
6510
|
html += "</ul>";
|
|
5488
6511
|
break;
|
|
5489
6512
|
}
|
|
5490
6513
|
case "list-item": {
|
|
5491
|
-
html +=
|
|
6514
|
+
html += '<li style="margin: 4px 0; font-size: 11pt; line-height: 1.5; color: #1e293b;">';
|
|
5492
6515
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5493
6516
|
html += "</li>";
|
|
5494
6517
|
break;
|
|
@@ -5614,28 +6637,26 @@ var DocPlugin = class {
|
|
|
5614
6637
|
getToolbarActions(instance) {
|
|
5615
6638
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5616
6639
|
const actions = [];
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
if (
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
instance.goToPage?.(page);
|
|
5635
|
-
}
|
|
6640
|
+
actions.push({
|
|
6641
|
+
id: "page-nav",
|
|
6642
|
+
icon: "",
|
|
6643
|
+
label: "Page Navigation",
|
|
6644
|
+
type: "page-nav",
|
|
6645
|
+
group: "navigation",
|
|
6646
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
6647
|
+
max: totalPages,
|
|
6648
|
+
execute: (action, page) => {
|
|
6649
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
6650
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
6651
|
+
if (action === "prev") {
|
|
6652
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
6653
|
+
} else if (action === "next") {
|
|
6654
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
6655
|
+
} else if (typeof page === "number") {
|
|
6656
|
+
instance.goToPage?.(page);
|
|
5636
6657
|
}
|
|
5637
|
-
}
|
|
5638
|
-
}
|
|
6658
|
+
}
|
|
6659
|
+
});
|
|
5639
6660
|
actions.push(
|
|
5640
6661
|
{
|
|
5641
6662
|
id: "zoom-out",
|
|
@@ -5709,8 +6730,9 @@ var DocPlugin = class {
|
|
|
5709
6730
|
container.className = "fp-doc-container";
|
|
5710
6731
|
container.style.width = "100%";
|
|
5711
6732
|
container.style.height = "100%";
|
|
5712
|
-
container.style.
|
|
5713
|
-
container.style.
|
|
6733
|
+
container.style.overflowX = "hidden";
|
|
6734
|
+
container.style.overflowY = "auto";
|
|
6735
|
+
container.style.padding = "16px 8px";
|
|
5714
6736
|
container.style.backgroundColor = "#f1f5f9";
|
|
5715
6737
|
container.style.display = "flex";
|
|
5716
6738
|
container.style.justifyContent = "center";
|
|
@@ -5755,16 +6777,15 @@ var DocPlugin = class {
|
|
|
5755
6777
|
const pageCard = document.createElement("div");
|
|
5756
6778
|
pageCard.className = "fp-doc-page-card";
|
|
5757
6779
|
pageCard.style.width = "816px";
|
|
5758
|
-
pageCard.style.
|
|
6780
|
+
pageCard.style.minHeight = "1056px";
|
|
5759
6781
|
pageCard.style.backgroundColor = "#ffffff";
|
|
5760
|
-
pageCard.style.boxShadow = "0
|
|
6782
|
+
pageCard.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
5761
6783
|
pageCard.style.borderRadius = "4px";
|
|
5762
|
-
pageCard.style.padding = "
|
|
6784
|
+
pageCard.style.padding = "72px 56px";
|
|
5763
6785
|
pageCard.style.boxSizing = "border-box";
|
|
5764
|
-
pageCard.style.overflow = "hidden";
|
|
5765
6786
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5766
6787
|
pageCard.style.transformOrigin = "top center";
|
|
5767
|
-
pageCard.style.transition = "transform 0.
|
|
6788
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
5768
6789
|
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5769
6790
|
pageCard.style.color = "#1e293b";
|
|
5770
6791
|
if (isFallback && i === 0) {
|
|
@@ -5781,34 +6802,15 @@ var DocPlugin = class {
|
|
|
5781
6802
|
container.appendChild(pageCard);
|
|
5782
6803
|
pageCards.push(pageCard);
|
|
5783
6804
|
}
|
|
5784
|
-
let indicator = null;
|
|
5785
|
-
if (totalPages > 1) {
|
|
5786
|
-
indicator = document.createElement("div");
|
|
5787
|
-
indicator.className = "fp-doc-page-indicator";
|
|
5788
|
-
indicator.style.position = "fixed";
|
|
5789
|
-
indicator.style.bottom = "16px";
|
|
5790
|
-
indicator.style.left = "50%";
|
|
5791
|
-
indicator.style.transform = "translateX(-50%)";
|
|
5792
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
5793
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
5794
|
-
indicator.style.color = "#f8fafc";
|
|
5795
|
-
indicator.style.fontSize = "12px";
|
|
5796
|
-
indicator.style.fontWeight = "600";
|
|
5797
|
-
indicator.style.padding = "5px 14px";
|
|
5798
|
-
indicator.style.borderRadius = "20px";
|
|
5799
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
5800
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
5801
|
-
indicator.style.zIndex = "10";
|
|
5802
|
-
indicator.style.userSelect = "none";
|
|
5803
|
-
indicator.style.pointerEvents = "none";
|
|
5804
|
-
indicator.style.textAlign = "center";
|
|
5805
|
-
container.appendChild(indicator);
|
|
5806
|
-
}
|
|
5807
6805
|
let rotation = 0;
|
|
5808
6806
|
const applyTransform = () => {
|
|
5809
6807
|
const activeCard = pageCards[currentPage - 1];
|
|
5810
6808
|
if (activeCard) {
|
|
5811
6809
|
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
6810
|
+
const baseH = activeCard.offsetHeight || 1056;
|
|
6811
|
+
const scaledH = baseH * scale;
|
|
6812
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6813
|
+
activeCard.style.marginBottom = `${extraH + 32}px`;
|
|
5812
6814
|
}
|
|
5813
6815
|
};
|
|
5814
6816
|
const showPage = (pageNum) => {
|
|
@@ -5821,35 +6823,39 @@ var DocPlugin = class {
|
|
|
5821
6823
|
card.style.display = "none";
|
|
5822
6824
|
}
|
|
5823
6825
|
});
|
|
5824
|
-
if (indicator) {
|
|
5825
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5826
|
-
}
|
|
5827
6826
|
container.scrollTop = 0;
|
|
5828
6827
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5829
6828
|
};
|
|
5830
6829
|
if (totalPages > 1) {
|
|
5831
6830
|
showPage(1);
|
|
5832
6831
|
}
|
|
5833
|
-
let fitMode = "width";
|
|
6832
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6833
|
+
let isUserZoomed = false;
|
|
5834
6834
|
const calculateFitScale = (mode = fitMode) => {
|
|
5835
6835
|
const elW = 816;
|
|
5836
6836
|
const elH = 1056;
|
|
5837
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
5838
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
6837
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6838
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5839
6839
|
const sW = availW / elW;
|
|
5840
6840
|
const sH = availH / elH;
|
|
5841
6841
|
if (mode === "page") {
|
|
5842
|
-
return Math.max(0.
|
|
6842
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5843
6843
|
}
|
|
5844
|
-
return Math.max(0.
|
|
6844
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5845
6845
|
};
|
|
6846
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6847
|
+
if (!isUserZoomed) {
|
|
6848
|
+
scale = calculateFitScale(fitMode);
|
|
6849
|
+
applyTransform();
|
|
6850
|
+
}
|
|
6851
|
+
}) : null;
|
|
6852
|
+
resizeObserver?.observe(ctx.container);
|
|
5846
6853
|
setTimeout(() => {
|
|
5847
|
-
|
|
5848
|
-
scale = calculateFitScale("width");
|
|
6854
|
+
scale = calculateFitScale(fitMode);
|
|
5849
6855
|
applyTransform();
|
|
5850
6856
|
}, 60);
|
|
5851
6857
|
const cleanup = () => {
|
|
5852
|
-
|
|
6858
|
+
resizeObserver?.disconnect();
|
|
5853
6859
|
container.remove();
|
|
5854
6860
|
ctx.container.innerHTML = "";
|
|
5855
6861
|
};
|
|
@@ -5860,21 +6866,25 @@ var DocPlugin = class {
|
|
|
5860
6866
|
getCurrentPage: () => currentPage,
|
|
5861
6867
|
goToPage: (page) => showPage(page),
|
|
5862
6868
|
zoomIn: () => {
|
|
6869
|
+
isUserZoomed = true;
|
|
5863
6870
|
scale += 0.15;
|
|
5864
6871
|
applyTransform();
|
|
5865
6872
|
},
|
|
5866
6873
|
zoomOut: () => {
|
|
6874
|
+
isUserZoomed = true;
|
|
5867
6875
|
scale = Math.max(0.2, scale - 0.15);
|
|
5868
6876
|
applyTransform();
|
|
5869
6877
|
},
|
|
5870
6878
|
getZoom: () => scale,
|
|
5871
6879
|
setZoom: (level) => {
|
|
6880
|
+
isUserZoomed = true;
|
|
5872
6881
|
scale = level;
|
|
5873
6882
|
applyTransform();
|
|
5874
6883
|
},
|
|
5875
6884
|
fitToPage: () => {
|
|
5876
|
-
|
|
5877
|
-
|
|
6885
|
+
isUserZoomed = false;
|
|
6886
|
+
fitMode = "width";
|
|
6887
|
+
scale = calculateFitScale("width");
|
|
5878
6888
|
rotation = 0;
|
|
5879
6889
|
applyTransform();
|
|
5880
6890
|
},
|
|
@@ -6251,25 +7261,31 @@ ${chartSvg}
|
|
|
6251
7261
|
i++;
|
|
6252
7262
|
continue;
|
|
6253
7263
|
}
|
|
6254
|
-
if (
|
|
7264
|
+
if (/^\d{1,2}$/.test(line.trim())) {
|
|
7265
|
+
i++;
|
|
7266
|
+
continue;
|
|
7267
|
+
}
|
|
7268
|
+
const isShortLine = line.length < 60 && !line.endsWith(".") && !line.endsWith(",");
|
|
7269
|
+
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));
|
|
7270
|
+
if (isTitleLike) {
|
|
6255
7271
|
if (inList) {
|
|
6256
7272
|
html += "</ul>";
|
|
6257
7273
|
inList = false;
|
|
6258
7274
|
}
|
|
6259
|
-
html += `<h2 style="font-size:
|
|
7275
|
+
html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 18px 0 10px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6.sanitize(line, sanitizeOptions)}</h2>`;
|
|
6260
7276
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
6261
7277
|
if (!inList) {
|
|
6262
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
7278
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
6263
7279
|
inList = true;
|
|
6264
7280
|
}
|
|
6265
7281
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
6266
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
7282
|
+
html += `<li style="margin: 4px 0; line-height: 1.5; font-size: 11pt; color: #1e293b;">${DOMPurify6.sanitize(bulletText, sanitizeOptions)}</li>`;
|
|
6267
7283
|
} else {
|
|
6268
7284
|
if (inList) {
|
|
6269
7285
|
html += "</ul>";
|
|
6270
7286
|
inList = false;
|
|
6271
7287
|
}
|
|
6272
|
-
html += `<p style="line-height: 1.
|
|
7288
|
+
html += `<p style="line-height: 1.5; margin: 0 0 12px 0; font-size: 11pt; color: #1e293b; text-align: justify;">${DOMPurify6.sanitize(line, sanitizeOptions)}</p>`;
|
|
6273
7289
|
}
|
|
6274
7290
|
i++;
|
|
6275
7291
|
}
|
|
@@ -6823,14 +7839,14 @@ var FilePreviewViewer2 = class extends FilePreviewViewer {
|
|
|
6823
7839
|
};
|
|
6824
7840
|
|
|
6825
7841
|
// src/angular.ts
|
|
6826
|
-
var _container_dec, _zoomChange_dec, _pageChange_dec, _error_dec, _loaded_dec, _loading_dec, _options_dec, _plugins_dec, _src_dec, _FilePreviewComponent_decorators, _init;
|
|
7842
|
+
var _container_dec, _destroyed_dec, _rotate_dec, _zoomChange_dec, _pageChange_dec, _error_dec, _loaded_dec, _loading_dec, _options_dec, _plugins_dec, _src_dec, _FilePreviewComponent_decorators, _init;
|
|
6827
7843
|
_FilePreviewComponent_decorators = [Component({
|
|
6828
7844
|
selector: "fp-file-preview",
|
|
6829
7845
|
standalone: true,
|
|
6830
7846
|
imports: [CommonModule],
|
|
6831
7847
|
template: `<div #container [style.width]="'100%'" [style.height]="'100%'"></div>`,
|
|
6832
7848
|
changeDetection: ChangeDetectionStrategy.OnPush
|
|
6833
|
-
})], _src_dec = [Input({ required: true })], _plugins_dec = [Input()], _options_dec = [Input()], _loading_dec = [Output()], _loaded_dec = [Output()], _error_dec = [Output()], _pageChange_dec = [Output()], _zoomChange_dec = [Output()], _container_dec = [ViewChild("container", { static: true })];
|
|
7849
|
+
})], _src_dec = [Input({ required: true })], _plugins_dec = [Input()], _options_dec = [Input()], _loading_dec = [Output()], _loaded_dec = [Output()], _error_dec = [Output()], _pageChange_dec = [Output()], _zoomChange_dec = [Output()], _rotate_dec = [Output()], _destroyed_dec = [Output()], _container_dec = [ViewChild("container", { static: true })];
|
|
6834
7850
|
var FilePreviewComponent = class {
|
|
6835
7851
|
constructor(ngZone) {
|
|
6836
7852
|
this.ngZone = ngZone;
|
|
@@ -6842,7 +7858,9 @@ var FilePreviewComponent = class {
|
|
|
6842
7858
|
__publicField(this, "error", __runInitializers(_init, 28, this, new EventEmitter$1())), __runInitializers(_init, 31, this);
|
|
6843
7859
|
__publicField(this, "pageChange", __runInitializers(_init, 32, this, new EventEmitter$1())), __runInitializers(_init, 35, this);
|
|
6844
7860
|
__publicField(this, "zoomChange", __runInitializers(_init, 36, this, new EventEmitter$1())), __runInitializers(_init, 39, this);
|
|
6845
|
-
__publicField(this, "
|
|
7861
|
+
__publicField(this, "rotate", __runInitializers(_init, 40, this, new EventEmitter$1())), __runInitializers(_init, 43, this);
|
|
7862
|
+
__publicField(this, "destroyed", __runInitializers(_init, 44, this, new EventEmitter$1())), __runInitializers(_init, 47, this);
|
|
7863
|
+
__publicField(this, "container", __runInitializers(_init, 48, this)), __runInitializers(_init, 51, this);
|
|
6846
7864
|
__publicField(this, "viewer", null);
|
|
6847
7865
|
__publicField(this, "instance", null);
|
|
6848
7866
|
}
|
|
@@ -6867,6 +7885,12 @@ var FilePreviewComponent = class {
|
|
|
6867
7885
|
viewer.on("zoom-change", (data) => {
|
|
6868
7886
|
this.ngZone.run(() => this.zoomChange.emit(data));
|
|
6869
7887
|
});
|
|
7888
|
+
viewer.on("rotate", (data) => {
|
|
7889
|
+
this.ngZone.run(() => this.rotate.emit(data));
|
|
7890
|
+
});
|
|
7891
|
+
viewer.on("destroy", () => {
|
|
7892
|
+
this.ngZone.run(() => this.destroyed.emit());
|
|
7893
|
+
});
|
|
6870
7894
|
this.render();
|
|
6871
7895
|
}
|
|
6872
7896
|
ngOnChanges(changes) {
|
|
@@ -6901,6 +7925,12 @@ var FilePreviewComponent = class {
|
|
|
6901
7925
|
getInstance() {
|
|
6902
7926
|
return this.instance;
|
|
6903
7927
|
}
|
|
7928
|
+
getViewer() {
|
|
7929
|
+
return this.viewer;
|
|
7930
|
+
}
|
|
7931
|
+
destroy() {
|
|
7932
|
+
this.viewer?.destroy();
|
|
7933
|
+
}
|
|
6904
7934
|
};
|
|
6905
7935
|
_init = __decoratorStart();
|
|
6906
7936
|
__decorateElement(_init, 5, "src", _src_dec, FilePreviewComponent);
|
|
@@ -6911,6 +7941,8 @@ __decorateElement(_init, 5, "loaded", _loaded_dec, FilePreviewComponent);
|
|
|
6911
7941
|
__decorateElement(_init, 5, "error", _error_dec, FilePreviewComponent);
|
|
6912
7942
|
__decorateElement(_init, 5, "pageChange", _pageChange_dec, FilePreviewComponent);
|
|
6913
7943
|
__decorateElement(_init, 5, "zoomChange", _zoomChange_dec, FilePreviewComponent);
|
|
7944
|
+
__decorateElement(_init, 5, "rotate", _rotate_dec, FilePreviewComponent);
|
|
7945
|
+
__decorateElement(_init, 5, "destroyed", _destroyed_dec, FilePreviewComponent);
|
|
6914
7946
|
__decorateElement(_init, 5, "container", _container_dec, FilePreviewComponent);
|
|
6915
7947
|
FilePreviewComponent = __decorateElement(_init, 0, "FilePreviewComponent", _FilePreviewComponent_decorators, FilePreviewComponent);
|
|
6916
7948
|
__runInitializers(_init, 1, FilePreviewComponent);
|