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