@files-preview-app/preview-file 1.3.1 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -3
- package/dist/angular.cjs +1552 -520
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.d.cts +6 -1
- package/dist/angular.d.ts +6 -1
- package/dist/angular.js +1552 -520
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +1535 -519
- package/dist/index.cjs.map +1 -1
- package/dist/index.d-B79v0jxi.d.cts +570 -0
- package/dist/index.d-B79v0jxi.d.ts +570 -0
- package/dist/index.d.cts +3227 -19
- package/dist/index.d.ts +3227 -19
- package/dist/index.js +1535 -519
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +1539 -519
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +5 -16
- package/dist/react.d.ts +5 -16
- package/dist/react.js +1539 -519
- package/dist/react.js.map +1 -1
- package/dist/styles.css +195 -14
- package/dist/vue.cjs +1538 -520
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.d.cts +4 -2
- package/dist/vue.d.ts +4 -2
- package/dist/vue.js +1538 -520
- package/dist/vue.js.map +1 -1
- package/package.json +2 -2
package/dist/react.js
CHANGED
|
@@ -495,8 +495,7 @@ var ICON_FULLSCREEN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="non
|
|
|
495
495
|
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>`;
|
|
496
496
|
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>`;
|
|
497
497
|
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>`;
|
|
498
|
-
var
|
|
499
|
-
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>`;
|
|
498
|
+
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>`;
|
|
500
499
|
var ICON_MAP = {
|
|
501
500
|
"zoom-in": ICON_ZOOM_IN,
|
|
502
501
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -523,28 +522,177 @@ var ICON_MAP = {
|
|
|
523
522
|
"forward-10": ICON_FAST_FORWARD,
|
|
524
523
|
"rewind": ICON_REWIND,
|
|
525
524
|
"replay-10": ICON_REWIND,
|
|
526
|
-
"speed": ICON_SPEED,
|
|
527
525
|
"open-window": ICON_EXTERNAL_WINDOW,
|
|
528
|
-
"external-window": ICON_EXTERNAL_WINDOW
|
|
526
|
+
"external-window": ICON_EXTERNAL_WINDOW,
|
|
527
|
+
"openWindow": ICON_EXTERNAL_WINDOW,
|
|
528
|
+
"openSeparateWindow": ICON_EXTERNAL_WINDOW
|
|
529
529
|
};
|
|
530
530
|
var ToolbarController = class {
|
|
531
531
|
el;
|
|
532
532
|
toolbarEl;
|
|
533
533
|
actions = [];
|
|
534
|
+
config = {};
|
|
534
535
|
pageInputEl = null;
|
|
535
536
|
pageLabelEl = null;
|
|
536
|
-
|
|
537
|
+
prevPageBtn = null;
|
|
538
|
+
nextPageBtn = null;
|
|
539
|
+
constructor(container, config) {
|
|
537
540
|
this.el = container;
|
|
541
|
+
if (config) this.config = { ...config };
|
|
538
542
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
539
543
|
this.el.appendChild(this.toolbarEl);
|
|
540
544
|
}
|
|
545
|
+
setConfig(config) {
|
|
546
|
+
this.config = { ...config };
|
|
547
|
+
this.render();
|
|
548
|
+
}
|
|
549
|
+
getConfig() {
|
|
550
|
+
return { ...this.config };
|
|
551
|
+
}
|
|
552
|
+
hideAction(actionId) {
|
|
553
|
+
this.config[actionId] = false;
|
|
554
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = false;
|
|
555
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = false;
|
|
556
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
557
|
+
this.config.fitPage = false;
|
|
558
|
+
this.config.fitToPage = false;
|
|
559
|
+
this.config.fitWidth = false;
|
|
560
|
+
}
|
|
561
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = false;
|
|
562
|
+
if (actionId === "fullscreen") this.config.fullscreen = false;
|
|
563
|
+
if (actionId === "download") this.config.download = false;
|
|
564
|
+
if (actionId === "print") this.config.print = false;
|
|
565
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
566
|
+
this.config.openWindow = false;
|
|
567
|
+
this.config.openSeparateWindow = false;
|
|
568
|
+
}
|
|
569
|
+
if (actionId === "copy") this.config.copy = false;
|
|
570
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
571
|
+
this.config.pageNav = false;
|
|
572
|
+
this.config.pagination = false;
|
|
573
|
+
}
|
|
574
|
+
this.render();
|
|
575
|
+
}
|
|
576
|
+
showAction(actionId) {
|
|
577
|
+
this.config[actionId] = true;
|
|
578
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = true;
|
|
579
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = true;
|
|
580
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
581
|
+
this.config.fitPage = true;
|
|
582
|
+
this.config.fitToPage = true;
|
|
583
|
+
this.config.fitWidth = true;
|
|
584
|
+
}
|
|
585
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = true;
|
|
586
|
+
if (actionId === "fullscreen") this.config.fullscreen = true;
|
|
587
|
+
if (actionId === "download") this.config.download = true;
|
|
588
|
+
if (actionId === "print") this.config.print = true;
|
|
589
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
590
|
+
this.config.openWindow = true;
|
|
591
|
+
this.config.openSeparateWindow = true;
|
|
592
|
+
}
|
|
593
|
+
if (actionId === "copy") this.config.copy = true;
|
|
594
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
595
|
+
this.config.pageNav = true;
|
|
596
|
+
this.config.pagination = true;
|
|
597
|
+
}
|
|
598
|
+
this.render();
|
|
599
|
+
}
|
|
600
|
+
normalizeActionId(actionId) {
|
|
601
|
+
if (actionId === "zoomIn") return "zoom-in";
|
|
602
|
+
if (actionId === "zoomOut") return "zoom-out";
|
|
603
|
+
if (actionId === "fitPage" || actionId === "fitToPage" || actionId === "fitWidth") return "fit-page";
|
|
604
|
+
if (actionId === "rotateCW") return "rotate-cw";
|
|
605
|
+
if (actionId === "rotateCCW") return "rotate-ccw";
|
|
606
|
+
if (actionId === "openWindow" || actionId === "openSeparateWindow") return "open-window";
|
|
607
|
+
if (actionId === "pageNav") return "page-nav";
|
|
608
|
+
return actionId;
|
|
609
|
+
}
|
|
610
|
+
enableAction(actionId) {
|
|
611
|
+
const norm = this.normalizeActionId(actionId);
|
|
612
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
613
|
+
if (btn) {
|
|
614
|
+
btn.disabled = false;
|
|
615
|
+
btn.classList.remove("disabled");
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
disableAction(actionId) {
|
|
619
|
+
const norm = this.normalizeActionId(actionId);
|
|
620
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
621
|
+
if (btn) {
|
|
622
|
+
btn.disabled = true;
|
|
623
|
+
btn.classList.add("disabled");
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
setActionActive(actionId, active) {
|
|
627
|
+
const norm = this.normalizeActionId(actionId);
|
|
628
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
629
|
+
if (btn) {
|
|
630
|
+
if (active) {
|
|
631
|
+
btn.classList.add("active");
|
|
632
|
+
} else {
|
|
633
|
+
btn.classList.remove("active");
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
isActionEnabled(action) {
|
|
638
|
+
const c = this.config;
|
|
639
|
+
const id = action.id;
|
|
640
|
+
if (c[id] === false) return false;
|
|
641
|
+
if (id === "zoom-in" && (c.zoomIn === false || c["zoom-in"] === false)) return false;
|
|
642
|
+
if (id === "zoom-out" && (c.zoomOut === false || c["zoom-out"] === false)) return false;
|
|
643
|
+
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)) {
|
|
644
|
+
return false;
|
|
645
|
+
}
|
|
646
|
+
if ((id === "rotate-cw" || id === "rotate-ccw" || id === "rotate") && (c.rotate === false || c.rotateCW === false || c.rotateCCW === false || c["rotate-cw"] === false)) {
|
|
647
|
+
return false;
|
|
648
|
+
}
|
|
649
|
+
if (id === "fullscreen" && c.fullscreen === false) return false;
|
|
650
|
+
if (id === "download" && c.download === false) return false;
|
|
651
|
+
if (id === "print" && c.print === false) return false;
|
|
652
|
+
if ((id === "open-window" || id === "external-window") && (c.openWindow === false || c.openSeparateWindow === false || c["open-window"] === false)) {
|
|
653
|
+
return false;
|
|
654
|
+
}
|
|
655
|
+
if (id === "copy" && c.copy === false) return false;
|
|
656
|
+
if (id === "thumbnails" && c.thumbnails === false) return false;
|
|
657
|
+
if (id === "page-nav" && (c.pageNav === false || c.pagination === false || c["page-nav"] === false)) {
|
|
658
|
+
return false;
|
|
659
|
+
}
|
|
660
|
+
if ((id === "prev" || id === "page-prev") && (c.prevPage === false || c.prev === false || c["prev"] === false || c.pageNav === false || c.pagination === false)) {
|
|
661
|
+
return false;
|
|
662
|
+
}
|
|
663
|
+
if ((id === "next" || id === "page-next") && (c.nextPage === false || c.next === false || c["next"] === false || c.pageNav === false || c.pagination === false)) {
|
|
664
|
+
return false;
|
|
665
|
+
}
|
|
666
|
+
if (id === "play" && c.play === false) return false;
|
|
667
|
+
if (id === "pause" && c.pause === false) return false;
|
|
668
|
+
if ((id === "fast-forward" || id === "forward-10") && (c.fastForward === false || c["fast-forward"] === false)) {
|
|
669
|
+
return false;
|
|
670
|
+
}
|
|
671
|
+
if ((id === "rewind" || id === "replay-10") && (c.rewind === false || c["rewind"] === false)) {
|
|
672
|
+
return false;
|
|
673
|
+
}
|
|
674
|
+
if (id === "speed" && c.speed === false) return false;
|
|
675
|
+
return true;
|
|
676
|
+
}
|
|
541
677
|
setPage(page, max) {
|
|
542
678
|
if (this.pageInputEl) {
|
|
543
679
|
this.pageInputEl.value = page.toString();
|
|
680
|
+
if (max !== void 0) {
|
|
681
|
+
this.pageInputEl.max = max.toString();
|
|
682
|
+
}
|
|
544
683
|
}
|
|
545
684
|
if (max !== void 0 && this.pageLabelEl) {
|
|
546
685
|
this.pageLabelEl.textContent = ` / ${max}`;
|
|
547
686
|
}
|
|
687
|
+
const currentMax = max !== void 0 ? max : parseInt(this.pageInputEl?.max || "1", 10) || 1;
|
|
688
|
+
if (this.prevPageBtn) {
|
|
689
|
+
this.prevPageBtn.disabled = page <= 1;
|
|
690
|
+
this.prevPageBtn.style.opacity = page <= 1 ? "0.4" : "1";
|
|
691
|
+
}
|
|
692
|
+
if (this.nextPageBtn) {
|
|
693
|
+
this.nextPageBtn.disabled = page >= currentMax;
|
|
694
|
+
this.nextPageBtn.style.opacity = page >= currentMax ? "0.4" : "1";
|
|
695
|
+
}
|
|
548
696
|
}
|
|
549
697
|
update(actions) {
|
|
550
698
|
this.actions = actions;
|
|
@@ -567,8 +715,9 @@ var ToolbarController = class {
|
|
|
567
715
|
view: [],
|
|
568
716
|
actions: []
|
|
569
717
|
};
|
|
570
|
-
const
|
|
571
|
-
const
|
|
718
|
+
const enabledActions = this.actions.filter((a) => this.isActionEnabled(a));
|
|
719
|
+
const hasPageNav = enabledActions.some((a) => a.type === "page-nav");
|
|
720
|
+
const effectiveActions = hasPageNav ? enabledActions.filter((a) => a.id !== "page-prev" && a.id !== "page-next" && a.id !== "prev" && a.id !== "next") : enabledActions;
|
|
572
721
|
for (const action of effectiveActions) {
|
|
573
722
|
if (groups[action.group]) {
|
|
574
723
|
groups[action.group].push(action);
|
|
@@ -628,6 +777,13 @@ var ToolbarController = class {
|
|
|
628
777
|
action.execute("go", val);
|
|
629
778
|
});
|
|
630
779
|
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
780
|
+
const curVal = action.value ?? 1;
|
|
781
|
+
prevBtn.disabled = curVal <= 1;
|
|
782
|
+
prevBtn.style.opacity = curVal <= 1 ? "0.4" : "1";
|
|
783
|
+
nextBtn.disabled = curVal >= max;
|
|
784
|
+
nextBtn.style.opacity = curVal >= max ? "0.4" : "1";
|
|
785
|
+
this.prevPageBtn = prevBtn;
|
|
786
|
+
this.nextPageBtn = nextBtn;
|
|
631
787
|
this.pageInputEl = input;
|
|
632
788
|
this.pageLabelEl = label;
|
|
633
789
|
groupEl.appendChild(prevBtn);
|
|
@@ -683,25 +839,63 @@ var ToolbarController = class {
|
|
|
683
839
|
var ThumbnailPanel = class {
|
|
684
840
|
el;
|
|
685
841
|
panelEl;
|
|
842
|
+
listEl;
|
|
843
|
+
headerEl;
|
|
686
844
|
thumbnails = [];
|
|
687
845
|
onSelect;
|
|
846
|
+
onToggleCallback;
|
|
688
847
|
activeIndex = 0;
|
|
689
|
-
|
|
848
|
+
observer;
|
|
849
|
+
renderedIndices = /* @__PURE__ */ new Set();
|
|
850
|
+
constructor(container, onToggle) {
|
|
690
851
|
this.el = container;
|
|
852
|
+
this.onToggleCallback = onToggle;
|
|
691
853
|
this.panelEl = createElement("div", { className: "fp-thumbnail-panel hidden" });
|
|
854
|
+
this.panelEl.style.width = "0px";
|
|
855
|
+
this.panelEl.style.minWidth = "0px";
|
|
856
|
+
this.panelEl.style.opacity = "0";
|
|
857
|
+
this.headerEl = createElement("div", { className: "fp-thumbnail-header" });
|
|
858
|
+
const title = createElement("span", { className: "fp-thumbnail-title" }, "Pages");
|
|
859
|
+
const closeBtn = createElement("button", {
|
|
860
|
+
className: "fp-thumbnail-close-btn",
|
|
861
|
+
title: "Close Thumbnails",
|
|
862
|
+
type: "button"
|
|
863
|
+
});
|
|
864
|
+
closeBtn.innerHTML = ICON_CLOSE;
|
|
865
|
+
closeBtn.addEventListener("click", (e) => {
|
|
866
|
+
e.stopPropagation();
|
|
867
|
+
this.hide();
|
|
868
|
+
});
|
|
869
|
+
this.headerEl.appendChild(title);
|
|
870
|
+
this.headerEl.appendChild(closeBtn);
|
|
871
|
+
this.listEl = createElement("div", { className: "fp-thumbnail-list" });
|
|
872
|
+
this.panelEl.appendChild(this.headerEl);
|
|
873
|
+
this.panelEl.appendChild(this.listEl);
|
|
692
874
|
this.el.appendChild(this.panelEl);
|
|
693
875
|
}
|
|
876
|
+
isOpen() {
|
|
877
|
+
return !this.panelEl.classList.contains("hidden") && this.panelEl.style.width !== "0px";
|
|
878
|
+
}
|
|
694
879
|
update(thumbnails, onSelect) {
|
|
695
880
|
this.thumbnails = thumbnails;
|
|
696
881
|
this.onSelect = onSelect;
|
|
882
|
+
this.renderedIndices.clear();
|
|
883
|
+
const titleEl = this.headerEl.querySelector(".fp-thumbnail-title");
|
|
884
|
+
if (titleEl) {
|
|
885
|
+
titleEl.textContent = `Pages (${thumbnails.length})`;
|
|
886
|
+
}
|
|
697
887
|
this.render();
|
|
888
|
+
if (this.isOpen()) {
|
|
889
|
+
this.renderAllVisible();
|
|
890
|
+
}
|
|
698
891
|
}
|
|
699
892
|
setActive(index) {
|
|
700
893
|
this.activeIndex = index;
|
|
701
|
-
const items = this.
|
|
894
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
702
895
|
items.forEach((item, i) => {
|
|
703
896
|
if (i === index) {
|
|
704
897
|
item.classList.add("active");
|
|
898
|
+
item.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
705
899
|
} else {
|
|
706
900
|
item.classList.remove("active");
|
|
707
901
|
}
|
|
@@ -709,37 +903,102 @@ var ThumbnailPanel = class {
|
|
|
709
903
|
}
|
|
710
904
|
show() {
|
|
711
905
|
this.panelEl.classList.remove("hidden");
|
|
906
|
+
this.panelEl.style.width = "200px";
|
|
907
|
+
this.panelEl.style.minWidth = "200px";
|
|
908
|
+
this.panelEl.style.opacity = "1";
|
|
909
|
+
this.panelEl.style.display = "flex";
|
|
910
|
+
this.onToggleCallback?.(true);
|
|
911
|
+
this.renderAllVisible();
|
|
712
912
|
}
|
|
713
913
|
hide() {
|
|
714
914
|
this.panelEl.classList.add("hidden");
|
|
915
|
+
this.panelEl.style.width = "0px";
|
|
916
|
+
this.panelEl.style.minWidth = "0px";
|
|
917
|
+
this.panelEl.style.opacity = "0";
|
|
918
|
+
this.onToggleCallback?.(false);
|
|
715
919
|
}
|
|
716
920
|
toggle() {
|
|
717
|
-
this.
|
|
921
|
+
if (this.isOpen()) {
|
|
922
|
+
this.hide();
|
|
923
|
+
} else {
|
|
924
|
+
this.show();
|
|
925
|
+
}
|
|
718
926
|
}
|
|
719
927
|
destroy() {
|
|
928
|
+
if (this.observer) {
|
|
929
|
+
this.observer.disconnect();
|
|
930
|
+
this.observer = void 0;
|
|
931
|
+
}
|
|
932
|
+
this.renderedIndices.clear();
|
|
720
933
|
this.el.innerHTML = "";
|
|
721
934
|
}
|
|
722
|
-
|
|
723
|
-
this.
|
|
935
|
+
renderAllVisible() {
|
|
936
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
937
|
+
items.forEach((item) => {
|
|
938
|
+
const idx = parseInt(item.dataset.thumbIndex || "-1", 10);
|
|
939
|
+
if (idx >= 0 && !this.renderedIndices.has(idx)) {
|
|
940
|
+
this.renderThumbnailItem(idx, item);
|
|
941
|
+
}
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
renderThumbnailItem(idx, itemEl) {
|
|
945
|
+
if (this.renderedIndices.has(idx)) return;
|
|
946
|
+
this.renderedIndices.add(idx);
|
|
947
|
+
const canvas = itemEl.querySelector("canvas");
|
|
948
|
+
const thumb = this.thumbnails[idx];
|
|
949
|
+
if (canvas && thumb) {
|
|
950
|
+
Promise.resolve(thumb.render(canvas)).catch((err) => {
|
|
951
|
+
console.warn(`[FilePreview] Error rendering thumbnail ${idx}:`, err);
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
render() {
|
|
956
|
+
if (this.observer) {
|
|
957
|
+
this.observer.disconnect();
|
|
958
|
+
}
|
|
959
|
+
this.listEl.innerHTML = "";
|
|
960
|
+
const useObserver = typeof IntersectionObserver !== "undefined";
|
|
961
|
+
if (useObserver) {
|
|
962
|
+
this.observer = new IntersectionObserver(
|
|
963
|
+
(entries) => {
|
|
964
|
+
for (const entry of entries) {
|
|
965
|
+
if (entry.isIntersecting) {
|
|
966
|
+
const target = entry.target;
|
|
967
|
+
const idx = parseInt(target.dataset.thumbIndex || "-1", 10);
|
|
968
|
+
if (idx >= 0) {
|
|
969
|
+
this.renderThumbnailItem(idx, target);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
},
|
|
974
|
+
{
|
|
975
|
+
root: this.listEl,
|
|
976
|
+
rootMargin: "120px 0px 120px 0px"
|
|
977
|
+
}
|
|
978
|
+
);
|
|
979
|
+
}
|
|
724
980
|
for (let i = 0; i < this.thumbnails.length; i++) {
|
|
725
981
|
const thumb = this.thumbnails[i];
|
|
726
|
-
const itemEl = createElement("div", {
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
982
|
+
const itemEl = createElement("div", {
|
|
983
|
+
className: "fp-thumbnail-item" + (i === this.activeIndex ? " active" : "")
|
|
984
|
+
});
|
|
985
|
+
itemEl.dataset.thumbIndex = i.toString();
|
|
730
986
|
itemEl.addEventListener("click", () => {
|
|
731
987
|
this.setActive(i);
|
|
732
988
|
this.onSelect?.(i);
|
|
733
989
|
});
|
|
734
|
-
const
|
|
735
|
-
const
|
|
736
|
-
|
|
990
|
+
const canvasWrapper = createElement("div", { className: "fp-thumbnail-canvas-wrapper" });
|
|
991
|
+
const canvas = createElement("canvas", { width: "130", height: "170" });
|
|
992
|
+
canvasWrapper.appendChild(canvas);
|
|
993
|
+
const label = createElement("span", { className: "fp-thumbnail-label" }, thumb.label || `Page ${i + 1}`);
|
|
994
|
+
itemEl.appendChild(canvasWrapper);
|
|
737
995
|
itemEl.appendChild(label);
|
|
738
|
-
this.
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
}
|
|
742
|
-
|
|
996
|
+
this.listEl.appendChild(itemEl);
|
|
997
|
+
if (this.observer) {
|
|
998
|
+
this.observer.observe(itemEl);
|
|
999
|
+
}
|
|
1000
|
+
if (i < 4) {
|
|
1001
|
+
this.renderThumbnailItem(i, itemEl);
|
|
743
1002
|
}
|
|
744
1003
|
}
|
|
745
1004
|
}
|
|
@@ -760,6 +1019,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
760
1019
|
currentOptions = {};
|
|
761
1020
|
resizeObserver = null;
|
|
762
1021
|
fullscreenHandler = null;
|
|
1022
|
+
titleBarEl = null;
|
|
763
1023
|
/**
|
|
764
1024
|
* Register a preview plugin.
|
|
765
1025
|
*/
|
|
@@ -796,6 +1056,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
796
1056
|
}
|
|
797
1057
|
this.currentBuffer = buffer.slice(0);
|
|
798
1058
|
this.currentMetadata = metadata;
|
|
1059
|
+
this.updateTitleBar(options, metadata);
|
|
799
1060
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
800
1061
|
const fileInfo = { metadata, buffer };
|
|
801
1062
|
const matchedPlugin = await this.findPlugin(fileInfo);
|
|
@@ -819,15 +1080,21 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
819
1080
|
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
820
1081
|
const total = payload.total ?? payload.totalPages;
|
|
821
1082
|
this.toolbar?.setPage(payload.page, total);
|
|
1083
|
+
this.thumbnailPanel?.setActive(payload.page - 1);
|
|
822
1084
|
}
|
|
823
1085
|
this.eventEmitter.emit(event, payload);
|
|
824
|
-
}
|
|
1086
|
+
},
|
|
1087
|
+
toggleThumbnails: () => this.toggleThumbnails()
|
|
825
1088
|
});
|
|
826
1089
|
this.activeInstance = instance;
|
|
827
1090
|
instance.openInSeparateWindow = () => this.openInSeparateWindow();
|
|
1091
|
+
instance.toggleThumbnails = () => this.toggleThumbnails();
|
|
828
1092
|
this.hideLoading();
|
|
829
1093
|
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
830
|
-
|
|
1094
|
+
const isToolbarVisible = options.showToolbar !== false && options.toolbar !== false;
|
|
1095
|
+
if (isToolbarVisible && this.toolbar) {
|
|
1096
|
+
const toolbarConfig = this.extractToolbarConfig(options);
|
|
1097
|
+
this.toolbar.setConfig(toolbarConfig);
|
|
831
1098
|
const actions = matchedPlugin.getToolbarActions(instance);
|
|
832
1099
|
const hasFullscreen = actions.some((a) => a.id === "fullscreen");
|
|
833
1100
|
if (!hasFullscreen && this.wrapperEl) {
|
|
@@ -877,6 +1144,12 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
877
1144
|
}
|
|
878
1145
|
});
|
|
879
1146
|
}
|
|
1147
|
+
const thumbAction = actions.find((a) => a.id === "thumbnails");
|
|
1148
|
+
if (thumbAction) {
|
|
1149
|
+
thumbAction.execute = () => {
|
|
1150
|
+
this.toggleThumbnails();
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
880
1153
|
this.toolbar.update(actions);
|
|
881
1154
|
this.toolbar.show();
|
|
882
1155
|
}
|
|
@@ -961,7 +1234,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
961
1234
|
if (targetUrl) {
|
|
962
1235
|
const newWin2 = window.open(targetUrl, "_blank");
|
|
963
1236
|
if (!newWin2) {
|
|
964
|
-
|
|
1237
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
965
1238
|
return null;
|
|
966
1239
|
}
|
|
967
1240
|
return newWin2;
|
|
@@ -969,7 +1242,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
969
1242
|
const title = (this.currentMetadata?.name || "Document Preview") + " - Full Preview";
|
|
970
1243
|
const newWin = window.open("", "_blank");
|
|
971
1244
|
if (!newWin) {
|
|
972
|
-
|
|
1245
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
973
1246
|
return null;
|
|
974
1247
|
}
|
|
975
1248
|
newWin.document.title = title;
|
|
@@ -1046,6 +1319,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1046
1319
|
this.currentBuffer = null;
|
|
1047
1320
|
this.currentMetadata = null;
|
|
1048
1321
|
this.currentContainer = null;
|
|
1322
|
+
this.titleBarEl = null;
|
|
1049
1323
|
}
|
|
1050
1324
|
/**
|
|
1051
1325
|
* Get the currently active preview instance.
|
|
@@ -1053,7 +1327,218 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1053
1327
|
getInstance() {
|
|
1054
1328
|
return this.activeInstance;
|
|
1055
1329
|
}
|
|
1330
|
+
// --- Toolbar Configuration & Feature Toggles ---
|
|
1331
|
+
/**
|
|
1332
|
+
* Configure toolbar features dynamically through options or methods.
|
|
1333
|
+
* e.g. viewer.setToolbarConfig({ zoomIn: false, print: false })
|
|
1334
|
+
*/
|
|
1335
|
+
setToolbarConfig(config) {
|
|
1336
|
+
this.toolbar?.setConfig(config);
|
|
1337
|
+
}
|
|
1338
|
+
/**
|
|
1339
|
+
* Get current toolbar configuration.
|
|
1340
|
+
*/
|
|
1341
|
+
getToolbarConfig() {
|
|
1342
|
+
return this.toolbar?.getConfig() ?? {};
|
|
1343
|
+
}
|
|
1344
|
+
/**
|
|
1345
|
+
* Hide a specific toolbar action by ID or alias (e.g. 'zoom-in', 'print', 'download').
|
|
1346
|
+
*/
|
|
1347
|
+
hideToolbarAction(actionId) {
|
|
1348
|
+
this.toolbar?.hideAction(actionId);
|
|
1349
|
+
}
|
|
1350
|
+
/**
|
|
1351
|
+
* Show a specific toolbar action by ID or alias.
|
|
1352
|
+
*/
|
|
1353
|
+
showToolbarAction(actionId) {
|
|
1354
|
+
this.toolbar?.showAction(actionId);
|
|
1355
|
+
}
|
|
1356
|
+
/**
|
|
1357
|
+
* Enable a specific toolbar action button.
|
|
1358
|
+
*/
|
|
1359
|
+
enableToolbarAction(actionId) {
|
|
1360
|
+
this.toolbar?.enableAction(actionId);
|
|
1361
|
+
}
|
|
1362
|
+
/**
|
|
1363
|
+
* Disable a specific toolbar action button.
|
|
1364
|
+
*/
|
|
1365
|
+
disableToolbarAction(actionId) {
|
|
1366
|
+
this.toolbar?.disableAction(actionId);
|
|
1367
|
+
}
|
|
1368
|
+
// --- Programmatic Toolbar Action Methods ---
|
|
1369
|
+
/**
|
|
1370
|
+
* Fit document to page so it fills the frame width with minimal margins.
|
|
1371
|
+
*/
|
|
1372
|
+
fitToPage() {
|
|
1373
|
+
this.activeInstance?.fitToPage?.();
|
|
1374
|
+
}
|
|
1375
|
+
/**
|
|
1376
|
+
* Zoom in.
|
|
1377
|
+
*/
|
|
1378
|
+
zoomIn() {
|
|
1379
|
+
this.activeInstance?.zoomIn?.();
|
|
1380
|
+
}
|
|
1381
|
+
/**
|
|
1382
|
+
* Zoom out.
|
|
1383
|
+
*/
|
|
1384
|
+
zoomOut() {
|
|
1385
|
+
this.activeInstance?.zoomOut?.();
|
|
1386
|
+
}
|
|
1387
|
+
/**
|
|
1388
|
+
* Set specific zoom level.
|
|
1389
|
+
*/
|
|
1390
|
+
setZoom(level) {
|
|
1391
|
+
this.activeInstance?.setZoom?.(level);
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* Get current zoom level.
|
|
1395
|
+
*/
|
|
1396
|
+
getZoom() {
|
|
1397
|
+
return this.activeInstance?.getZoom?.() ?? 1;
|
|
1398
|
+
}
|
|
1399
|
+
/**
|
|
1400
|
+
* Rotate 90 degrees clockwise.
|
|
1401
|
+
*/
|
|
1402
|
+
rotateCW() {
|
|
1403
|
+
this.activeInstance?.rotateCW?.();
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* Rotate 90 degrees counter-clockwise.
|
|
1407
|
+
*/
|
|
1408
|
+
rotateCCW() {
|
|
1409
|
+
this.activeInstance?.rotateCCW?.();
|
|
1410
|
+
}
|
|
1411
|
+
/**
|
|
1412
|
+
* Navigate to a specific page number.
|
|
1413
|
+
*/
|
|
1414
|
+
goToPage(page) {
|
|
1415
|
+
this.activeInstance?.goToPage?.(page);
|
|
1416
|
+
this.toolbar?.setPage(page);
|
|
1417
|
+
}
|
|
1418
|
+
/**
|
|
1419
|
+
* Navigate to next page.
|
|
1420
|
+
*/
|
|
1421
|
+
nextPage() {
|
|
1422
|
+
const cur = this.getCurrentPage();
|
|
1423
|
+
const max = this.getPageCount();
|
|
1424
|
+
if (cur < max) {
|
|
1425
|
+
this.goToPage(cur + 1);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
/**
|
|
1429
|
+
* Navigate to previous page.
|
|
1430
|
+
*/
|
|
1431
|
+
prevPage() {
|
|
1432
|
+
const cur = this.getCurrentPage();
|
|
1433
|
+
if (cur > 1) {
|
|
1434
|
+
this.goToPage(cur - 1);
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
/**
|
|
1438
|
+
* Get total page count.
|
|
1439
|
+
*/
|
|
1440
|
+
getPageCount() {
|
|
1441
|
+
return this.activeInstance?.getPageCount?.() ?? 1;
|
|
1442
|
+
}
|
|
1443
|
+
/**
|
|
1444
|
+
* Get current page number.
|
|
1445
|
+
*/
|
|
1446
|
+
getCurrentPage() {
|
|
1447
|
+
return this.activeInstance?.getCurrentPage?.() ?? 1;
|
|
1448
|
+
}
|
|
1449
|
+
/**
|
|
1450
|
+
* Download the current document.
|
|
1451
|
+
*/
|
|
1452
|
+
download() {
|
|
1453
|
+
this.activeInstance?.download?.();
|
|
1454
|
+
}
|
|
1455
|
+
/**
|
|
1456
|
+
* Print the current document.
|
|
1457
|
+
*/
|
|
1458
|
+
print() {
|
|
1459
|
+
this.activeInstance?.print?.();
|
|
1460
|
+
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Toggle fullscreen mode.
|
|
1463
|
+
*/
|
|
1464
|
+
toggleFullscreen() {
|
|
1465
|
+
try {
|
|
1466
|
+
if (!document.fullscreenElement) {
|
|
1467
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
1468
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
1469
|
+
} else {
|
|
1470
|
+
document.exitFullscreen?.();
|
|
1471
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
1472
|
+
}
|
|
1473
|
+
} catch {
|
|
1474
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
1475
|
+
}
|
|
1476
|
+
setTimeout(() => {
|
|
1477
|
+
this.activeInstance?.fitToPage?.();
|
|
1478
|
+
}, 120);
|
|
1479
|
+
}
|
|
1480
|
+
/**
|
|
1481
|
+
* Toggle thumbnails sidebar panel.
|
|
1482
|
+
*/
|
|
1483
|
+
toggleThumbnails() {
|
|
1484
|
+
if (!this.thumbnailPanel) return;
|
|
1485
|
+
this.thumbnailPanel.toggle();
|
|
1486
|
+
const isOpen = this.thumbnailPanel.isOpen();
|
|
1487
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1488
|
+
setTimeout(() => {
|
|
1489
|
+
this.activeInstance?.fitToPage?.();
|
|
1490
|
+
}, 260);
|
|
1491
|
+
}
|
|
1492
|
+
/**
|
|
1493
|
+
* Set whether to display the file name / title bar above the toolbar.
|
|
1494
|
+
*/
|
|
1495
|
+
setShowFileName(show) {
|
|
1496
|
+
if (this.currentOptions) {
|
|
1497
|
+
this.currentOptions.showFileName = show;
|
|
1498
|
+
}
|
|
1499
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* Set or override the displayed file name in the preview panel.
|
|
1503
|
+
*/
|
|
1504
|
+
setFileName(name) {
|
|
1505
|
+
if (this.currentOptions) {
|
|
1506
|
+
this.currentOptions.fileName = name;
|
|
1507
|
+
}
|
|
1508
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1509
|
+
}
|
|
1056
1510
|
// --- Private methods ---
|
|
1511
|
+
updateTitleBar(options, metadata) {
|
|
1512
|
+
if (!this.titleBarEl) return;
|
|
1513
|
+
const show = options?.showFileName !== false;
|
|
1514
|
+
if (!show) {
|
|
1515
|
+
this.titleBarEl.style.display = "none";
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
const name = options?.fileName || metadata?.name || this.currentMetadata?.name || "";
|
|
1519
|
+
if (!name) {
|
|
1520
|
+
this.titleBarEl.style.display = "none";
|
|
1521
|
+
return;
|
|
1522
|
+
}
|
|
1523
|
+
this.titleBarEl.style.display = "flex";
|
|
1524
|
+
const ext = metadata?.extension || (name.includes(".") ? "." + name.split(".").pop() : "");
|
|
1525
|
+
const badge = ext ? ext.replace(".", "").toUpperCase() : "";
|
|
1526
|
+
this.titleBarEl.innerHTML = `
|
|
1527
|
+
<div class="fp-titlebar-info">
|
|
1528
|
+
<span class="fp-titlebar-icon">\u{1F4C4}</span>
|
|
1529
|
+
<span class="fp-titlebar-name" title="${name}">${name}</span>
|
|
1530
|
+
${badge ? `<span class="fp-titlebar-badge">${badge}</span>` : ""}
|
|
1531
|
+
</div>
|
|
1532
|
+
`;
|
|
1533
|
+
}
|
|
1534
|
+
extractToolbarConfig(options) {
|
|
1535
|
+
if (!options) return {};
|
|
1536
|
+
const nested = typeof options.toolbar === "object" ? options.toolbar : {};
|
|
1537
|
+
return {
|
|
1538
|
+
...options,
|
|
1539
|
+
...nested
|
|
1540
|
+
};
|
|
1541
|
+
}
|
|
1057
1542
|
abort() {
|
|
1058
1543
|
if (this.abortController) {
|
|
1059
1544
|
this.abortController.abort();
|
|
@@ -1096,17 +1581,29 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1096
1581
|
bodyEl.className = "fp-body";
|
|
1097
1582
|
bodyEl.appendChild(thumbnailEl);
|
|
1098
1583
|
bodyEl.appendChild(this.contentEl);
|
|
1584
|
+
const titleBarEl = document.createElement("div");
|
|
1585
|
+
titleBarEl.className = "fp-titlebar";
|
|
1586
|
+
this.titleBarEl = titleBarEl;
|
|
1587
|
+
this.updateTitleBar(options, this.currentMetadata);
|
|
1099
1588
|
if (toolbarPos === "top") {
|
|
1589
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1100
1590
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1101
1591
|
this.wrapperEl.appendChild(bodyEl);
|
|
1102
1592
|
} else {
|
|
1593
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1103
1594
|
this.wrapperEl.appendChild(bodyEl);
|
|
1104
1595
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1105
1596
|
}
|
|
1106
1597
|
container.innerHTML = "";
|
|
1107
1598
|
container.appendChild(this.wrapperEl);
|
|
1108
|
-
|
|
1109
|
-
this.
|
|
1599
|
+
const initialToolbarConfig = this.extractToolbarConfig(options);
|
|
1600
|
+
this.toolbar = new ToolbarController(toolbarEl, initialToolbarConfig);
|
|
1601
|
+
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl, (isOpen) => {
|
|
1602
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1603
|
+
setTimeout(() => {
|
|
1604
|
+
this.activeInstance?.fitToPage?.();
|
|
1605
|
+
}, 260);
|
|
1606
|
+
});
|
|
1110
1607
|
this.setupKeyboardShortcuts();
|
|
1111
1608
|
this.setupDragAndDrop(container, options);
|
|
1112
1609
|
this.setupResizeAndFullscreenListeners();
|
|
@@ -1496,6 +1993,14 @@ var PdfPlugin = class {
|
|
|
1496
1993
|
group: "zoom",
|
|
1497
1994
|
execute: () => instance.fitToPage?.()
|
|
1498
1995
|
},
|
|
1996
|
+
{
|
|
1997
|
+
id: "fit-width",
|
|
1998
|
+
icon: "fit-width",
|
|
1999
|
+
label: "Fit to Width",
|
|
2000
|
+
type: "button",
|
|
2001
|
+
group: "zoom",
|
|
2002
|
+
execute: () => instance.fitToWidth?.()
|
|
2003
|
+
},
|
|
1499
2004
|
{
|
|
1500
2005
|
id: "rotate-cw",
|
|
1501
2006
|
icon: "rotate-cw",
|
|
@@ -1504,6 +2009,14 @@ var PdfPlugin = class {
|
|
|
1504
2009
|
group: "view",
|
|
1505
2010
|
execute: () => instance.rotateCW?.()
|
|
1506
2011
|
},
|
|
2012
|
+
{
|
|
2013
|
+
id: "rotate-ccw",
|
|
2014
|
+
icon: "rotate-ccw",
|
|
2015
|
+
label: "Rotate Counter-Clockwise",
|
|
2016
|
+
type: "button",
|
|
2017
|
+
group: "view",
|
|
2018
|
+
execute: () => instance.rotateCCW?.()
|
|
2019
|
+
},
|
|
1507
2020
|
{
|
|
1508
2021
|
id: "download",
|
|
1509
2022
|
icon: "download",
|
|
@@ -1535,12 +2048,13 @@ var PdfPlugin = class {
|
|
|
1535
2048
|
container.className = "fp-pdf-container";
|
|
1536
2049
|
container.style.width = "100%";
|
|
1537
2050
|
container.style.height = "100%";
|
|
1538
|
-
container.style.
|
|
2051
|
+
container.style.overflowX = "hidden";
|
|
2052
|
+
container.style.overflowY = "auto";
|
|
1539
2053
|
container.style.display = "flex";
|
|
1540
2054
|
container.style.flexDirection = "column";
|
|
1541
2055
|
container.style.alignItems = "center";
|
|
1542
2056
|
container.style.justifyContent = "flex-start";
|
|
1543
|
-
container.style.padding = "
|
|
2057
|
+
container.style.padding = "16px 8px";
|
|
1544
2058
|
container.style.backgroundColor = "#0f172a";
|
|
1545
2059
|
container.style.boxSizing = "border-box";
|
|
1546
2060
|
container.style.position = "relative";
|
|
@@ -1551,30 +2065,12 @@ var PdfPlugin = class {
|
|
|
1551
2065
|
pageCard.style.borderRadius = "4px";
|
|
1552
2066
|
pageCard.style.overflow = "hidden";
|
|
1553
2067
|
pageCard.style.lineHeight = "0";
|
|
1554
|
-
pageCard.style.transition = "transform 0.15s ease";
|
|
1555
2068
|
pageCard.style.position = "relative";
|
|
1556
2069
|
pageCard.style.flexShrink = "0";
|
|
2070
|
+
pageCard.style.transition = "box-shadow 0.2s ease";
|
|
1557
2071
|
let canvas = document.createElement("canvas");
|
|
1558
2072
|
pageCard.appendChild(canvas);
|
|
1559
2073
|
container.appendChild(pageCard);
|
|
1560
|
-
const indicator = document.createElement("div");
|
|
1561
|
-
indicator.className = "fp-pdf-page-indicator";
|
|
1562
|
-
indicator.style.position = "sticky";
|
|
1563
|
-
indicator.style.bottom = "16px";
|
|
1564
|
-
indicator.style.marginTop = "16px";
|
|
1565
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1566
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
1567
|
-
indicator.style.color = "#f8fafc";
|
|
1568
|
-
indicator.style.fontSize = "12px";
|
|
1569
|
-
indicator.style.fontWeight = "600";
|
|
1570
|
-
indicator.style.padding = "5px 14px";
|
|
1571
|
-
indicator.style.borderRadius = "20px";
|
|
1572
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1573
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1574
|
-
indicator.style.zIndex = "10";
|
|
1575
|
-
indicator.style.userSelect = "none";
|
|
1576
|
-
indicator.style.pointerEvents = "none";
|
|
1577
|
-
container.appendChild(indicator);
|
|
1578
2074
|
ctx.container.appendChild(container);
|
|
1579
2075
|
const standardFontsUrl = typeof window !== "undefined" && window.__PDF_STANDARD_FONTS_URL__ || "./standard_fonts/";
|
|
1580
2076
|
const cmapsUrl = typeof window !== "undefined" && window.__PDF_CMAPS_URL__ || "./cmaps/";
|
|
@@ -1590,8 +2086,9 @@ var PdfPlugin = class {
|
|
|
1590
2086
|
let currentPage = 1;
|
|
1591
2087
|
let zoomScale = 1;
|
|
1592
2088
|
let rotation = 0;
|
|
1593
|
-
let fitMode = "
|
|
2089
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
1594
2090
|
let currentRenderTask = null;
|
|
2091
|
+
let textLayerDiv = null;
|
|
1595
2092
|
const renderPage = async (pageNum) => {
|
|
1596
2093
|
if (currentRenderTask) {
|
|
1597
2094
|
try {
|
|
@@ -1603,30 +2100,37 @@ var PdfPlugin = class {
|
|
|
1603
2100
|
const newCanvas = document.createElement("canvas");
|
|
1604
2101
|
pageCard.replaceChild(newCanvas, canvas);
|
|
1605
2102
|
canvas = newCanvas;
|
|
2103
|
+
if (textLayerDiv) {
|
|
2104
|
+
textLayerDiv.remove();
|
|
2105
|
+
textLayerDiv = null;
|
|
2106
|
+
}
|
|
1606
2107
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1607
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1608
2108
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1609
2109
|
const page = await pdfDoc.getPage(currentPage);
|
|
1610
2110
|
const containerWidth = container.clientWidth || 900;
|
|
1611
2111
|
const containerHeight = container.clientHeight || 700;
|
|
1612
2112
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1613
|
-
const availWidth = Math.max(
|
|
1614
|
-
const availHeight = Math.max(
|
|
2113
|
+
const availWidth = Math.max(280, containerWidth - 36);
|
|
2114
|
+
const availHeight = Math.max(280, containerHeight - 32);
|
|
1615
2115
|
const scaleW = availWidth / unscaledVp.width;
|
|
1616
2116
|
const scaleH = availHeight / unscaledVp.height;
|
|
1617
2117
|
let fitScale;
|
|
1618
2118
|
if (fitMode === "page") {
|
|
1619
|
-
fitScale = Math.max(0.4, Math.min(scaleW, scaleH));
|
|
2119
|
+
fitScale = Math.max(0.2, Math.min(4, Math.min(scaleW, scaleH)));
|
|
1620
2120
|
} else {
|
|
1621
|
-
fitScale = Math.max(0.
|
|
2121
|
+
fitScale = Math.max(0.2, Math.min(4, scaleW));
|
|
1622
2122
|
}
|
|
1623
2123
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1624
2124
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1625
2125
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
2126
|
+
const displayWidth = Math.floor(viewport.width);
|
|
2127
|
+
const displayHeight = Math.floor(viewport.height);
|
|
1626
2128
|
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1627
2129
|
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1628
|
-
canvas.style.width = `${
|
|
1629
|
-
canvas.style.height = `${
|
|
2130
|
+
canvas.style.width = `${displayWidth}px`;
|
|
2131
|
+
canvas.style.height = `${displayHeight}px`;
|
|
2132
|
+
pageCard.style.width = `${displayWidth}px`;
|
|
2133
|
+
pageCard.style.height = `${displayHeight}px`;
|
|
1630
2134
|
const canvasCtx = canvas.getContext("2d");
|
|
1631
2135
|
if (!canvasCtx) return;
|
|
1632
2136
|
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
@@ -1640,9 +2144,31 @@ var PdfPlugin = class {
|
|
|
1640
2144
|
if (err?.name !== "RenderingCancelledException") {
|
|
1641
2145
|
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1642
2146
|
}
|
|
2147
|
+
return;
|
|
1643
2148
|
} finally {
|
|
1644
2149
|
currentRenderTask = null;
|
|
1645
2150
|
}
|
|
2151
|
+
try {
|
|
2152
|
+
textLayerDiv = document.createElement("div");
|
|
2153
|
+
textLayerDiv.className = "textLayer";
|
|
2154
|
+
textLayerDiv.style.width = `${displayWidth}px`;
|
|
2155
|
+
textLayerDiv.style.height = `${displayHeight}px`;
|
|
2156
|
+
textLayerDiv.style.position = "absolute";
|
|
2157
|
+
textLayerDiv.style.top = "0";
|
|
2158
|
+
textLayerDiv.style.left = "0";
|
|
2159
|
+
textLayerDiv.style.lineHeight = "1";
|
|
2160
|
+
pageCard.appendChild(textLayerDiv);
|
|
2161
|
+
if (pdfjsLib.TextLayer) {
|
|
2162
|
+
const textLayer = new pdfjsLib.TextLayer({
|
|
2163
|
+
textContentSource: page.streamTextContent(),
|
|
2164
|
+
container: textLayerDiv,
|
|
2165
|
+
viewport
|
|
2166
|
+
});
|
|
2167
|
+
await textLayer.render();
|
|
2168
|
+
}
|
|
2169
|
+
} catch (err) {
|
|
2170
|
+
console.debug("[PdfPlugin] TextLayer notice:", err);
|
|
2171
|
+
}
|
|
1646
2172
|
};
|
|
1647
2173
|
renderPage(1);
|
|
1648
2174
|
let resizeTimer = null;
|
|
@@ -1652,11 +2178,48 @@ var PdfPlugin = class {
|
|
|
1652
2178
|
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1653
2179
|
renderPage(currentPage);
|
|
1654
2180
|
}
|
|
1655
|
-
},
|
|
2181
|
+
}, 120);
|
|
1656
2182
|
});
|
|
1657
2183
|
resizeObserver.observe(container);
|
|
2184
|
+
const onWheel = (e) => {
|
|
2185
|
+
if (e.ctrlKey || e.metaKey) {
|
|
2186
|
+
e.preventDefault();
|
|
2187
|
+
const delta = e.deltaY > 0 ? -0.15 : 0.15;
|
|
2188
|
+
zoomScale = Math.max(0.25, Math.min(4, Math.round((zoomScale + delta) * 100) / 100));
|
|
2189
|
+
renderPage(currentPage);
|
|
2190
|
+
}
|
|
2191
|
+
};
|
|
2192
|
+
container.addEventListener("wheel", onWheel, { passive: false });
|
|
2193
|
+
const onKeyDown = (e) => {
|
|
2194
|
+
const tag = e.target?.tagName?.toLowerCase();
|
|
2195
|
+
if (tag === "input" || tag === "textarea" || tag === "select") return;
|
|
2196
|
+
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
2197
|
+
if (currentPage < totalPages) {
|
|
2198
|
+
e.preventDefault();
|
|
2199
|
+
container.scrollTop = 0;
|
|
2200
|
+
renderPage(currentPage + 1);
|
|
2201
|
+
}
|
|
2202
|
+
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
2203
|
+
if (currentPage > 1) {
|
|
2204
|
+
e.preventDefault();
|
|
2205
|
+
container.scrollTop = 0;
|
|
2206
|
+
renderPage(currentPage - 1);
|
|
2207
|
+
}
|
|
2208
|
+
} else if (e.key === "Home") {
|
|
2209
|
+
e.preventDefault();
|
|
2210
|
+
container.scrollTop = 0;
|
|
2211
|
+
renderPage(1);
|
|
2212
|
+
} else if (e.key === "End") {
|
|
2213
|
+
e.preventDefault();
|
|
2214
|
+
container.scrollTop = 0;
|
|
2215
|
+
renderPage(totalPages);
|
|
2216
|
+
}
|
|
2217
|
+
};
|
|
2218
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1658
2219
|
const cleanup = () => {
|
|
1659
2220
|
resizeObserver.disconnect();
|
|
2221
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
2222
|
+
container.removeEventListener("wheel", onWheel);
|
|
1660
2223
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1661
2224
|
if (currentRenderTask) {
|
|
1662
2225
|
try {
|
|
@@ -1675,22 +2238,26 @@ var PdfPlugin = class {
|
|
|
1675
2238
|
const instance = {
|
|
1676
2239
|
destroy: cleanup,
|
|
1677
2240
|
zoomIn: () => {
|
|
1678
|
-
zoomScale = Math.min(
|
|
2241
|
+
zoomScale = Math.min(4, Math.round((zoomScale + 0.2) * 10) / 10);
|
|
1679
2242
|
renderPage(currentPage);
|
|
1680
2243
|
},
|
|
1681
2244
|
zoomOut: () => {
|
|
1682
|
-
zoomScale = Math.max(0.
|
|
2245
|
+
zoomScale = Math.max(0.25, Math.round((zoomScale - 0.2) * 10) / 10);
|
|
1683
2246
|
renderPage(currentPage);
|
|
1684
2247
|
},
|
|
1685
2248
|
getZoom: () => zoomScale,
|
|
1686
2249
|
setZoom: (level) => {
|
|
1687
|
-
zoomScale = Math.max(0.
|
|
2250
|
+
zoomScale = Math.max(0.25, Math.min(4, level));
|
|
1688
2251
|
renderPage(currentPage);
|
|
1689
2252
|
},
|
|
1690
2253
|
fitToPage: () => {
|
|
1691
|
-
fitMode =
|
|
2254
|
+
fitMode = "page";
|
|
2255
|
+
zoomScale = 1;
|
|
2256
|
+
renderPage(currentPage);
|
|
2257
|
+
},
|
|
2258
|
+
fitToWidth: () => {
|
|
2259
|
+
fitMode = "width";
|
|
1692
2260
|
zoomScale = 1;
|
|
1693
|
-
rotation = 0;
|
|
1694
2261
|
renderPage(currentPage);
|
|
1695
2262
|
},
|
|
1696
2263
|
rotateCW: () => {
|
|
@@ -1708,6 +2275,9 @@ var PdfPlugin = class {
|
|
|
1708
2275
|
container.scrollTop = 0;
|
|
1709
2276
|
renderPage(page);
|
|
1710
2277
|
},
|
|
2278
|
+
toggleThumbnails: () => {
|
|
2279
|
+
ctx?.toggleThumbnails?.();
|
|
2280
|
+
},
|
|
1711
2281
|
download: () => {
|
|
1712
2282
|
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1713
2283
|
const url = URL.createObjectURL(blob);
|
|
@@ -1741,7 +2311,7 @@ var PdfPlugin = class {
|
|
|
1741
2311
|
},
|
|
1742
2312
|
getThumbnails: async () => {
|
|
1743
2313
|
const thumbnails = [];
|
|
1744
|
-
const count =
|
|
2314
|
+
const count = totalPages;
|
|
1745
2315
|
for (let i = 1; i <= count; i++) {
|
|
1746
2316
|
thumbnails.push({
|
|
1747
2317
|
index: i,
|
|
@@ -1749,9 +2319,10 @@ var PdfPlugin = class {
|
|
|
1749
2319
|
render: async (thumbCanvas) => {
|
|
1750
2320
|
try {
|
|
1751
2321
|
const p = await pdfDoc.getPage(i);
|
|
1752
|
-
const baseVp = p.getViewport({ scale: 1 });
|
|
1753
|
-
const
|
|
1754
|
-
const
|
|
2322
|
+
const baseVp = p.getViewport({ scale: 1, rotation });
|
|
2323
|
+
const targetW = thumbCanvas.width || 130;
|
|
2324
|
+
const thumbScale = targetW / baseVp.width;
|
|
2325
|
+
const thumbVp = p.getViewport({ scale: thumbScale, rotation });
|
|
1755
2326
|
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1756
2327
|
const tCtx = thumbCanvas.getContext("2d");
|
|
1757
2328
|
if (tCtx) {
|
|
@@ -2095,28 +2666,26 @@ var DocxPlugin = class {
|
|
|
2095
2666
|
getToolbarActions(instance) {
|
|
2096
2667
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2097
2668
|
const actions = [];
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
if (
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
instance.goToPage?.(page);
|
|
2116
|
-
}
|
|
2669
|
+
actions.push({
|
|
2670
|
+
id: "page-nav",
|
|
2671
|
+
icon: "",
|
|
2672
|
+
label: "Page Navigation",
|
|
2673
|
+
type: "page-nav",
|
|
2674
|
+
group: "navigation",
|
|
2675
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2676
|
+
max: totalPages,
|
|
2677
|
+
execute: (action, page) => {
|
|
2678
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2679
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2680
|
+
if (action === "prev") {
|
|
2681
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2682
|
+
} else if (action === "next") {
|
|
2683
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2684
|
+
} else if (typeof page === "number") {
|
|
2685
|
+
instance.goToPage?.(page);
|
|
2117
2686
|
}
|
|
2118
|
-
}
|
|
2119
|
-
}
|
|
2687
|
+
}
|
|
2688
|
+
});
|
|
2120
2689
|
actions.push(
|
|
2121
2690
|
{
|
|
2122
2691
|
id: "zoom-out",
|
|
@@ -2182,11 +2751,17 @@ var DocxPlugin = class {
|
|
|
2182
2751
|
wrapper.className = "fp-docx-wrapper";
|
|
2183
2752
|
wrapper.style.transformOrigin = "top center";
|
|
2184
2753
|
wrapper.style.transition = "transform 0.2s ease";
|
|
2185
|
-
wrapper.style.padding = "
|
|
2186
|
-
wrapper.style.maxWidth = "
|
|
2754
|
+
wrapper.style.padding = "0";
|
|
2755
|
+
wrapper.style.maxWidth = "none";
|
|
2756
|
+
wrapper.style.width = "816px";
|
|
2187
2757
|
wrapper.style.margin = "0 auto";
|
|
2758
|
+
wrapper.style.display = "flex";
|
|
2759
|
+
wrapper.style.flexDirection = "column";
|
|
2760
|
+
wrapper.style.alignItems = "center";
|
|
2188
2761
|
wrapper.style.boxSizing = "border-box";
|
|
2189
|
-
ctx.container.style.
|
|
2762
|
+
ctx.container.style.overflowX = "hidden";
|
|
2763
|
+
ctx.container.style.overflowY = "auto";
|
|
2764
|
+
ctx.container.style.padding = "16px 8px";
|
|
2190
2765
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
2191
2766
|
ctx.container.appendChild(wrapper);
|
|
2192
2767
|
const styleOverride = document.createElement("style");
|
|
@@ -2360,39 +2935,13 @@ var DocxPlugin = class {
|
|
|
2360
2935
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2361
2936
|
const totalPages = Math.max(1, pageElements.length);
|
|
2362
2937
|
let currentPage = 1;
|
|
2363
|
-
let indicator = null;
|
|
2364
|
-
if (totalPages > 1) {
|
|
2365
|
-
indicator = document.createElement("div");
|
|
2366
|
-
indicator.className = "fp-docx-page-indicator";
|
|
2367
|
-
indicator.style.position = "sticky";
|
|
2368
|
-
indicator.style.bottom = "16px";
|
|
2369
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2370
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
2371
|
-
indicator.style.color = "#f8fafc";
|
|
2372
|
-
indicator.style.fontSize = "12px";
|
|
2373
|
-
indicator.style.fontWeight = "600";
|
|
2374
|
-
indicator.style.padding = "5px 14px";
|
|
2375
|
-
indicator.style.borderRadius = "20px";
|
|
2376
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2377
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2378
|
-
indicator.style.zIndex = "10";
|
|
2379
|
-
indicator.style.userSelect = "none";
|
|
2380
|
-
indicator.style.pointerEvents = "none";
|
|
2381
|
-
indicator.style.textAlign = "center";
|
|
2382
|
-
indicator.style.width = "fit-content";
|
|
2383
|
-
indicator.style.margin = "16px auto 0";
|
|
2384
|
-
ctx.container.appendChild(indicator);
|
|
2385
|
-
}
|
|
2386
2938
|
const showPage = (pageNum) => {
|
|
2387
2939
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2388
2940
|
if (pageElements.length > 1) {
|
|
2389
2941
|
pageElements.forEach((sec, idx) => {
|
|
2390
|
-
sec.style.display = idx + 1 === currentPage ? "
|
|
2942
|
+
sec.style.display = idx + 1 === currentPage ? "" : "none";
|
|
2391
2943
|
});
|
|
2392
2944
|
}
|
|
2393
|
-
if (indicator) {
|
|
2394
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2395
|
-
}
|
|
2396
2945
|
ctx.container.scrollTop = 0;
|
|
2397
2946
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2398
2947
|
};
|
|
@@ -2401,31 +2950,46 @@ var DocxPlugin = class {
|
|
|
2401
2950
|
}
|
|
2402
2951
|
scale = 1;
|
|
2403
2952
|
let rotation = 0;
|
|
2404
|
-
let fitMode = "
|
|
2405
|
-
|
|
2406
|
-
|
|
2953
|
+
let fitMode = "page";
|
|
2954
|
+
let isUserZoomed = false;
|
|
2955
|
+
const calculateFitScale = (_mode = fitMode) => {
|
|
2956
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
2407
2957
|
const elW = activeEl.offsetWidth || 816;
|
|
2408
|
-
const
|
|
2409
|
-
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
2410
|
-
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
2958
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
2411
2959
|
const sW = availW / elW;
|
|
2412
|
-
|
|
2413
|
-
if (mode === "page") {
|
|
2414
|
-
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
2415
|
-
}
|
|
2416
|
-
return Math.max(0.65, Math.min(1.05, sW));
|
|
2960
|
+
return Math.max(0.35, Math.min(3, sW));
|
|
2417
2961
|
};
|
|
2418
2962
|
const applyTransform = () => {
|
|
2419
2963
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2420
2964
|
wrapper.style.transformOrigin = "top center";
|
|
2965
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
2966
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
2967
|
+
if (scale > 1) {
|
|
2968
|
+
wrapper.style.marginBottom = `${Math.round(elH * scale - elH + 32)}px`;
|
|
2969
|
+
} else {
|
|
2970
|
+
wrapper.style.marginBottom = "32px";
|
|
2971
|
+
}
|
|
2421
2972
|
};
|
|
2973
|
+
let resizeObserver = null;
|
|
2974
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
2975
|
+
resizeObserver = new ResizeObserver(() => {
|
|
2976
|
+
if (!isUserZoomed) {
|
|
2977
|
+
const newFit = calculateFitScale("page");
|
|
2978
|
+
if (Math.abs(scale - newFit) > 0.015) {
|
|
2979
|
+
scale = newFit;
|
|
2980
|
+
applyTransform();
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
});
|
|
2984
|
+
resizeObserver.observe(ctx.container);
|
|
2985
|
+
}
|
|
2422
2986
|
setTimeout(() => {
|
|
2423
|
-
|
|
2424
|
-
scale = calculateFitScale("width");
|
|
2987
|
+
scale = calculateFitScale("page");
|
|
2425
2988
|
applyTransform();
|
|
2426
|
-
},
|
|
2989
|
+
}, 40);
|
|
2427
2990
|
const cleanup = () => {
|
|
2428
|
-
|
|
2991
|
+
resizeObserver?.disconnect();
|
|
2992
|
+
resizeObserver = null;
|
|
2429
2993
|
for (const url of createdBlobUrls) {
|
|
2430
2994
|
URL.revokeObjectURL(url);
|
|
2431
2995
|
}
|
|
@@ -2442,21 +3006,24 @@ var DocxPlugin = class {
|
|
|
2442
3006
|
showPage(page);
|
|
2443
3007
|
},
|
|
2444
3008
|
zoomIn: () => {
|
|
2445
|
-
|
|
3009
|
+
isUserZoomed = true;
|
|
3010
|
+
scale = Math.min(3.5, scale + 0.15);
|
|
2446
3011
|
applyTransform();
|
|
2447
3012
|
},
|
|
2448
3013
|
zoomOut: () => {
|
|
3014
|
+
isUserZoomed = true;
|
|
2449
3015
|
scale = Math.max(0.2, scale - 0.15);
|
|
2450
3016
|
applyTransform();
|
|
2451
3017
|
},
|
|
2452
3018
|
getZoom: () => scale,
|
|
2453
3019
|
setZoom: (level) => {
|
|
3020
|
+
isUserZoomed = true;
|
|
2454
3021
|
scale = level;
|
|
2455
3022
|
applyTransform();
|
|
2456
3023
|
},
|
|
2457
3024
|
fitToPage: () => {
|
|
2458
|
-
|
|
2459
|
-
scale = calculateFitScale(
|
|
3025
|
+
isUserZoomed = false;
|
|
3026
|
+
scale = calculateFitScale("page");
|
|
2460
3027
|
rotation = 0;
|
|
2461
3028
|
applyTransform();
|
|
2462
3029
|
},
|
|
@@ -2846,7 +3413,7 @@ var ExcelPlugin = class {
|
|
|
2846
3413
|
"application/vnd.ms-excel.template.macroEnabled.12",
|
|
2847
3414
|
"application/vnd.oasis.opendocument.spreadsheet"
|
|
2848
3415
|
];
|
|
2849
|
-
weight =
|
|
3416
|
+
weight = 85;
|
|
2850
3417
|
supports(file) {
|
|
2851
3418
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2852
3419
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
@@ -2858,6 +3425,14 @@ var ExcelPlugin = class {
|
|
|
2858
3425
|
getToolbarActions(instance) {
|
|
2859
3426
|
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2860
3427
|
const actions = [];
|
|
3428
|
+
actions.push({
|
|
3429
|
+
id: "thumbnails",
|
|
3430
|
+
icon: "thumbnails",
|
|
3431
|
+
label: "Sheet Thumbnails",
|
|
3432
|
+
type: "button",
|
|
3433
|
+
group: "navigation",
|
|
3434
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3435
|
+
});
|
|
2861
3436
|
if (totalSheets > 1) {
|
|
2862
3437
|
actions.push({
|
|
2863
3438
|
id: "page-nav",
|
|
@@ -2901,26 +3476,6 @@ var ExcelPlugin = class {
|
|
|
2901
3476
|
instance.zoomIn?.();
|
|
2902
3477
|
}
|
|
2903
3478
|
},
|
|
2904
|
-
{
|
|
2905
|
-
id: "fit-page",
|
|
2906
|
-
icon: "fit-page",
|
|
2907
|
-
label: "Fit to View",
|
|
2908
|
-
type: "button",
|
|
2909
|
-
group: "zoom",
|
|
2910
|
-
execute: () => {
|
|
2911
|
-
instance.fitToPage?.();
|
|
2912
|
-
}
|
|
2913
|
-
},
|
|
2914
|
-
{
|
|
2915
|
-
id: "rotate-cw",
|
|
2916
|
-
icon: "rotate-cw",
|
|
2917
|
-
label: "Rotate",
|
|
2918
|
-
type: "button",
|
|
2919
|
-
group: "view",
|
|
2920
|
-
execute: () => {
|
|
2921
|
-
instance.rotateCW?.();
|
|
2922
|
-
}
|
|
2923
|
-
},
|
|
2924
3479
|
{
|
|
2925
3480
|
id: "download",
|
|
2926
3481
|
icon: "download",
|
|
@@ -2940,6 +3495,16 @@ var ExcelPlugin = class {
|
|
|
2940
3495
|
execute: () => {
|
|
2941
3496
|
instance.print?.();
|
|
2942
3497
|
}
|
|
3498
|
+
},
|
|
3499
|
+
{
|
|
3500
|
+
id: "open-window",
|
|
3501
|
+
icon: "open-window",
|
|
3502
|
+
label: "Open in Separate Full Window",
|
|
3503
|
+
type: "button",
|
|
3504
|
+
group: "actions",
|
|
3505
|
+
execute: () => {
|
|
3506
|
+
instance.openInSeparateWindow?.();
|
|
3507
|
+
}
|
|
2943
3508
|
}
|
|
2944
3509
|
);
|
|
2945
3510
|
return actions;
|
|
@@ -2971,12 +3536,11 @@ var ExcelPlugin = class {
|
|
|
2971
3536
|
container.appendChild(tabsArea);
|
|
2972
3537
|
ctx.container.appendChild(container);
|
|
2973
3538
|
let scale = 1;
|
|
2974
|
-
let rotation = 0;
|
|
2975
3539
|
let currentSheetIndex = 1;
|
|
2976
3540
|
let sheetNames = [];
|
|
2977
3541
|
let wb = null;
|
|
2978
3542
|
const applyTransform = () => {
|
|
2979
|
-
contentArea.style.transform = `scale(${scale})
|
|
3543
|
+
contentArea.style.transform = `scale(${scale})`;
|
|
2980
3544
|
contentArea.style.transformOrigin = "top left";
|
|
2981
3545
|
};
|
|
2982
3546
|
const calculateFitScale = () => {
|
|
@@ -2984,7 +3548,7 @@ var ExcelPlugin = class {
|
|
|
2984
3548
|
if (!table) return 1;
|
|
2985
3549
|
const availW = Math.max(280, container.clientWidth - 48);
|
|
2986
3550
|
const tW = table.offsetWidth || 800;
|
|
2987
|
-
return Math.max(0.
|
|
3551
|
+
return Math.max(0.4, Math.min(1, availW / tW));
|
|
2988
3552
|
};
|
|
2989
3553
|
try {
|
|
2990
3554
|
wb = XLSX.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
|
|
@@ -3039,7 +3603,16 @@ var ExcelPlugin = class {
|
|
|
3039
3603
|
}
|
|
3040
3604
|
});
|
|
3041
3605
|
ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
|
|
3606
|
+
requestAnimationFrame(() => {
|
|
3607
|
+
scale = calculateFitScale();
|
|
3608
|
+
applyTransform();
|
|
3609
|
+
});
|
|
3042
3610
|
};
|
|
3611
|
+
const ro = new ResizeObserver(() => {
|
|
3612
|
+
scale = calculateFitScale();
|
|
3613
|
+
applyTransform();
|
|
3614
|
+
});
|
|
3615
|
+
ro.observe(container);
|
|
3043
3616
|
if (sheetNames.length > 0) {
|
|
3044
3617
|
sheetNames.forEach((name, idx) => {
|
|
3045
3618
|
const btn = document.createElement("button");
|
|
@@ -3066,6 +3639,7 @@ var ExcelPlugin = class {
|
|
|
3066
3639
|
`;
|
|
3067
3640
|
}
|
|
3068
3641
|
const cleanup = () => {
|
|
3642
|
+
ro.disconnect();
|
|
3069
3643
|
container.remove();
|
|
3070
3644
|
ctx.container.innerHTML = "";
|
|
3071
3645
|
};
|
|
@@ -3087,16 +3661,11 @@ var ExcelPlugin = class {
|
|
|
3087
3661
|
},
|
|
3088
3662
|
fitToPage: () => {
|
|
3089
3663
|
scale = calculateFitScale();
|
|
3090
|
-
rotation = 0;
|
|
3091
3664
|
applyTransform();
|
|
3092
3665
|
},
|
|
3093
3666
|
rotateCW: () => {
|
|
3094
|
-
rotation = (rotation + 90) % 360;
|
|
3095
|
-
applyTransform();
|
|
3096
3667
|
},
|
|
3097
3668
|
rotateCCW: () => {
|
|
3098
|
-
rotation = (rotation - 90 + 360) % 360;
|
|
3099
|
-
applyTransform();
|
|
3100
3669
|
},
|
|
3101
3670
|
goToPage: (page) => {
|
|
3102
3671
|
if (page > 0 && page <= sheetNames.length) {
|
|
@@ -3105,6 +3674,63 @@ var ExcelPlugin = class {
|
|
|
3105
3674
|
},
|
|
3106
3675
|
getPageCount: () => sheetNames.length,
|
|
3107
3676
|
getCurrentPage: () => currentSheetIndex,
|
|
3677
|
+
getThumbnails: () => {
|
|
3678
|
+
return sheetNames.map((name, idx) => ({
|
|
3679
|
+
index: idx,
|
|
3680
|
+
label: name,
|
|
3681
|
+
render: async (canvas) => {
|
|
3682
|
+
canvas.width = 140;
|
|
3683
|
+
canvas.height = 100;
|
|
3684
|
+
const c = canvas.getContext("2d");
|
|
3685
|
+
if (!c) return;
|
|
3686
|
+
c.fillStyle = "#ffffff";
|
|
3687
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
3688
|
+
c.fillStyle = "#107c41";
|
|
3689
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
3690
|
+
c.fillStyle = "#ffffff";
|
|
3691
|
+
c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
3692
|
+
c.fillText(`\u{1F4CA} ${name.slice(0, 16)}`, 6, 11);
|
|
3693
|
+
const startY = 17;
|
|
3694
|
+
const rowH = 13;
|
|
3695
|
+
const colW = 30;
|
|
3696
|
+
const colHeaders = ["A", "B", "C", "D"];
|
|
3697
|
+
c.fillStyle = "#f1f5f9";
|
|
3698
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
3699
|
+
c.strokeStyle = "#cbd5e1";
|
|
3700
|
+
c.lineWidth = 0.8;
|
|
3701
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
3702
|
+
c.fillStyle = "#64748b";
|
|
3703
|
+
c.font = "bold 7px sans-serif";
|
|
3704
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3705
|
+
c.fillText(colHeaders[ci], 14 + ci * colW, startY + 9);
|
|
3706
|
+
}
|
|
3707
|
+
const ws = wb?.Sheets[name];
|
|
3708
|
+
for (let ri = 1; ri <= 5; ri++) {
|
|
3709
|
+
const y = startY + ri * rowH;
|
|
3710
|
+
if (y > canvas.height - 2) break;
|
|
3711
|
+
c.fillStyle = "#f8fafc";
|
|
3712
|
+
c.fillRect(0, y, 12, rowH);
|
|
3713
|
+
c.fillStyle = "#94a3b8";
|
|
3714
|
+
c.font = "6px sans-serif";
|
|
3715
|
+
c.fillText(String(ri), 3, y + 9);
|
|
3716
|
+
c.strokeStyle = "#e2e8f0";
|
|
3717
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
3718
|
+
c.fillStyle = "#334155";
|
|
3719
|
+
c.font = "6px sans-serif";
|
|
3720
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3721
|
+
const cellRef = `${colHeaders[ci]}${ri}`;
|
|
3722
|
+
const cellVal = ws?.[cellRef]?.w || ws?.[cellRef]?.v;
|
|
3723
|
+
if (cellVal !== void 0) {
|
|
3724
|
+
c.fillText(String(cellVal).slice(0, 6), 14 + ci * colW, y + 9);
|
|
3725
|
+
}
|
|
3726
|
+
}
|
|
3727
|
+
}
|
|
3728
|
+
c.strokeStyle = "#cbd5e1";
|
|
3729
|
+
c.lineWidth = 1;
|
|
3730
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
3731
|
+
}
|
|
3732
|
+
}));
|
|
3733
|
+
},
|
|
3108
3734
|
download: () => {
|
|
3109
3735
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
3110
3736
|
const url = URL.createObjectURL(blob);
|
|
@@ -3137,7 +3763,16 @@ var CsvPlugin = class {
|
|
|
3137
3763
|
return ext === ".csv" || ext === ".tsv" || mime === "text/csv" || mime === "text/tab-separated-values";
|
|
3138
3764
|
}
|
|
3139
3765
|
getToolbarActions(instance) {
|
|
3140
|
-
|
|
3766
|
+
const actions = [];
|
|
3767
|
+
actions.push({
|
|
3768
|
+
id: "thumbnails",
|
|
3769
|
+
icon: "thumbnails",
|
|
3770
|
+
label: "Sheet Thumbnails",
|
|
3771
|
+
type: "button",
|
|
3772
|
+
group: "navigation",
|
|
3773
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3774
|
+
});
|
|
3775
|
+
actions.push(
|
|
3141
3776
|
{
|
|
3142
3777
|
id: "zoom-out",
|
|
3143
3778
|
icon: "zoom-out",
|
|
@@ -3177,8 +3812,19 @@ var CsvPlugin = class {
|
|
|
3177
3812
|
execute: () => {
|
|
3178
3813
|
instance.print?.();
|
|
3179
3814
|
}
|
|
3815
|
+
},
|
|
3816
|
+
{
|
|
3817
|
+
id: "open-window",
|
|
3818
|
+
icon: "open-window",
|
|
3819
|
+
label: "Open in Separate Full Window",
|
|
3820
|
+
type: "button",
|
|
3821
|
+
group: "actions",
|
|
3822
|
+
execute: () => {
|
|
3823
|
+
instance.openInSeparateWindow?.();
|
|
3824
|
+
}
|
|
3180
3825
|
}
|
|
3181
|
-
|
|
3826
|
+
);
|
|
3827
|
+
return actions;
|
|
3182
3828
|
}
|
|
3183
3829
|
async render(ctx) {
|
|
3184
3830
|
const decoder = new TextDecoder("utf-8");
|
|
@@ -3189,57 +3835,156 @@ var CsvPlugin = class {
|
|
|
3189
3835
|
container.style.overflow = "auto";
|
|
3190
3836
|
container.style.padding = "16px";
|
|
3191
3837
|
container.style.boxSizing = "border-box";
|
|
3192
|
-
|
|
3838
|
+
const tableWrapper = document.createElement("div");
|
|
3839
|
+
tableWrapper.style.transformOrigin = "top left";
|
|
3840
|
+
const delimiter = ctx.metadata.extension === ".tsv" ? " " : ",";
|
|
3841
|
+
const allLines = text.split(/\r?\n/).filter((r) => r.trim().length > 0);
|
|
3842
|
+
const headerLine = allLines[0] || "";
|
|
3843
|
+
const headerCells = headerLine.split(delimiter);
|
|
3844
|
+
const dataLines = allLines.slice(1);
|
|
3193
3845
|
const table = document.createElement("table");
|
|
3194
3846
|
table.style.borderCollapse = "collapse";
|
|
3195
|
-
table.style.
|
|
3196
|
-
table.style.fontFamily = "monospace
|
|
3847
|
+
table.style.minWidth = "100%";
|
|
3848
|
+
table.style.fontFamily = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace';
|
|
3197
3849
|
table.style.fontSize = "13px";
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3850
|
+
table.style.background = "#ffffff";
|
|
3851
|
+
table.style.border = "1px solid #d0d7de";
|
|
3852
|
+
const headerTr = document.createElement("tr");
|
|
3853
|
+
headerCells.forEach((cell) => {
|
|
3854
|
+
const th = document.createElement("th");
|
|
3855
|
+
th.textContent = cell.trim();
|
|
3856
|
+
th.style.border = "1px solid #d0d7de";
|
|
3857
|
+
th.style.padding = "8px 12px";
|
|
3858
|
+
th.style.backgroundColor = "#f6f8fa";
|
|
3859
|
+
th.style.fontWeight = "600";
|
|
3860
|
+
th.style.whiteSpace = "nowrap";
|
|
3861
|
+
headerTr.appendChild(th);
|
|
3862
|
+
});
|
|
3863
|
+
table.appendChild(headerTr);
|
|
3864
|
+
dataLines.forEach((row, idx) => {
|
|
3202
3865
|
const tr = document.createElement("tr");
|
|
3866
|
+
if (idx % 2 === 1) tr.style.backgroundColor = "#f8fafc";
|
|
3203
3867
|
const cells = row.split(delimiter);
|
|
3204
3868
|
cells.forEach((cell) => {
|
|
3205
|
-
const td = document.createElement(
|
|
3869
|
+
const td = document.createElement("td");
|
|
3206
3870
|
td.textContent = cell.trim();
|
|
3207
3871
|
td.style.border = "1px solid #d0d7de";
|
|
3208
3872
|
td.style.padding = "6px 12px";
|
|
3209
|
-
|
|
3210
|
-
td.style.backgroundColor = "#f6f8fa";
|
|
3211
|
-
td.style.fontWeight = "bold";
|
|
3212
|
-
}
|
|
3873
|
+
td.style.whiteSpace = "nowrap";
|
|
3213
3874
|
tr.appendChild(td);
|
|
3214
3875
|
});
|
|
3215
3876
|
table.appendChild(tr);
|
|
3216
3877
|
});
|
|
3217
|
-
|
|
3878
|
+
tableWrapper.appendChild(table);
|
|
3879
|
+
container.appendChild(tableWrapper);
|
|
3218
3880
|
ctx.container.appendChild(container);
|
|
3219
3881
|
let scale = 1;
|
|
3882
|
+
const calculateFitScale = () => {
|
|
3883
|
+
const availW = Math.max(280, container.clientWidth - 48);
|
|
3884
|
+
const tW = table.offsetWidth || 800;
|
|
3885
|
+
return Math.max(0.4, Math.min(1, availW / tW));
|
|
3886
|
+
};
|
|
3887
|
+
const applyScale = () => {
|
|
3888
|
+
tableWrapper.style.transform = `scale(${scale})`;
|
|
3889
|
+
};
|
|
3890
|
+
requestAnimationFrame(() => {
|
|
3891
|
+
scale = calculateFitScale();
|
|
3892
|
+
applyScale();
|
|
3893
|
+
});
|
|
3894
|
+
const ro = new ResizeObserver(() => {
|
|
3895
|
+
scale = calculateFitScale();
|
|
3896
|
+
applyScale();
|
|
3897
|
+
});
|
|
3898
|
+
ro.observe(container);
|
|
3220
3899
|
const cleanup = () => {
|
|
3900
|
+
ro.disconnect();
|
|
3221
3901
|
container.remove();
|
|
3222
3902
|
ctx.container.innerHTML = "";
|
|
3223
3903
|
};
|
|
3224
3904
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3225
3905
|
return {
|
|
3226
3906
|
destroy: cleanup,
|
|
3907
|
+
getPageCount: () => 1,
|
|
3908
|
+
getCurrentPage: () => 1,
|
|
3909
|
+
goToPage: () => {
|
|
3910
|
+
},
|
|
3911
|
+
getThumbnails: () => {
|
|
3912
|
+
const sheetName = ctx.metadata.name?.replace(/\.[^/.]+$/, "") || "Sheet1";
|
|
3913
|
+
return [{
|
|
3914
|
+
index: 0,
|
|
3915
|
+
label: sheetName,
|
|
3916
|
+
render: async (canvas) => {
|
|
3917
|
+
canvas.width = 140;
|
|
3918
|
+
canvas.height = 100;
|
|
3919
|
+
const c = canvas.getContext("2d");
|
|
3920
|
+
if (!c) return;
|
|
3921
|
+
c.fillStyle = "#ffffff";
|
|
3922
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
3923
|
+
c.fillStyle = "#107c41";
|
|
3924
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
3925
|
+
c.fillStyle = "#ffffff";
|
|
3926
|
+
c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
3927
|
+
c.fillText(`\u{1F4CA} ${sheetName.slice(0, 16)}`, 6, 11);
|
|
3928
|
+
const startY = 17;
|
|
3929
|
+
const rowH = 13;
|
|
3930
|
+
const colW = 30;
|
|
3931
|
+
const cols = headerCells.slice(0, 4).map((h) => h.trim() || "Col");
|
|
3932
|
+
c.fillStyle = "#f1f5f9";
|
|
3933
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
3934
|
+
c.strokeStyle = "#cbd5e1";
|
|
3935
|
+
c.lineWidth = 0.8;
|
|
3936
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
3937
|
+
c.fillStyle = "#64748b";
|
|
3938
|
+
c.font = "bold 7px sans-serif";
|
|
3939
|
+
for (let ci = 0; ci < cols.length; ci++) {
|
|
3940
|
+
c.fillText(cols[ci].slice(0, 5), 14 + ci * colW, startY + 9);
|
|
3941
|
+
}
|
|
3942
|
+
for (let ri = 0; ri < Math.min(5, dataLines.length); ri++) {
|
|
3943
|
+
const y = startY + (ri + 1) * rowH;
|
|
3944
|
+
if (y > canvas.height - 2) break;
|
|
3945
|
+
c.fillStyle = "#f8fafc";
|
|
3946
|
+
c.fillRect(0, y, 12, rowH);
|
|
3947
|
+
c.fillStyle = "#94a3b8";
|
|
3948
|
+
c.font = "6px sans-serif";
|
|
3949
|
+
c.fillText(String(ri + 1), 3, y + 9);
|
|
3950
|
+
c.strokeStyle = "#e2e8f0";
|
|
3951
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
3952
|
+
const rowCells = dataLines[ri].split(delimiter);
|
|
3953
|
+
c.fillStyle = "#334155";
|
|
3954
|
+
c.font = "6px sans-serif";
|
|
3955
|
+
for (let ci = 0; ci < cols.length; ci++) {
|
|
3956
|
+
const val = (rowCells[ci] || "").trim();
|
|
3957
|
+
if (val) {
|
|
3958
|
+
c.fillText(val.slice(0, 6), 14 + ci * colW, y + 9);
|
|
3959
|
+
}
|
|
3960
|
+
}
|
|
3961
|
+
}
|
|
3962
|
+
c.strokeStyle = "#cbd5e1";
|
|
3963
|
+
c.lineWidth = 1;
|
|
3964
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
3965
|
+
}
|
|
3966
|
+
}];
|
|
3967
|
+
},
|
|
3227
3968
|
zoomIn: () => {
|
|
3228
3969
|
scale += 0.1;
|
|
3229
|
-
|
|
3970
|
+
applyScale();
|
|
3230
3971
|
},
|
|
3231
3972
|
zoomOut: () => {
|
|
3232
3973
|
scale = Math.max(0.2, scale - 0.1);
|
|
3233
|
-
|
|
3974
|
+
applyScale();
|
|
3234
3975
|
},
|
|
3235
3976
|
getZoom: () => scale,
|
|
3236
3977
|
setZoom: (level) => {
|
|
3237
3978
|
scale = level;
|
|
3238
|
-
|
|
3979
|
+
applyScale();
|
|
3239
3980
|
},
|
|
3240
3981
|
fitToPage: () => {
|
|
3241
|
-
scale =
|
|
3242
|
-
|
|
3982
|
+
scale = calculateFitScale();
|
|
3983
|
+
applyScale();
|
|
3984
|
+
},
|
|
3985
|
+
rotateCW: () => {
|
|
3986
|
+
},
|
|
3987
|
+
rotateCCW: () => {
|
|
3243
3988
|
},
|
|
3244
3989
|
download: () => {
|
|
3245
3990
|
const blob = new Blob([ctx.buffer], { type: "text/csv" });
|
|
@@ -3301,30 +4046,36 @@ var CodePlugin = class {
|
|
|
3301
4046
|
return false;
|
|
3302
4047
|
}
|
|
3303
4048
|
getToolbarActions(instance) {
|
|
3304
|
-
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3305
|
-
const actions = [];
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
4049
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4050
|
+
const actions = [];
|
|
4051
|
+
actions.push({
|
|
4052
|
+
id: "thumbnails",
|
|
4053
|
+
icon: "thumbnails",
|
|
4054
|
+
label: "Page Thumbnails",
|
|
4055
|
+
type: "button",
|
|
4056
|
+
group: "navigation",
|
|
4057
|
+
execute: () => instance.toggleThumbnails?.()
|
|
4058
|
+
});
|
|
4059
|
+
actions.push({
|
|
4060
|
+
id: "page-nav",
|
|
4061
|
+
icon: "",
|
|
4062
|
+
label: "Page Navigation",
|
|
4063
|
+
type: "page-nav",
|
|
4064
|
+
group: "navigation",
|
|
4065
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4066
|
+
max: totalPages,
|
|
4067
|
+
execute: (action, page) => {
|
|
4068
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4069
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4070
|
+
if (action === "prev") {
|
|
4071
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4072
|
+
} else if (action === "next") {
|
|
4073
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4074
|
+
} else if (typeof page === "number") {
|
|
4075
|
+
instance.goToPage?.(page);
|
|
3325
4076
|
}
|
|
3326
|
-
}
|
|
3327
|
-
}
|
|
4077
|
+
}
|
|
4078
|
+
});
|
|
3328
4079
|
actions.push(
|
|
3329
4080
|
{
|
|
3330
4081
|
id: "zoom-out",
|
|
@@ -3346,26 +4097,6 @@ var CodePlugin = class {
|
|
|
3346
4097
|
instance.zoomIn?.();
|
|
3347
4098
|
}
|
|
3348
4099
|
},
|
|
3349
|
-
{
|
|
3350
|
-
id: "fit-page",
|
|
3351
|
-
icon: "fit-page",
|
|
3352
|
-
label: "Fit to View",
|
|
3353
|
-
type: "button",
|
|
3354
|
-
group: "zoom",
|
|
3355
|
-
execute: () => {
|
|
3356
|
-
instance.fitToPage?.();
|
|
3357
|
-
}
|
|
3358
|
-
},
|
|
3359
|
-
{
|
|
3360
|
-
id: "rotate-cw",
|
|
3361
|
-
icon: "rotate-cw",
|
|
3362
|
-
label: "Rotate",
|
|
3363
|
-
type: "button",
|
|
3364
|
-
group: "view",
|
|
3365
|
-
execute: () => {
|
|
3366
|
-
instance.rotateCW?.();
|
|
3367
|
-
}
|
|
3368
|
-
},
|
|
3369
4100
|
{
|
|
3370
4101
|
id: "copy",
|
|
3371
4102
|
icon: "copy",
|
|
@@ -3468,16 +4199,19 @@ var CodePlugin = class {
|
|
|
3468
4199
|
let fontSize = 13;
|
|
3469
4200
|
let rotation = 0;
|
|
3470
4201
|
let zoomLevel = 1;
|
|
4202
|
+
let isUserZoomed = false;
|
|
3471
4203
|
const pre = document.createElement("pre");
|
|
3472
4204
|
const code = document.createElement("code");
|
|
3473
4205
|
if (isTxt) {
|
|
4206
|
+
container.style.overflowX = "hidden";
|
|
4207
|
+
container.style.overflowY = "auto";
|
|
3474
4208
|
container.style.backgroundColor = "#f1f5f9";
|
|
3475
|
-
container.style.padding = "
|
|
4209
|
+
container.style.padding = "16px 8px";
|
|
3476
4210
|
container.style.boxSizing = "border-box";
|
|
3477
4211
|
container.style.display = "flex";
|
|
3478
4212
|
container.style.flexDirection = "column";
|
|
3479
4213
|
container.style.alignItems = "center";
|
|
3480
|
-
pre.style.margin = "0";
|
|
4214
|
+
pre.style.margin = "0 auto";
|
|
3481
4215
|
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3482
4216
|
pre.style.fontSize = "13px";
|
|
3483
4217
|
pre.style.color = "#1e293b";
|
|
@@ -3489,10 +4223,12 @@ var CodePlugin = class {
|
|
|
3489
4223
|
pre.style.minHeight = "1056px";
|
|
3490
4224
|
pre.style.padding = "72px 56px";
|
|
3491
4225
|
pre.style.boxSizing = "border-box";
|
|
3492
|
-
pre.style.boxShadow = "0 4px
|
|
4226
|
+
pre.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
3493
4227
|
pre.style.borderRadius = "4px";
|
|
3494
4228
|
pre.style.transformOrigin = "top center";
|
|
4229
|
+
pre.style.transition = "transform 0.15s ease";
|
|
3495
4230
|
} else {
|
|
4231
|
+
container.style.overflow = "auto";
|
|
3496
4232
|
container.style.backgroundColor = "#1e1e1e";
|
|
3497
4233
|
container.style.color = "#d4d4d4";
|
|
3498
4234
|
container.style.padding = "16px";
|
|
@@ -3524,42 +4260,9 @@ var CodePlugin = class {
|
|
|
3524
4260
|
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
3525
4261
|
pre.appendChild(code);
|
|
3526
4262
|
container.appendChild(pre);
|
|
3527
|
-
let indicator = null;
|
|
3528
|
-
if (totalPages > 1) {
|
|
3529
|
-
indicator = document.createElement("div");
|
|
3530
|
-
indicator.className = "fp-code-page-indicator";
|
|
3531
|
-
indicator.style.position = "sticky";
|
|
3532
|
-
indicator.style.bottom = "16px";
|
|
3533
|
-
if (isTxt) {
|
|
3534
|
-
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3535
|
-
indicator.style.color = "#334155";
|
|
3536
|
-
indicator.style.border = "1px solid #e2e8f0";
|
|
3537
|
-
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3538
|
-
} else {
|
|
3539
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3540
|
-
indicator.style.color = "#f8fafc";
|
|
3541
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3542
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3543
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
3544
|
-
}
|
|
3545
|
-
indicator.style.fontSize = "12px";
|
|
3546
|
-
indicator.style.fontWeight = "600";
|
|
3547
|
-
indicator.style.padding = "5px 14px";
|
|
3548
|
-
indicator.style.borderRadius = "20px";
|
|
3549
|
-
indicator.style.zIndex = "10";
|
|
3550
|
-
indicator.style.userSelect = "none";
|
|
3551
|
-
indicator.style.pointerEvents = "none";
|
|
3552
|
-
indicator.style.textAlign = "center";
|
|
3553
|
-
indicator.style.width = "fit-content";
|
|
3554
|
-
indicator.style.margin = "16px auto 0";
|
|
3555
|
-
container.appendChild(indicator);
|
|
3556
|
-
}
|
|
3557
4263
|
const showPage = (pageNum) => {
|
|
3558
4264
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3559
4265
|
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
3560
|
-
if (indicator) {
|
|
3561
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3562
|
-
}
|
|
3563
4266
|
container.scrollTop = 0;
|
|
3564
4267
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3565
4268
|
};
|
|
@@ -3567,36 +4270,90 @@ var CodePlugin = class {
|
|
|
3567
4270
|
showPage(1);
|
|
3568
4271
|
}
|
|
3569
4272
|
ctx.container.appendChild(container);
|
|
3570
|
-
const
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
ctx.container.innerHTML = "";
|
|
4273
|
+
const calculateTxtFit = () => {
|
|
4274
|
+
const availW = Math.max(280, container.clientWidth - 32);
|
|
4275
|
+
return Math.max(0.4, Math.min(3, availW / 816));
|
|
3574
4276
|
};
|
|
3575
|
-
ctx.signal.addEventListener("abort", cleanup);
|
|
3576
4277
|
const updateTransform = () => {
|
|
3577
4278
|
if (isTxt) {
|
|
3578
4279
|
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
4280
|
+
const scaledH = 1056 * zoomLevel;
|
|
4281
|
+
const extraH = Math.max(0, scaledH - 1056);
|
|
4282
|
+
pre.style.marginBottom = `${extraH + 32}px`;
|
|
3579
4283
|
} else {
|
|
3580
4284
|
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3581
4285
|
pre.style.fontSize = `${fontSize}px`;
|
|
3582
4286
|
}
|
|
3583
4287
|
};
|
|
4288
|
+
let resizeObserver = null;
|
|
4289
|
+
if (isTxt) {
|
|
4290
|
+
setTimeout(() => {
|
|
4291
|
+
zoomLevel = calculateTxtFit();
|
|
4292
|
+
updateTransform();
|
|
4293
|
+
}, 60);
|
|
4294
|
+
resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
4295
|
+
if (!isUserZoomed) {
|
|
4296
|
+
zoomLevel = calculateTxtFit();
|
|
4297
|
+
updateTransform();
|
|
4298
|
+
}
|
|
4299
|
+
}) : null;
|
|
4300
|
+
resizeObserver?.observe(container);
|
|
4301
|
+
}
|
|
4302
|
+
const cleanup = () => {
|
|
4303
|
+
resizeObserver?.disconnect();
|
|
4304
|
+
container.remove();
|
|
4305
|
+
ctx.container.innerHTML = "";
|
|
4306
|
+
};
|
|
4307
|
+
ctx.signal.addEventListener("abort", cleanup);
|
|
3584
4308
|
return {
|
|
3585
4309
|
destroy: cleanup,
|
|
3586
4310
|
getPageCount: () => totalPages,
|
|
3587
4311
|
getCurrentPage: () => currentPage,
|
|
3588
4312
|
goToPage: (page) => showPage(page),
|
|
4313
|
+
getThumbnails: () => {
|
|
4314
|
+
return rawPages.map((pageText, idx) => ({
|
|
4315
|
+
index: idx,
|
|
4316
|
+
label: `Page ${idx + 1}`,
|
|
4317
|
+
render: async (canvas) => {
|
|
4318
|
+
canvas.width = 140;
|
|
4319
|
+
canvas.height = 180;
|
|
4320
|
+
const c = canvas.getContext("2d");
|
|
4321
|
+
if (!c) return;
|
|
4322
|
+
c.fillStyle = "#ffffff";
|
|
4323
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4324
|
+
c.strokeStyle = "#cbd5e1";
|
|
4325
|
+
c.lineWidth = 1;
|
|
4326
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4327
|
+
c.fillStyle = "#64748b";
|
|
4328
|
+
const lines = (pageText || "").split("\n").slice(0, 24);
|
|
4329
|
+
const lineH = 6;
|
|
4330
|
+
const startY = 14;
|
|
4331
|
+
const startX = 12;
|
|
4332
|
+
const maxW = canvas.width - 24;
|
|
4333
|
+
c.font = "5px monospace";
|
|
4334
|
+
for (let li = 0; li < lines.length; li++) {
|
|
4335
|
+
const l = lines[li].trim();
|
|
4336
|
+
if (!l) continue;
|
|
4337
|
+
const y = startY + li * lineH;
|
|
4338
|
+
if (y > canvas.height - 12) break;
|
|
4339
|
+
c.fillText(l.slice(0, 30), startX, y, maxW);
|
|
4340
|
+
}
|
|
4341
|
+
}
|
|
4342
|
+
}));
|
|
4343
|
+
},
|
|
3589
4344
|
zoomIn: () => {
|
|
4345
|
+
isUserZoomed = true;
|
|
3590
4346
|
if (isTxt) {
|
|
3591
|
-
zoomLevel = Math.min(3, zoomLevel + 0.
|
|
4347
|
+
zoomLevel = Math.min(3.5, zoomLevel + 0.15);
|
|
3592
4348
|
} else {
|
|
3593
4349
|
fontSize = Math.min(32, fontSize + 2);
|
|
3594
4350
|
}
|
|
3595
4351
|
updateTransform();
|
|
3596
4352
|
},
|
|
3597
4353
|
zoomOut: () => {
|
|
4354
|
+
isUserZoomed = true;
|
|
3598
4355
|
if (isTxt) {
|
|
3599
|
-
zoomLevel = Math.max(0.1, zoomLevel - 0.
|
|
4356
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.15);
|
|
3600
4357
|
} else {
|
|
3601
4358
|
fontSize = Math.max(8, fontSize - 2);
|
|
3602
4359
|
}
|
|
@@ -3604,6 +4361,7 @@ var CodePlugin = class {
|
|
|
3604
4361
|
},
|
|
3605
4362
|
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
3606
4363
|
setZoom: (level) => {
|
|
4364
|
+
isUserZoomed = true;
|
|
3607
4365
|
if (isTxt) {
|
|
3608
4366
|
zoomLevel = level;
|
|
3609
4367
|
} else {
|
|
@@ -3612,9 +4370,10 @@ var CodePlugin = class {
|
|
|
3612
4370
|
updateTransform();
|
|
3613
4371
|
},
|
|
3614
4372
|
fitToPage: () => {
|
|
4373
|
+
isUserZoomed = false;
|
|
3615
4374
|
fontSize = 13;
|
|
3616
4375
|
rotation = 0;
|
|
3617
|
-
zoomLevel = isTxt ?
|
|
4376
|
+
zoomLevel = isTxt ? calculateTxtFit() : 1;
|
|
3618
4377
|
updateTransform();
|
|
3619
4378
|
},
|
|
3620
4379
|
rotateCW: () => {
|
|
@@ -4481,6 +5240,148 @@ var ThreeDPlugin = class {
|
|
|
4481
5240
|
function threeDPlugin() {
|
|
4482
5241
|
return new ThreeDPlugin();
|
|
4483
5242
|
}
|
|
5243
|
+
function cleanRtfText(raw) {
|
|
5244
|
+
return raw.replace(/\\bin\d+\s/g, "").replace(/{\\\*[^}]+}/g, "").replace(/\\u(-?\d+)\??/g, (_, code) => {
|
|
5245
|
+
let num = parseInt(code, 10);
|
|
5246
|
+
if (num < 0) num += 65536;
|
|
5247
|
+
return String.fromCharCode(num);
|
|
5248
|
+
}).replace(/\\'([0-9a-fA-F]{2})/g, (_, hex) => {
|
|
5249
|
+
return String.fromCharCode(parseInt(hex, 16));
|
|
5250
|
+
}).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();
|
|
5251
|
+
}
|
|
5252
|
+
function parseRtfTables(rtfText) {
|
|
5253
|
+
const rowSegments = rtfText.split(/\\row\b/);
|
|
5254
|
+
if (rowSegments.length <= 1) return [];
|
|
5255
|
+
const rawTables = [];
|
|
5256
|
+
let currentTable = null;
|
|
5257
|
+
let charOffset = 0;
|
|
5258
|
+
for (let i = 0; i < rowSegments.length - 1; i++) {
|
|
5259
|
+
const segment = rowSegments[i];
|
|
5260
|
+
const segmentStart = charOffset;
|
|
5261
|
+
const segmentEnd = charOffset + segment.length + 4;
|
|
5262
|
+
const cellParts = segment.split(/\\cell\b/);
|
|
5263
|
+
if (cellParts.length > 1) {
|
|
5264
|
+
const cellxMatches = [...segment.matchAll(/\\cellx(\d+)/g)].map((m) => parseInt(m[1], 10));
|
|
5265
|
+
let cellWidths = [];
|
|
5266
|
+
if (cellxMatches.length > 0) {
|
|
5267
|
+
let seq = [cellxMatches[0]];
|
|
5268
|
+
for (let k = 1; k < cellxMatches.length; k++) {
|
|
5269
|
+
if (cellxMatches[k] > cellxMatches[k - 1]) seq.push(cellxMatches[k]);
|
|
5270
|
+
else break;
|
|
5271
|
+
}
|
|
5272
|
+
let prev = 0;
|
|
5273
|
+
cellWidths = seq.map((x) => {
|
|
5274
|
+
const w = x - prev;
|
|
5275
|
+
prev = x;
|
|
5276
|
+
return w;
|
|
5277
|
+
});
|
|
5278
|
+
}
|
|
5279
|
+
const cells = [];
|
|
5280
|
+
for (let c = 0; c < cellParts.length - 1; c++) {
|
|
5281
|
+
let rawCell = cellParts[c];
|
|
5282
|
+
if (c === 0) {
|
|
5283
|
+
const lastTrowd = rawCell.lastIndexOf("\\trowd");
|
|
5284
|
+
if (lastTrowd !== -1) rawCell = rawCell.slice(lastTrowd);
|
|
5285
|
+
}
|
|
5286
|
+
cells.push(cleanRtfText(rawCell));
|
|
5287
|
+
}
|
|
5288
|
+
const isNewTable = !currentTable || segmentStart - currentTable.lastEnd > 2500;
|
|
5289
|
+
if (isNewTable) {
|
|
5290
|
+
const prevTextSlice = rtfText.slice(Math.max(0, segmentStart - 4e3), segmentStart);
|
|
5291
|
+
const cleanPrev = cleanRtfText(prevTextSlice);
|
|
5292
|
+
const anchorBefore = cleanPrev.slice(-80).trim();
|
|
5293
|
+
currentTable = {
|
|
5294
|
+
id: `RTF_TABLE_${rawTables.length}`,
|
|
5295
|
+
startPos: segmentStart,
|
|
5296
|
+
lastEnd: segmentEnd,
|
|
5297
|
+
rows: [],
|
|
5298
|
+
columnWidths: cellWidths,
|
|
5299
|
+
anchorBefore,
|
|
5300
|
+
anchorAfter: ""
|
|
5301
|
+
};
|
|
5302
|
+
rawTables.push(currentTable);
|
|
5303
|
+
}
|
|
5304
|
+
if (currentTable) {
|
|
5305
|
+
currentTable.rows.push({
|
|
5306
|
+
cells,
|
|
5307
|
+
widths: cellWidths.length === cells.length ? cellWidths : currentTable.columnWidths
|
|
5308
|
+
});
|
|
5309
|
+
currentTable.lastEnd = segmentEnd;
|
|
5310
|
+
}
|
|
5311
|
+
}
|
|
5312
|
+
charOffset += segment.length + 4;
|
|
5313
|
+
}
|
|
5314
|
+
rawTables.forEach((tbl) => {
|
|
5315
|
+
const afterSlice = rtfText.slice(tbl.lastEnd, Math.min(rtfText.length, tbl.lastEnd + 2e3));
|
|
5316
|
+
const cleanAfter = cleanRtfText(afterSlice);
|
|
5317
|
+
tbl.anchorAfter = cleanAfter.slice(0, 80).trim();
|
|
5318
|
+
});
|
|
5319
|
+
return rawTables.map((tbl) => {
|
|
5320
|
+
const totalW = (tbl.columnWidths || []).reduce((a, b) => a + b, 0);
|
|
5321
|
+
const colPercents = totalW > 0 ? tbl.columnWidths.map((w) => Math.round(w / totalW * 100)) : [];
|
|
5322
|
+
return {
|
|
5323
|
+
id: tbl.id,
|
|
5324
|
+
rows: tbl.rows.map((r) => r.cells),
|
|
5325
|
+
colPercents,
|
|
5326
|
+
anchorBefore: tbl.anchorBefore,
|
|
5327
|
+
anchorAfter: tbl.anchorAfter
|
|
5328
|
+
};
|
|
5329
|
+
});
|
|
5330
|
+
}
|
|
5331
|
+
function renderRtfTableElement(table) {
|
|
5332
|
+
const tableEl = document.createElement("table");
|
|
5333
|
+
tableEl.className = "fp-rtf-table";
|
|
5334
|
+
tableEl.style.width = "100%";
|
|
5335
|
+
tableEl.style.borderCollapse = "collapse";
|
|
5336
|
+
tableEl.style.margin = "16px 0 20px";
|
|
5337
|
+
tableEl.style.fontSize = "10pt";
|
|
5338
|
+
tableEl.style.lineHeight = "1.5";
|
|
5339
|
+
tableEl.style.border = "1px solid #cbd5e1";
|
|
5340
|
+
tableEl.style.borderRadius = "4px";
|
|
5341
|
+
tableEl.style.boxSizing = "border-box";
|
|
5342
|
+
tableEl.style.backgroundColor = "#ffffff";
|
|
5343
|
+
const thead = document.createElement("thead");
|
|
5344
|
+
const tbody = document.createElement("tbody");
|
|
5345
|
+
table.rows.forEach((rowCells, rIdx) => {
|
|
5346
|
+
const tr = document.createElement("tr");
|
|
5347
|
+
const isHeader = rIdx === 0;
|
|
5348
|
+
if (isHeader) {
|
|
5349
|
+
tr.style.backgroundColor = "#f8fafc";
|
|
5350
|
+
tr.style.borderBottom = "2px solid #cbd5e1";
|
|
5351
|
+
} else {
|
|
5352
|
+
tr.style.borderBottom = "1px solid #e2e8f0";
|
|
5353
|
+
if (rIdx % 2 === 0) {
|
|
5354
|
+
tr.style.backgroundColor = "#fcfdfe";
|
|
5355
|
+
}
|
|
5356
|
+
}
|
|
5357
|
+
rowCells.forEach((cellText, cIdx) => {
|
|
5358
|
+
const cellEl = document.createElement(isHeader ? "th" : "td");
|
|
5359
|
+
cellEl.style.padding = "8px 12px";
|
|
5360
|
+
cellEl.style.border = "1px solid #cbd5e1";
|
|
5361
|
+
cellEl.style.verticalAlign = "top";
|
|
5362
|
+
cellEl.style.color = isHeader ? "#0f172a" : "#1e293b";
|
|
5363
|
+
cellEl.style.fontWeight = isHeader ? "600" : "normal";
|
|
5364
|
+
if (table.colPercents && table.colPercents[cIdx]) {
|
|
5365
|
+
cellEl.style.width = `${table.colPercents[cIdx]}%`;
|
|
5366
|
+
}
|
|
5367
|
+
if (/^\d+$/.test(cellText.trim()) || cellText.trim() === "#") {
|
|
5368
|
+
cellEl.style.textAlign = "center";
|
|
5369
|
+
} else {
|
|
5370
|
+
cellEl.style.textAlign = "left";
|
|
5371
|
+
}
|
|
5372
|
+
cellEl.textContent = cellText;
|
|
5373
|
+
tr.appendChild(cellEl);
|
|
5374
|
+
});
|
|
5375
|
+
if (isHeader) {
|
|
5376
|
+
thead.appendChild(tr);
|
|
5377
|
+
} else {
|
|
5378
|
+
tbody.appendChild(tr);
|
|
5379
|
+
}
|
|
5380
|
+
});
|
|
5381
|
+
tableEl.appendChild(thead);
|
|
5382
|
+
tableEl.appendChild(tbody);
|
|
5383
|
+
return tableEl;
|
|
5384
|
+
}
|
|
4484
5385
|
var RtfPlugin = class {
|
|
4485
5386
|
id = "rtf";
|
|
4486
5387
|
name = "Rich Text Format (RTF)";
|
|
@@ -4495,29 +5396,35 @@ var RtfPlugin = class {
|
|
|
4495
5396
|
getToolbarActions(instance) {
|
|
4496
5397
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4497
5398
|
const actions = [];
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
if (
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
instance.goToPage?.(page);
|
|
4516
|
-
}
|
|
5399
|
+
actions.push({
|
|
5400
|
+
id: "page-nav",
|
|
5401
|
+
icon: "",
|
|
5402
|
+
label: "Page Navigation",
|
|
5403
|
+
type: "page-nav",
|
|
5404
|
+
group: "navigation",
|
|
5405
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5406
|
+
max: totalPages,
|
|
5407
|
+
execute: (action, page) => {
|
|
5408
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5409
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5410
|
+
if (action === "prev") {
|
|
5411
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5412
|
+
} else if (action === "next") {
|
|
5413
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5414
|
+
} else if (typeof page === "number") {
|
|
5415
|
+
instance.goToPage?.(page);
|
|
4517
5416
|
}
|
|
4518
|
-
}
|
|
4519
|
-
}
|
|
5417
|
+
}
|
|
5418
|
+
});
|
|
4520
5419
|
actions.push(
|
|
5420
|
+
{
|
|
5421
|
+
id: "thumbnails",
|
|
5422
|
+
icon: "thumbnails",
|
|
5423
|
+
label: "Thumbnails",
|
|
5424
|
+
type: "button",
|
|
5425
|
+
group: "view",
|
|
5426
|
+
execute: () => instance.toggleThumbnails?.()
|
|
5427
|
+
},
|
|
4521
5428
|
{
|
|
4522
5429
|
id: "zoom-out",
|
|
4523
5430
|
icon: "zoom-out",
|
|
@@ -4588,67 +5495,143 @@ var RtfPlugin = class {
|
|
|
4588
5495
|
async render(ctx) {
|
|
4589
5496
|
const wrapper = document.createElement("div");
|
|
4590
5497
|
wrapper.className = "fp-rtf-wrapper";
|
|
4591
|
-
wrapper.style.padding = "
|
|
4592
|
-
wrapper.style.
|
|
5498
|
+
wrapper.style.padding = "0";
|
|
5499
|
+
wrapper.style.width = "816px";
|
|
4593
5500
|
wrapper.style.margin = "0 auto";
|
|
4594
|
-
wrapper.style.
|
|
4595
|
-
wrapper.style.
|
|
4596
|
-
wrapper.style.
|
|
4597
|
-
wrapper.style.
|
|
5501
|
+
wrapper.style.boxSizing = "border-box";
|
|
5502
|
+
wrapper.style.display = "flex";
|
|
5503
|
+
wrapper.style.flexDirection = "column";
|
|
5504
|
+
wrapper.style.alignItems = "center";
|
|
5505
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4598
5506
|
wrapper.style.transformOrigin = "top center";
|
|
4599
|
-
wrapper.style.transition = "transform 0.
|
|
4600
|
-
ctx.container.style.
|
|
4601
|
-
ctx.container.style.
|
|
5507
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5508
|
+
ctx.container.style.overflowX = "hidden";
|
|
5509
|
+
ctx.container.style.overflowY = "auto";
|
|
5510
|
+
ctx.container.style.padding = "16px 8px";
|
|
4602
5511
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
4603
5512
|
ctx.container.appendChild(wrapper);
|
|
4604
5513
|
let scale = 1;
|
|
4605
5514
|
let rotation = 0;
|
|
4606
5515
|
let pageElements = [];
|
|
4607
|
-
let
|
|
5516
|
+
let isUserZoomed = false;
|
|
5517
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
4608
5518
|
const calculateFitScale = (mode = fitMode) => {
|
|
4609
5519
|
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4610
|
-
const elW =
|
|
4611
|
-
const singlePageH =
|
|
4612
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
4613
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
5520
|
+
const elW = 816;
|
|
5521
|
+
const singlePageH = activeEl?.offsetHeight || 1056;
|
|
5522
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
5523
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
4614
5524
|
const sW = availW / elW;
|
|
4615
5525
|
const sH = availH / singlePageH;
|
|
4616
5526
|
if (mode === "page") {
|
|
4617
|
-
return Math.max(0.
|
|
5527
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
4618
5528
|
}
|
|
4619
|
-
return Math.max(0.
|
|
5529
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
4620
5530
|
};
|
|
4621
5531
|
const applyTransform = () => {
|
|
4622
5532
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4623
5533
|
wrapper.style.transformOrigin = "top center";
|
|
5534
|
+
const activeEl = pageElements[currentPage - 1];
|
|
5535
|
+
const baseH = activeEl?.offsetHeight || 1056;
|
|
5536
|
+
const scaledH = baseH * scale;
|
|
5537
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
5538
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
4624
5539
|
};
|
|
5540
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
5541
|
+
if (!isUserZoomed) {
|
|
5542
|
+
scale = calculateFitScale(fitMode);
|
|
5543
|
+
applyTransform();
|
|
5544
|
+
}
|
|
5545
|
+
}) : null;
|
|
5546
|
+
resizeObserver?.observe(ctx.container);
|
|
4625
5547
|
setTimeout(() => {
|
|
4626
|
-
|
|
4627
|
-
scale = calculateFitScale("width");
|
|
5548
|
+
scale = calculateFitScale(fitMode);
|
|
4628
5549
|
applyTransform();
|
|
4629
5550
|
}, 60);
|
|
4630
5551
|
try {
|
|
4631
5552
|
if (typeof RTFJS.loggingEnabled === "function") {
|
|
4632
5553
|
RTFJS.loggingEnabled(false);
|
|
4633
5554
|
}
|
|
5555
|
+
const rawText = new TextDecoder("latin1").decode(ctx.buffer);
|
|
5556
|
+
const tables = parseRtfTables(rawText);
|
|
4634
5557
|
const doc = new RTFJS.Document(ctx.buffer, {});
|
|
4635
5558
|
const htmlElements = await doc.render();
|
|
4636
5559
|
const contentNodes = [];
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
5560
|
+
const extractBlocks = (nodes) => {
|
|
5561
|
+
for (const item of nodes) {
|
|
5562
|
+
if (!item || !(item instanceof HTMLElement)) continue;
|
|
5563
|
+
const tag = item.tagName.toLowerCase();
|
|
5564
|
+
const hasChildBlocks = Array.from(item.children).some((c) => {
|
|
5565
|
+
const ct = c.tagName.toLowerCase();
|
|
5566
|
+
return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
|
|
5567
|
+
});
|
|
5568
|
+
if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
|
|
5569
|
+
extractBlocks(Array.from(item.children));
|
|
5570
|
+
} else {
|
|
5571
|
+
const svgs = item.querySelectorAll("svg, img");
|
|
5572
|
+
svgs.forEach((s) => {
|
|
5573
|
+
const el = s;
|
|
5574
|
+
el.style.maxWidth = "100%";
|
|
5575
|
+
el.style.maxHeight = "360px";
|
|
5576
|
+
el.style.display = "block";
|
|
5577
|
+
el.style.margin = "12px auto";
|
|
5578
|
+
if (s.tagName.toLowerCase() === "svg") {
|
|
5579
|
+
s.removeAttribute("width");
|
|
5580
|
+
s.removeAttribute("height");
|
|
5581
|
+
el.style.width = "100%";
|
|
5582
|
+
el.style.maxHeight = "360px";
|
|
5583
|
+
}
|
|
5584
|
+
});
|
|
5585
|
+
if (tag === "p" || tag === "div") {
|
|
5586
|
+
item.style.display = "block";
|
|
5587
|
+
item.style.marginBottom = "12px";
|
|
5588
|
+
item.style.lineHeight = "1.6";
|
|
5589
|
+
}
|
|
5590
|
+
contentNodes.push(item);
|
|
5591
|
+
}
|
|
4642
5592
|
}
|
|
4643
|
-
}
|
|
5593
|
+
};
|
|
5594
|
+
extractBlocks(htmlElements);
|
|
5595
|
+
tables.forEach((table) => {
|
|
5596
|
+
const tableEl = renderRtfTableElement(table);
|
|
5597
|
+
let inserted = false;
|
|
5598
|
+
if (table.anchorBefore && table.anchorBefore.length > 10) {
|
|
5599
|
+
const keyword = table.anchorBefore.slice(-35).trim();
|
|
5600
|
+
for (let i = 0; i < contentNodes.length; i++) {
|
|
5601
|
+
if (contentNodes[i].textContent?.includes(keyword)) {
|
|
5602
|
+
contentNodes.splice(i + 1, 0, tableEl);
|
|
5603
|
+
inserted = true;
|
|
5604
|
+
break;
|
|
5605
|
+
}
|
|
5606
|
+
}
|
|
5607
|
+
}
|
|
5608
|
+
if (!inserted && table.anchorAfter && table.anchorAfter.length > 10) {
|
|
5609
|
+
const keyword = table.anchorAfter.slice(0, 35).trim();
|
|
5610
|
+
for (let i = 0; i < contentNodes.length; i++) {
|
|
5611
|
+
if (contentNodes[i].textContent?.includes(keyword)) {
|
|
5612
|
+
contentNodes.splice(i, 0, tableEl);
|
|
5613
|
+
inserted = true;
|
|
5614
|
+
break;
|
|
5615
|
+
}
|
|
5616
|
+
}
|
|
5617
|
+
}
|
|
5618
|
+
if (!inserted) {
|
|
5619
|
+
if (contentNodes.length > 2) {
|
|
5620
|
+
contentNodes.splice(2, 0, tableEl);
|
|
5621
|
+
} else {
|
|
5622
|
+
contentNodes.push(tableEl);
|
|
5623
|
+
}
|
|
5624
|
+
}
|
|
5625
|
+
});
|
|
4644
5626
|
wrapper.innerHTML = "";
|
|
4645
5627
|
contentNodes.forEach((node) => wrapper.appendChild(node));
|
|
4646
5628
|
const childHeights = contentNodes.map((c) => {
|
|
4647
5629
|
const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
|
|
4648
5630
|
const offH = c.offsetHeight || 0;
|
|
5631
|
+
const realH = Math.max(rectH, offH);
|
|
5632
|
+
if (realH > 0) return realH;
|
|
4649
5633
|
const textLen = c.textContent?.trim().length || 0;
|
|
4650
|
-
|
|
4651
|
-
return Math.max(rectH, offH, estH);
|
|
5634
|
+
return Math.max(24, Math.ceil(textLen / 95) * 22 + 12);
|
|
4652
5635
|
});
|
|
4653
5636
|
wrapper.innerHTML = "";
|
|
4654
5637
|
const createRtfCard = () => {
|
|
@@ -4657,35 +5640,49 @@ var RtfPlugin = class {
|
|
|
4657
5640
|
card.style.backgroundColor = "#ffffff";
|
|
4658
5641
|
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
4659
5642
|
card.style.borderRadius = "4px";
|
|
4660
|
-
card.style.padding = "
|
|
5643
|
+
card.style.padding = "64px 56px";
|
|
4661
5644
|
card.style.width = "816px";
|
|
4662
5645
|
card.style.minHeight = "1056px";
|
|
4663
5646
|
card.style.boxSizing = "border-box";
|
|
4664
5647
|
card.style.marginBottom = "24px";
|
|
4665
5648
|
card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4666
5649
|
card.style.lineHeight = "1.6";
|
|
5650
|
+
card.style.color = "#1e293b";
|
|
4667
5651
|
return card;
|
|
4668
5652
|
};
|
|
4669
5653
|
let curCard = createRtfCard();
|
|
4670
5654
|
wrapper.appendChild(curCard);
|
|
4671
5655
|
pageElements = [curCard];
|
|
4672
5656
|
let curH = 0;
|
|
4673
|
-
const maxH =
|
|
5657
|
+
const maxH = 928;
|
|
4674
5658
|
for (let i = 0; i < contentNodes.length; i++) {
|
|
4675
5659
|
const child = contentNodes[i];
|
|
4676
5660
|
const chH = childHeights[i];
|
|
4677
|
-
|
|
4678
|
-
curH
|
|
4679
|
-
|
|
5661
|
+
const isChildEmpty = (child.textContent || "").trim().length === 0 && !child.querySelector("table, img, svg, canvas");
|
|
5662
|
+
if (curH === 0 && isChildEmpty) {
|
|
5663
|
+
continue;
|
|
5664
|
+
}
|
|
5665
|
+
if (curH + chH > maxH && curCard.childNodes.length > 0) {
|
|
4680
5666
|
curCard = createRtfCard();
|
|
4681
5667
|
wrapper.appendChild(curCard);
|
|
4682
5668
|
pageElements.push(curCard);
|
|
4683
5669
|
curH = 0;
|
|
4684
5670
|
}
|
|
5671
|
+
curCard.appendChild(child);
|
|
5672
|
+
curH += chH;
|
|
5673
|
+
}
|
|
5674
|
+
pageElements = pageElements.filter((card) => {
|
|
5675
|
+
const hasText = (card.textContent || "").trim().length > 0;
|
|
5676
|
+
const hasMedia = card.querySelector("table, img, svg, canvas") !== null;
|
|
5677
|
+
return hasText || hasMedia;
|
|
5678
|
+
});
|
|
5679
|
+
if (pageElements.length === 0) {
|
|
5680
|
+
pageElements = [curCard];
|
|
4685
5681
|
}
|
|
4686
5682
|
} catch (err) {
|
|
4687
5683
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
4688
5684
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
5685
|
+
const tables = parseRtfTables(text);
|
|
4689
5686
|
const rawPages = text.split(/\\page\b/).map((segment) => {
|
|
4690
5687
|
return segment.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "").trim();
|
|
4691
5688
|
}).filter((p) => p.length > 0);
|
|
@@ -4696,47 +5693,26 @@ var RtfPlugin = class {
|
|
|
4696
5693
|
pageCard.style.backgroundColor = "#ffffff";
|
|
4697
5694
|
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4698
5695
|
pageCard.style.borderRadius = "4px";
|
|
4699
|
-
pageCard.style.padding = "
|
|
5696
|
+
pageCard.style.padding = "64px 56px";
|
|
4700
5697
|
pageCard.style.width = "816px";
|
|
4701
5698
|
pageCard.style.minHeight = "1056px";
|
|
4702
|
-
pageCard.style.maxWidth = "100%";
|
|
4703
5699
|
pageCard.style.boxSizing = "border-box";
|
|
4704
|
-
pageCard.style.fontFamily = "serif
|
|
5700
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4705
5701
|
pageCard.style.fontSize = "12pt";
|
|
4706
5702
|
pageCard.style.lineHeight = "1.6";
|
|
4707
5703
|
pageCard.style.color = "#1e293b";
|
|
4708
5704
|
pageCard.style.whiteSpace = "pre-wrap";
|
|
4709
5705
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4710
5706
|
pageCard.textContent = pages[i];
|
|
5707
|
+
if (i === 1 && tables.length > 0) {
|
|
5708
|
+
tables.forEach((tbl) => pageCard.appendChild(renderRtfTableElement(tbl)));
|
|
5709
|
+
}
|
|
4711
5710
|
wrapper.appendChild(pageCard);
|
|
4712
5711
|
pageElements.push(pageCard);
|
|
4713
5712
|
}
|
|
4714
5713
|
}
|
|
4715
5714
|
const totalPages = Math.max(1, pageElements.length);
|
|
4716
5715
|
let currentPage = 1;
|
|
4717
|
-
let indicator = null;
|
|
4718
|
-
if (totalPages > 1) {
|
|
4719
|
-
indicator = document.createElement("div");
|
|
4720
|
-
indicator.className = "fp-rtf-page-indicator";
|
|
4721
|
-
indicator.style.position = "sticky";
|
|
4722
|
-
indicator.style.bottom = "16px";
|
|
4723
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4724
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
4725
|
-
indicator.style.color = "#f8fafc";
|
|
4726
|
-
indicator.style.fontSize = "12px";
|
|
4727
|
-
indicator.style.fontWeight = "600";
|
|
4728
|
-
indicator.style.padding = "5px 14px";
|
|
4729
|
-
indicator.style.borderRadius = "20px";
|
|
4730
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4731
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4732
|
-
indicator.style.zIndex = "10";
|
|
4733
|
-
indicator.style.userSelect = "none";
|
|
4734
|
-
indicator.style.pointerEvents = "none";
|
|
4735
|
-
indicator.style.textAlign = "center";
|
|
4736
|
-
indicator.style.width = "fit-content";
|
|
4737
|
-
indicator.style.margin = "16px auto 0";
|
|
4738
|
-
ctx.container.appendChild(indicator);
|
|
4739
|
-
}
|
|
4740
5716
|
const showPage = (pageNum) => {
|
|
4741
5717
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4742
5718
|
if (totalPages > 1) {
|
|
@@ -4744,9 +5720,6 @@ var RtfPlugin = class {
|
|
|
4744
5720
|
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4745
5721
|
});
|
|
4746
5722
|
}
|
|
4747
|
-
if (indicator) {
|
|
4748
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4749
|
-
}
|
|
4750
5723
|
ctx.container.scrollTop = 0;
|
|
4751
5724
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4752
5725
|
};
|
|
@@ -4754,7 +5727,7 @@ var RtfPlugin = class {
|
|
|
4754
5727
|
showPage(1);
|
|
4755
5728
|
}
|
|
4756
5729
|
const cleanup = () => {
|
|
4757
|
-
|
|
5730
|
+
resizeObserver?.disconnect();
|
|
4758
5731
|
wrapper.remove();
|
|
4759
5732
|
ctx.container.innerHTML = "";
|
|
4760
5733
|
};
|
|
@@ -4764,22 +5737,52 @@ var RtfPlugin = class {
|
|
|
4764
5737
|
getPageCount: () => totalPages,
|
|
4765
5738
|
getCurrentPage: () => currentPage,
|
|
4766
5739
|
goToPage: (page) => showPage(page),
|
|
5740
|
+
getThumbnails: async () => {
|
|
5741
|
+
const items = [];
|
|
5742
|
+
for (let idx = 0; idx < totalPages; idx++) {
|
|
5743
|
+
const pageIdx = idx;
|
|
5744
|
+
items.push({
|
|
5745
|
+
index: pageIdx,
|
|
5746
|
+
label: `Page ${pageIdx + 1}`,
|
|
5747
|
+
render: async (canvas) => {
|
|
5748
|
+
const ctx2d = canvas.getContext("2d");
|
|
5749
|
+
if (!ctx2d) return;
|
|
5750
|
+
canvas.width = 140;
|
|
5751
|
+
canvas.height = 180;
|
|
5752
|
+
ctx2d.fillStyle = "#ffffff";
|
|
5753
|
+
ctx2d.fillRect(0, 0, 140, 180);
|
|
5754
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
5755
|
+
ctx2d.lineWidth = 1;
|
|
5756
|
+
ctx2d.strokeRect(0.5, 0.5, 139, 179);
|
|
5757
|
+
ctx2d.fillStyle = "#334155";
|
|
5758
|
+
ctx2d.font = 'bold 11px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
5759
|
+
ctx2d.textAlign = "center";
|
|
5760
|
+
ctx2d.fillText(`Page ${pageIdx + 1}`, 70, 95);
|
|
5761
|
+
}
|
|
5762
|
+
});
|
|
5763
|
+
}
|
|
5764
|
+
return items;
|
|
5765
|
+
},
|
|
4767
5766
|
zoomIn: () => {
|
|
5767
|
+
isUserZoomed = true;
|
|
4768
5768
|
scale += 0.15;
|
|
4769
5769
|
applyTransform();
|
|
4770
5770
|
},
|
|
4771
5771
|
zoomOut: () => {
|
|
5772
|
+
isUserZoomed = true;
|
|
4772
5773
|
scale = Math.max(0.2, scale - 0.15);
|
|
4773
5774
|
applyTransform();
|
|
4774
5775
|
},
|
|
4775
5776
|
getZoom: () => scale,
|
|
4776
5777
|
setZoom: (level) => {
|
|
5778
|
+
isUserZoomed = true;
|
|
4777
5779
|
scale = level;
|
|
4778
5780
|
applyTransform();
|
|
4779
5781
|
},
|
|
4780
5782
|
fitToPage: () => {
|
|
4781
|
-
|
|
4782
|
-
|
|
5783
|
+
isUserZoomed = false;
|
|
5784
|
+
fitMode = "width";
|
|
5785
|
+
scale = calculateFitScale("width");
|
|
4783
5786
|
rotation = 0;
|
|
4784
5787
|
applyTransform();
|
|
4785
5788
|
},
|
|
@@ -4967,40 +5970,36 @@ var OpenDocumentPlugin = class {
|
|
|
4967
5970
|
const isPresentation = instance.isPresentation;
|
|
4968
5971
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4969
5972
|
const actions = [];
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
max
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
if (
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
instance.goToPage?.(page);
|
|
4998
|
-
} else if (typeof action === "number") {
|
|
4999
|
-
instance.goToPage?.(action);
|
|
5000
|
-
}
|
|
5973
|
+
actions.push({
|
|
5974
|
+
id: "thumbnails",
|
|
5975
|
+
icon: "thumbnails",
|
|
5976
|
+
label: isPresentation ? "Slide Thumbnails" : "Page Thumbnails",
|
|
5977
|
+
type: "button",
|
|
5978
|
+
group: "navigation",
|
|
5979
|
+
execute: () => instance.toggleThumbnails?.()
|
|
5980
|
+
});
|
|
5981
|
+
actions.push({
|
|
5982
|
+
id: "page-nav",
|
|
5983
|
+
icon: "",
|
|
5984
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
5985
|
+
type: "page-nav",
|
|
5986
|
+
group: "navigation",
|
|
5987
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5988
|
+
max: totalPages,
|
|
5989
|
+
execute: (action, page) => {
|
|
5990
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5991
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5992
|
+
if (action === "prev") {
|
|
5993
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5994
|
+
} else if (action === "next") {
|
|
5995
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5996
|
+
} else if (typeof page === "number") {
|
|
5997
|
+
instance.goToPage?.(page);
|
|
5998
|
+
} else if (typeof action === "number") {
|
|
5999
|
+
instance.goToPage?.(action);
|
|
5001
6000
|
}
|
|
5002
|
-
}
|
|
5003
|
-
}
|
|
6001
|
+
}
|
|
6002
|
+
});
|
|
5004
6003
|
actions.push(
|
|
5005
6004
|
{
|
|
5006
6005
|
id: "zoom-out",
|
|
@@ -5091,49 +6090,65 @@ var OpenDocumentPlugin = class {
|
|
|
5091
6090
|
container.className = "fp-odf-container";
|
|
5092
6091
|
container.style.width = "100%";
|
|
5093
6092
|
container.style.height = "100%";
|
|
5094
|
-
container.style.
|
|
5095
|
-
container.style.
|
|
6093
|
+
container.style.overflowX = "hidden";
|
|
6094
|
+
container.style.overflowY = "auto";
|
|
6095
|
+
container.style.padding = "16px 8px";
|
|
5096
6096
|
container.style.backgroundColor = "#f1f5f9";
|
|
5097
6097
|
const wrapper = document.createElement("div");
|
|
5098
6098
|
wrapper.className = "fp-odf-wrapper";
|
|
5099
6099
|
wrapper.style.margin = "0 auto";
|
|
6100
|
+
wrapper.style.width = isPresentation ? "960px" : "816px";
|
|
6101
|
+
wrapper.style.boxSizing = "border-box";
|
|
5100
6102
|
wrapper.style.backgroundColor = "#ffffff";
|
|
5101
6103
|
wrapper.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
5102
6104
|
wrapper.style.borderRadius = "4px";
|
|
5103
6105
|
wrapper.style.transformOrigin = "top center";
|
|
5104
|
-
wrapper.style.transition = "transform 0.
|
|
6106
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5105
6107
|
container.appendChild(wrapper);
|
|
5106
6108
|
ctx.container.appendChild(container);
|
|
5107
6109
|
let scale = 1;
|
|
5108
6110
|
let rotation = 0;
|
|
5109
|
-
let
|
|
6111
|
+
let isUserZoomed = false;
|
|
6112
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6113
|
+
let currentPage = 1;
|
|
6114
|
+
let totalPages = 1;
|
|
6115
|
+
let slides = [];
|
|
5110
6116
|
const calculateFitScale = (mode = fitMode) => {
|
|
5111
|
-
const
|
|
5112
|
-
const
|
|
5113
|
-
const
|
|
5114
|
-
const
|
|
6117
|
+
const activeSlide = slides[currentPage - 1];
|
|
6118
|
+
const elW = isPresentation ? 960 : 816;
|
|
6119
|
+
const singlePageH = Math.min(activeSlide?.offsetHeight || wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
6120
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6121
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5115
6122
|
const sW = availW / elW;
|
|
5116
6123
|
const sH = availH / (isPresentation ? 540 : singlePageH);
|
|
5117
6124
|
if (isPresentation) {
|
|
5118
|
-
return Math.min(
|
|
6125
|
+
return Math.min(2.5, Math.min(sW, sH));
|
|
5119
6126
|
}
|
|
5120
6127
|
if (mode === "page") {
|
|
5121
|
-
return Math.max(0.
|
|
6128
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5122
6129
|
}
|
|
5123
|
-
return Math.max(0.
|
|
6130
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5124
6131
|
};
|
|
5125
6132
|
const applyTransform = () => {
|
|
5126
6133
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5127
6134
|
wrapper.style.transformOrigin = "top center";
|
|
6135
|
+
const activeSlide = slides[currentPage - 1];
|
|
6136
|
+
const baseH = activeSlide?.offsetHeight || wrapper.offsetHeight || 1056;
|
|
6137
|
+
const scaledH = baseH * scale;
|
|
6138
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6139
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
5128
6140
|
};
|
|
6141
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6142
|
+
if (!isUserZoomed) {
|
|
6143
|
+
scale = calculateFitScale(fitMode);
|
|
6144
|
+
applyTransform();
|
|
6145
|
+
}
|
|
6146
|
+
}) : null;
|
|
6147
|
+
resizeObserver?.observe(ctx.container);
|
|
5129
6148
|
setTimeout(() => {
|
|
5130
|
-
|
|
5131
|
-
scale = calculateFitScale("width");
|
|
6149
|
+
scale = calculateFitScale(fitMode);
|
|
5132
6150
|
applyTransform();
|
|
5133
6151
|
}, 60);
|
|
5134
|
-
let currentPage = 1;
|
|
5135
|
-
let totalPages = 1;
|
|
5136
|
-
let slides = [];
|
|
5137
6152
|
if (isPresentation) {
|
|
5138
6153
|
wrapper.style.maxWidth = "960px";
|
|
5139
6154
|
wrapper.style.aspectRatio = "16 / 9";
|
|
@@ -5234,24 +6249,9 @@ var OpenDocumentPlugin = class {
|
|
|
5234
6249
|
wrapper.appendChild(page);
|
|
5235
6250
|
slides.push(page);
|
|
5236
6251
|
});
|
|
5237
|
-
const pageIndicator = document.createElement("div");
|
|
5238
|
-
pageIndicator.className = "fp-odt-page-indicator";
|
|
5239
|
-
pageIndicator.style.position = "sticky";
|
|
5240
|
-
pageIndicator.style.bottom = "16px";
|
|
5241
|
-
pageIndicator.style.left = "50%";
|
|
5242
|
-
pageIndicator.style.transform = "translateX(-50%)";
|
|
5243
|
-
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
5244
|
-
pageIndicator.style.color = "#fff";
|
|
5245
|
-
pageIndicator.style.padding = "6px 12px";
|
|
5246
|
-
pageIndicator.style.borderRadius = "16px";
|
|
5247
|
-
pageIndicator.style.fontSize = "12px";
|
|
5248
|
-
pageIndicator.style.zIndex = "100";
|
|
5249
|
-
pageIndicator.style.display = "inline-block";
|
|
5250
|
-
pageIndicator.style.width = "fit-content";
|
|
5251
|
-
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
5252
|
-
container.appendChild(pageIndicator);
|
|
5253
6252
|
}
|
|
5254
6253
|
const cleanup = () => {
|
|
6254
|
+
resizeObserver?.disconnect();
|
|
5255
6255
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
5256
6256
|
container.remove();
|
|
5257
6257
|
ctx.container.innerHTML = "";
|
|
@@ -5263,10 +6263,6 @@ var OpenDocumentPlugin = class {
|
|
|
5263
6263
|
slides.forEach((s, idx) => {
|
|
5264
6264
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
5265
6265
|
});
|
|
5266
|
-
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
5267
|
-
if (indicator) {
|
|
5268
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5269
|
-
}
|
|
5270
6266
|
container.scrollTop = 0;
|
|
5271
6267
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5272
6268
|
};
|
|
@@ -5274,21 +6270,25 @@ var OpenDocumentPlugin = class {
|
|
|
5274
6270
|
destroy: cleanup,
|
|
5275
6271
|
isPresentation,
|
|
5276
6272
|
zoomIn: () => {
|
|
6273
|
+
isUserZoomed = true;
|
|
5277
6274
|
scale += 0.15;
|
|
5278
6275
|
applyTransform();
|
|
5279
6276
|
},
|
|
5280
6277
|
zoomOut: () => {
|
|
6278
|
+
isUserZoomed = true;
|
|
5281
6279
|
scale = Math.max(0.2, scale - 0.15);
|
|
5282
6280
|
applyTransform();
|
|
5283
6281
|
},
|
|
5284
6282
|
getZoom: () => scale,
|
|
5285
6283
|
setZoom: (level) => {
|
|
6284
|
+
isUserZoomed = true;
|
|
5286
6285
|
scale = level;
|
|
5287
6286
|
applyTransform();
|
|
5288
6287
|
},
|
|
5289
6288
|
fitToPage: () => {
|
|
5290
|
-
|
|
5291
|
-
|
|
6289
|
+
isUserZoomed = false;
|
|
6290
|
+
fitMode = "width";
|
|
6291
|
+
scale = calculateFitScale("width");
|
|
5292
6292
|
rotation = 0;
|
|
5293
6293
|
applyTransform();
|
|
5294
6294
|
},
|
|
@@ -5304,23 +6304,45 @@ var OpenDocumentPlugin = class {
|
|
|
5304
6304
|
getPageCount: () => totalPages,
|
|
5305
6305
|
getCurrentPage: () => currentPage,
|
|
5306
6306
|
getThumbnails: async () => {
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
canvas
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
6307
|
+
const count = totalPages || slides.length || 1;
|
|
6308
|
+
const items = [];
|
|
6309
|
+
for (let idx = 0; idx < count; idx++) {
|
|
6310
|
+
const itemIdx = idx;
|
|
6311
|
+
items.push({
|
|
6312
|
+
index: itemIdx,
|
|
6313
|
+
label: isPresentation ? `Slide ${itemIdx + 1}` : `Page ${itemIdx + 1}`,
|
|
6314
|
+
render: async (canvas) => {
|
|
6315
|
+
const ctx2d = canvas.getContext("2d");
|
|
6316
|
+
if (!ctx2d) return;
|
|
6317
|
+
if (isPresentation) {
|
|
6318
|
+
canvas.width = 160;
|
|
6319
|
+
canvas.height = 90;
|
|
6320
|
+
ctx2d.fillStyle = "#f8fafc";
|
|
6321
|
+
ctx2d.fillRect(0, 0, 160, 90);
|
|
6322
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6323
|
+
ctx2d.lineWidth = 1;
|
|
6324
|
+
ctx2d.strokeRect(0.5, 0.5, 159, 89);
|
|
6325
|
+
ctx2d.fillStyle = "#334155";
|
|
6326
|
+
ctx2d.font = "bold 11px sans-serif";
|
|
6327
|
+
ctx2d.textAlign = "center";
|
|
6328
|
+
ctx2d.fillText(`Slide ${itemIdx + 1}`, 80, 50);
|
|
6329
|
+
} else {
|
|
6330
|
+
canvas.width = 140;
|
|
6331
|
+
canvas.height = 180;
|
|
6332
|
+
ctx2d.fillStyle = "#ffffff";
|
|
6333
|
+
ctx2d.fillRect(0, 0, 140, 180);
|
|
6334
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6335
|
+
ctx2d.lineWidth = 1;
|
|
6336
|
+
ctx2d.strokeRect(0.5, 0.5, 139, 179);
|
|
6337
|
+
ctx2d.fillStyle = "#64748b";
|
|
6338
|
+
ctx2d.font = "bold 10px sans-serif";
|
|
6339
|
+
ctx2d.textAlign = "center";
|
|
6340
|
+
ctx2d.fillText(`Page ${itemIdx + 1}`, 70, 90);
|
|
6341
|
+
}
|
|
6342
|
+
}
|
|
6343
|
+
});
|
|
6344
|
+
}
|
|
6345
|
+
return items;
|
|
5324
6346
|
},
|
|
5325
6347
|
download: () => {
|
|
5326
6348
|
const mimeType = this.mimeTypes.find((m) => m.includes(ext.replace(".", ""))) || "application/octet-stream";
|
|
@@ -5425,23 +6447,24 @@ var OpenDocumentPlugin = class {
|
|
|
5425
6447
|
case "h": {
|
|
5426
6448
|
const level = Math.min(6, Math.max(1, Number(node.getAttribute("text:outline-level") || 1)));
|
|
5427
6449
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5428
|
-
html += `<h${level} style="${style}; font-family:
|
|
6450
|
+
html += `<h${level} style="${style}; margin: 18px 0 8px; color: #1e3a8a; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${node.textContent || ""}</h${level}>`;
|
|
5429
6451
|
break;
|
|
5430
6452
|
}
|
|
5431
6453
|
case "p": {
|
|
5432
6454
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5433
6455
|
const inner = this.renderSpans(node, styles, images);
|
|
5434
|
-
|
|
6456
|
+
const isInsideLi = node.parentElement?.localName === "list-item" || node.parentElement?.tagName?.toLowerCase() === "list-item";
|
|
6457
|
+
html += `<p style="${style}; line-height: 1.5; margin: ${isInsideLi ? "0" : "8px 0 12px"}; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${inner}</p>`;
|
|
5435
6458
|
break;
|
|
5436
6459
|
}
|
|
5437
6460
|
case "list": {
|
|
5438
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
6461
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
5439
6462
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5440
6463
|
html += "</ul>";
|
|
5441
6464
|
break;
|
|
5442
6465
|
}
|
|
5443
6466
|
case "list-item": {
|
|
5444
|
-
html +=
|
|
6467
|
+
html += '<li style="margin: 4px 0; font-size: 11pt; line-height: 1.5; color: #1e293b;">';
|
|
5445
6468
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5446
6469
|
html += "</li>";
|
|
5447
6470
|
break;
|
|
@@ -5567,28 +6590,26 @@ var DocPlugin = class {
|
|
|
5567
6590
|
getToolbarActions(instance) {
|
|
5568
6591
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5569
6592
|
const actions = [];
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
if (
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
instance.goToPage?.(page);
|
|
5588
|
-
}
|
|
6593
|
+
actions.push({
|
|
6594
|
+
id: "page-nav",
|
|
6595
|
+
icon: "",
|
|
6596
|
+
label: "Page Navigation",
|
|
6597
|
+
type: "page-nav",
|
|
6598
|
+
group: "navigation",
|
|
6599
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
6600
|
+
max: totalPages,
|
|
6601
|
+
execute: (action, page) => {
|
|
6602
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
6603
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
6604
|
+
if (action === "prev") {
|
|
6605
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
6606
|
+
} else if (action === "next") {
|
|
6607
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
6608
|
+
} else if (typeof page === "number") {
|
|
6609
|
+
instance.goToPage?.(page);
|
|
5589
6610
|
}
|
|
5590
|
-
}
|
|
5591
|
-
}
|
|
6611
|
+
}
|
|
6612
|
+
});
|
|
5592
6613
|
actions.push(
|
|
5593
6614
|
{
|
|
5594
6615
|
id: "zoom-out",
|
|
@@ -5662,8 +6683,9 @@ var DocPlugin = class {
|
|
|
5662
6683
|
container.className = "fp-doc-container";
|
|
5663
6684
|
container.style.width = "100%";
|
|
5664
6685
|
container.style.height = "100%";
|
|
5665
|
-
container.style.
|
|
5666
|
-
container.style.
|
|
6686
|
+
container.style.overflowX = "hidden";
|
|
6687
|
+
container.style.overflowY = "auto";
|
|
6688
|
+
container.style.padding = "16px 8px";
|
|
5667
6689
|
container.style.backgroundColor = "#f1f5f9";
|
|
5668
6690
|
container.style.display = "flex";
|
|
5669
6691
|
container.style.justifyContent = "center";
|
|
@@ -5708,16 +6730,15 @@ var DocPlugin = class {
|
|
|
5708
6730
|
const pageCard = document.createElement("div");
|
|
5709
6731
|
pageCard.className = "fp-doc-page-card";
|
|
5710
6732
|
pageCard.style.width = "816px";
|
|
5711
|
-
pageCard.style.
|
|
6733
|
+
pageCard.style.minHeight = "1056px";
|
|
5712
6734
|
pageCard.style.backgroundColor = "#ffffff";
|
|
5713
|
-
pageCard.style.boxShadow = "0
|
|
6735
|
+
pageCard.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
5714
6736
|
pageCard.style.borderRadius = "4px";
|
|
5715
|
-
pageCard.style.padding = "
|
|
6737
|
+
pageCard.style.padding = "72px 56px";
|
|
5716
6738
|
pageCard.style.boxSizing = "border-box";
|
|
5717
|
-
pageCard.style.overflow = "hidden";
|
|
5718
6739
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5719
6740
|
pageCard.style.transformOrigin = "top center";
|
|
5720
|
-
pageCard.style.transition = "transform 0.
|
|
6741
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
5721
6742
|
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5722
6743
|
pageCard.style.color = "#1e293b";
|
|
5723
6744
|
if (isFallback && i === 0) {
|
|
@@ -5734,34 +6755,15 @@ var DocPlugin = class {
|
|
|
5734
6755
|
container.appendChild(pageCard);
|
|
5735
6756
|
pageCards.push(pageCard);
|
|
5736
6757
|
}
|
|
5737
|
-
let indicator = null;
|
|
5738
|
-
if (totalPages > 1) {
|
|
5739
|
-
indicator = document.createElement("div");
|
|
5740
|
-
indicator.className = "fp-doc-page-indicator";
|
|
5741
|
-
indicator.style.position = "fixed";
|
|
5742
|
-
indicator.style.bottom = "16px";
|
|
5743
|
-
indicator.style.left = "50%";
|
|
5744
|
-
indicator.style.transform = "translateX(-50%)";
|
|
5745
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
5746
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
5747
|
-
indicator.style.color = "#f8fafc";
|
|
5748
|
-
indicator.style.fontSize = "12px";
|
|
5749
|
-
indicator.style.fontWeight = "600";
|
|
5750
|
-
indicator.style.padding = "5px 14px";
|
|
5751
|
-
indicator.style.borderRadius = "20px";
|
|
5752
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
5753
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
5754
|
-
indicator.style.zIndex = "10";
|
|
5755
|
-
indicator.style.userSelect = "none";
|
|
5756
|
-
indicator.style.pointerEvents = "none";
|
|
5757
|
-
indicator.style.textAlign = "center";
|
|
5758
|
-
container.appendChild(indicator);
|
|
5759
|
-
}
|
|
5760
6758
|
let rotation = 0;
|
|
5761
6759
|
const applyTransform = () => {
|
|
5762
6760
|
const activeCard = pageCards[currentPage - 1];
|
|
5763
6761
|
if (activeCard) {
|
|
5764
6762
|
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
6763
|
+
const baseH = activeCard.offsetHeight || 1056;
|
|
6764
|
+
const scaledH = baseH * scale;
|
|
6765
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6766
|
+
activeCard.style.marginBottom = `${extraH + 32}px`;
|
|
5765
6767
|
}
|
|
5766
6768
|
};
|
|
5767
6769
|
const showPage = (pageNum) => {
|
|
@@ -5774,35 +6776,39 @@ var DocPlugin = class {
|
|
|
5774
6776
|
card.style.display = "none";
|
|
5775
6777
|
}
|
|
5776
6778
|
});
|
|
5777
|
-
if (indicator) {
|
|
5778
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5779
|
-
}
|
|
5780
6779
|
container.scrollTop = 0;
|
|
5781
6780
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5782
6781
|
};
|
|
5783
6782
|
if (totalPages > 1) {
|
|
5784
6783
|
showPage(1);
|
|
5785
6784
|
}
|
|
5786
|
-
let fitMode = "width";
|
|
6785
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6786
|
+
let isUserZoomed = false;
|
|
5787
6787
|
const calculateFitScale = (mode = fitMode) => {
|
|
5788
6788
|
const elW = 816;
|
|
5789
6789
|
const elH = 1056;
|
|
5790
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
5791
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
6790
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6791
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5792
6792
|
const sW = availW / elW;
|
|
5793
6793
|
const sH = availH / elH;
|
|
5794
6794
|
if (mode === "page") {
|
|
5795
|
-
return Math.max(0.
|
|
6795
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5796
6796
|
}
|
|
5797
|
-
return Math.max(0.
|
|
6797
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5798
6798
|
};
|
|
6799
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6800
|
+
if (!isUserZoomed) {
|
|
6801
|
+
scale = calculateFitScale(fitMode);
|
|
6802
|
+
applyTransform();
|
|
6803
|
+
}
|
|
6804
|
+
}) : null;
|
|
6805
|
+
resizeObserver?.observe(ctx.container);
|
|
5799
6806
|
setTimeout(() => {
|
|
5800
|
-
|
|
5801
|
-
scale = calculateFitScale("width");
|
|
6807
|
+
scale = calculateFitScale(fitMode);
|
|
5802
6808
|
applyTransform();
|
|
5803
6809
|
}, 60);
|
|
5804
6810
|
const cleanup = () => {
|
|
5805
|
-
|
|
6811
|
+
resizeObserver?.disconnect();
|
|
5806
6812
|
container.remove();
|
|
5807
6813
|
ctx.container.innerHTML = "";
|
|
5808
6814
|
};
|
|
@@ -5813,21 +6819,25 @@ var DocPlugin = class {
|
|
|
5813
6819
|
getCurrentPage: () => currentPage,
|
|
5814
6820
|
goToPage: (page) => showPage(page),
|
|
5815
6821
|
zoomIn: () => {
|
|
6822
|
+
isUserZoomed = true;
|
|
5816
6823
|
scale += 0.15;
|
|
5817
6824
|
applyTransform();
|
|
5818
6825
|
},
|
|
5819
6826
|
zoomOut: () => {
|
|
6827
|
+
isUserZoomed = true;
|
|
5820
6828
|
scale = Math.max(0.2, scale - 0.15);
|
|
5821
6829
|
applyTransform();
|
|
5822
6830
|
},
|
|
5823
6831
|
getZoom: () => scale,
|
|
5824
6832
|
setZoom: (level) => {
|
|
6833
|
+
isUserZoomed = true;
|
|
5825
6834
|
scale = level;
|
|
5826
6835
|
applyTransform();
|
|
5827
6836
|
},
|
|
5828
6837
|
fitToPage: () => {
|
|
5829
|
-
|
|
5830
|
-
|
|
6838
|
+
isUserZoomed = false;
|
|
6839
|
+
fitMode = "width";
|
|
6840
|
+
scale = calculateFitScale("width");
|
|
5831
6841
|
rotation = 0;
|
|
5832
6842
|
applyTransform();
|
|
5833
6843
|
},
|
|
@@ -6204,25 +7214,31 @@ ${chartSvg}
|
|
|
6204
7214
|
i++;
|
|
6205
7215
|
continue;
|
|
6206
7216
|
}
|
|
6207
|
-
if (
|
|
7217
|
+
if (/^\d{1,2}$/.test(line.trim())) {
|
|
7218
|
+
i++;
|
|
7219
|
+
continue;
|
|
7220
|
+
}
|
|
7221
|
+
const isShortLine = line.length < 60 && !line.endsWith(".") && !line.endsWith(",");
|
|
7222
|
+
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));
|
|
7223
|
+
if (isTitleLike) {
|
|
6208
7224
|
if (inList) {
|
|
6209
7225
|
html += "</ul>";
|
|
6210
7226
|
inList = false;
|
|
6211
7227
|
}
|
|
6212
|
-
html += `<h2 style="font-size:
|
|
7228
|
+
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>`;
|
|
6213
7229
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
6214
7230
|
if (!inList) {
|
|
6215
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
7231
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
6216
7232
|
inList = true;
|
|
6217
7233
|
}
|
|
6218
7234
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
6219
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
7235
|
+
html += `<li style="margin: 4px 0; line-height: 1.5; font-size: 11pt; color: #1e293b;">${DOMPurify6.sanitize(bulletText, sanitizeOptions)}</li>`;
|
|
6220
7236
|
} else {
|
|
6221
7237
|
if (inList) {
|
|
6222
7238
|
html += "</ul>";
|
|
6223
7239
|
inList = false;
|
|
6224
7240
|
}
|
|
6225
|
-
html += `<p style="line-height: 1.
|
|
7241
|
+
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>`;
|
|
6226
7242
|
}
|
|
6227
7243
|
i++;
|
|
6228
7244
|
}
|
|
@@ -6784,6 +7800,8 @@ var FilePreview = memo(forwardRef(
|
|
|
6784
7800
|
onError,
|
|
6785
7801
|
onPageChange,
|
|
6786
7802
|
onZoomChange,
|
|
7803
|
+
onRotate,
|
|
7804
|
+
onDestroy,
|
|
6787
7805
|
className,
|
|
6788
7806
|
style
|
|
6789
7807
|
}, ref) => {
|
|
@@ -6806,6 +7824,8 @@ var FilePreview = memo(forwardRef(
|
|
|
6806
7824
|
if (onError) unsubs.push(viewer.on("error", (e) => onError(e instanceof Error ? e : new Error(String(e)))));
|
|
6807
7825
|
if (onPageChange) unsubs.push(viewer.on("page-change", onPageChange));
|
|
6808
7826
|
if (onZoomChange) unsubs.push(viewer.on("zoom-change", onZoomChange));
|
|
7827
|
+
if (onRotate) unsubs.push(viewer.on("rotate", onRotate));
|
|
7828
|
+
if (onDestroy) unsubs.push(viewer.on("destroy", onDestroy));
|
|
6809
7829
|
return () => {
|
|
6810
7830
|
unsubs.forEach((fn) => fn());
|
|
6811
7831
|
viewer.destroy();
|