@files-preview-app/preview-file 1.3.0 → 1.3.2
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 +69 -0
- package/dist/angular.cjs +1477 -482
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.d.cts +1 -1
- package/dist/angular.d.ts +1 -1
- package/dist/angular.js +1477 -482
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +1477 -482
- 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 +1477 -482
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +1477 -482
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -16
- package/dist/react.d.ts +1 -16
- package/dist/react.js +1477 -482
- package/dist/react.js.map +1 -1
- package/dist/styles.css +195 -14
- package/dist/vue.cjs +1477 -482
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.d.cts +1 -1
- package/dist/vue.d.ts +1 -1
- package/dist/vue.js +1477 -482
- package/dist/vue.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -38,6 +38,7 @@ function _interopNamespace(e) {
|
|
|
38
38
|
var DOMPurify6__default = /*#__PURE__*/_interopDefault(DOMPurify6);
|
|
39
39
|
var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
|
|
40
40
|
var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
41
|
+
var fflate__namespace = /*#__PURE__*/_interopNamespace(fflate);
|
|
41
42
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
42
43
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
43
44
|
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
@@ -608,8 +609,7 @@ var ICON_FULLSCREEN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="non
|
|
|
608
609
|
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>`;
|
|
609
610
|
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>`;
|
|
610
611
|
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>`;
|
|
611
|
-
var
|
|
612
|
-
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>`;
|
|
612
|
+
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>`;
|
|
613
613
|
var ICON_MAP = {
|
|
614
614
|
"zoom-in": ICON_ZOOM_IN,
|
|
615
615
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -636,28 +636,177 @@ var ICON_MAP = {
|
|
|
636
636
|
"forward-10": ICON_FAST_FORWARD,
|
|
637
637
|
"rewind": ICON_REWIND,
|
|
638
638
|
"replay-10": ICON_REWIND,
|
|
639
|
-
"speed": ICON_SPEED,
|
|
640
639
|
"open-window": ICON_EXTERNAL_WINDOW,
|
|
641
|
-
"external-window": ICON_EXTERNAL_WINDOW
|
|
640
|
+
"external-window": ICON_EXTERNAL_WINDOW,
|
|
641
|
+
"openWindow": ICON_EXTERNAL_WINDOW,
|
|
642
|
+
"openSeparateWindow": ICON_EXTERNAL_WINDOW
|
|
642
643
|
};
|
|
643
644
|
var ToolbarController = class {
|
|
644
645
|
el;
|
|
645
646
|
toolbarEl;
|
|
646
647
|
actions = [];
|
|
648
|
+
config = {};
|
|
647
649
|
pageInputEl = null;
|
|
648
650
|
pageLabelEl = null;
|
|
649
|
-
|
|
651
|
+
prevPageBtn = null;
|
|
652
|
+
nextPageBtn = null;
|
|
653
|
+
constructor(container, config) {
|
|
650
654
|
this.el = container;
|
|
655
|
+
if (config) this.config = { ...config };
|
|
651
656
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
652
657
|
this.el.appendChild(this.toolbarEl);
|
|
653
658
|
}
|
|
659
|
+
setConfig(config) {
|
|
660
|
+
this.config = { ...config };
|
|
661
|
+
this.render();
|
|
662
|
+
}
|
|
663
|
+
getConfig() {
|
|
664
|
+
return { ...this.config };
|
|
665
|
+
}
|
|
666
|
+
hideAction(actionId) {
|
|
667
|
+
this.config[actionId] = false;
|
|
668
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = false;
|
|
669
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = false;
|
|
670
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
671
|
+
this.config.fitPage = false;
|
|
672
|
+
this.config.fitToPage = false;
|
|
673
|
+
this.config.fitWidth = false;
|
|
674
|
+
}
|
|
675
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = false;
|
|
676
|
+
if (actionId === "fullscreen") this.config.fullscreen = false;
|
|
677
|
+
if (actionId === "download") this.config.download = false;
|
|
678
|
+
if (actionId === "print") this.config.print = false;
|
|
679
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
680
|
+
this.config.openWindow = false;
|
|
681
|
+
this.config.openSeparateWindow = false;
|
|
682
|
+
}
|
|
683
|
+
if (actionId === "copy") this.config.copy = false;
|
|
684
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
685
|
+
this.config.pageNav = false;
|
|
686
|
+
this.config.pagination = false;
|
|
687
|
+
}
|
|
688
|
+
this.render();
|
|
689
|
+
}
|
|
690
|
+
showAction(actionId) {
|
|
691
|
+
this.config[actionId] = true;
|
|
692
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = true;
|
|
693
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = true;
|
|
694
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
695
|
+
this.config.fitPage = true;
|
|
696
|
+
this.config.fitToPage = true;
|
|
697
|
+
this.config.fitWidth = true;
|
|
698
|
+
}
|
|
699
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = true;
|
|
700
|
+
if (actionId === "fullscreen") this.config.fullscreen = true;
|
|
701
|
+
if (actionId === "download") this.config.download = true;
|
|
702
|
+
if (actionId === "print") this.config.print = true;
|
|
703
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
704
|
+
this.config.openWindow = true;
|
|
705
|
+
this.config.openSeparateWindow = true;
|
|
706
|
+
}
|
|
707
|
+
if (actionId === "copy") this.config.copy = true;
|
|
708
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
709
|
+
this.config.pageNav = true;
|
|
710
|
+
this.config.pagination = true;
|
|
711
|
+
}
|
|
712
|
+
this.render();
|
|
713
|
+
}
|
|
714
|
+
normalizeActionId(actionId) {
|
|
715
|
+
if (actionId === "zoomIn") return "zoom-in";
|
|
716
|
+
if (actionId === "zoomOut") return "zoom-out";
|
|
717
|
+
if (actionId === "fitPage" || actionId === "fitToPage" || actionId === "fitWidth") return "fit-page";
|
|
718
|
+
if (actionId === "rotateCW") return "rotate-cw";
|
|
719
|
+
if (actionId === "rotateCCW") return "rotate-ccw";
|
|
720
|
+
if (actionId === "openWindow" || actionId === "openSeparateWindow") return "open-window";
|
|
721
|
+
if (actionId === "pageNav") return "page-nav";
|
|
722
|
+
return actionId;
|
|
723
|
+
}
|
|
724
|
+
enableAction(actionId) {
|
|
725
|
+
const norm = this.normalizeActionId(actionId);
|
|
726
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
727
|
+
if (btn) {
|
|
728
|
+
btn.disabled = false;
|
|
729
|
+
btn.classList.remove("disabled");
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
disableAction(actionId) {
|
|
733
|
+
const norm = this.normalizeActionId(actionId);
|
|
734
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
735
|
+
if (btn) {
|
|
736
|
+
btn.disabled = true;
|
|
737
|
+
btn.classList.add("disabled");
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
setActionActive(actionId, active) {
|
|
741
|
+
const norm = this.normalizeActionId(actionId);
|
|
742
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
743
|
+
if (btn) {
|
|
744
|
+
if (active) {
|
|
745
|
+
btn.classList.add("active");
|
|
746
|
+
} else {
|
|
747
|
+
btn.classList.remove("active");
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
isActionEnabled(action) {
|
|
752
|
+
const c = this.config;
|
|
753
|
+
const id = action.id;
|
|
754
|
+
if (c[id] === false) return false;
|
|
755
|
+
if (id === "zoom-in" && (c.zoomIn === false || c["zoom-in"] === false)) return false;
|
|
756
|
+
if (id === "zoom-out" && (c.zoomOut === false || c["zoom-out"] === false)) return false;
|
|
757
|
+
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)) {
|
|
758
|
+
return false;
|
|
759
|
+
}
|
|
760
|
+
if ((id === "rotate-cw" || id === "rotate-ccw" || id === "rotate") && (c.rotate === false || c.rotateCW === false || c.rotateCCW === false || c["rotate-cw"] === false)) {
|
|
761
|
+
return false;
|
|
762
|
+
}
|
|
763
|
+
if (id === "fullscreen" && c.fullscreen === false) return false;
|
|
764
|
+
if (id === "download" && c.download === false) return false;
|
|
765
|
+
if (id === "print" && c.print === false) return false;
|
|
766
|
+
if ((id === "open-window" || id === "external-window") && (c.openWindow === false || c.openSeparateWindow === false || c["open-window"] === false)) {
|
|
767
|
+
return false;
|
|
768
|
+
}
|
|
769
|
+
if (id === "copy" && c.copy === false) return false;
|
|
770
|
+
if (id === "thumbnails" && c.thumbnails === false) return false;
|
|
771
|
+
if (id === "page-nav" && (c.pageNav === false || c.pagination === false || c["page-nav"] === false)) {
|
|
772
|
+
return false;
|
|
773
|
+
}
|
|
774
|
+
if ((id === "prev" || id === "page-prev") && (c.prevPage === false || c.prev === false || c["prev"] === false || c.pageNav === false || c.pagination === false)) {
|
|
775
|
+
return false;
|
|
776
|
+
}
|
|
777
|
+
if ((id === "next" || id === "page-next") && (c.nextPage === false || c.next === false || c["next"] === false || c.pageNav === false || c.pagination === false)) {
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
780
|
+
if (id === "play" && c.play === false) return false;
|
|
781
|
+
if (id === "pause" && c.pause === false) return false;
|
|
782
|
+
if ((id === "fast-forward" || id === "forward-10") && (c.fastForward === false || c["fast-forward"] === false)) {
|
|
783
|
+
return false;
|
|
784
|
+
}
|
|
785
|
+
if ((id === "rewind" || id === "replay-10") && (c.rewind === false || c["rewind"] === false)) {
|
|
786
|
+
return false;
|
|
787
|
+
}
|
|
788
|
+
if (id === "speed" && c.speed === false) return false;
|
|
789
|
+
return true;
|
|
790
|
+
}
|
|
654
791
|
setPage(page, max) {
|
|
655
792
|
if (this.pageInputEl) {
|
|
656
793
|
this.pageInputEl.value = page.toString();
|
|
794
|
+
if (max !== void 0) {
|
|
795
|
+
this.pageInputEl.max = max.toString();
|
|
796
|
+
}
|
|
657
797
|
}
|
|
658
798
|
if (max !== void 0 && this.pageLabelEl) {
|
|
659
799
|
this.pageLabelEl.textContent = ` / ${max}`;
|
|
660
800
|
}
|
|
801
|
+
const currentMax = max !== void 0 ? max : parseInt(this.pageInputEl?.max || "1", 10) || 1;
|
|
802
|
+
if (this.prevPageBtn) {
|
|
803
|
+
this.prevPageBtn.disabled = page <= 1;
|
|
804
|
+
this.prevPageBtn.style.opacity = page <= 1 ? "0.4" : "1";
|
|
805
|
+
}
|
|
806
|
+
if (this.nextPageBtn) {
|
|
807
|
+
this.nextPageBtn.disabled = page >= currentMax;
|
|
808
|
+
this.nextPageBtn.style.opacity = page >= currentMax ? "0.4" : "1";
|
|
809
|
+
}
|
|
661
810
|
}
|
|
662
811
|
update(actions) {
|
|
663
812
|
this.actions = actions;
|
|
@@ -680,8 +829,9 @@ var ToolbarController = class {
|
|
|
680
829
|
view: [],
|
|
681
830
|
actions: []
|
|
682
831
|
};
|
|
683
|
-
const
|
|
684
|
-
const
|
|
832
|
+
const enabledActions = this.actions.filter((a) => this.isActionEnabled(a));
|
|
833
|
+
const hasPageNav = enabledActions.some((a) => a.type === "page-nav");
|
|
834
|
+
const effectiveActions = hasPageNav ? enabledActions.filter((a) => a.id !== "page-prev" && a.id !== "page-next" && a.id !== "prev" && a.id !== "next") : enabledActions;
|
|
685
835
|
for (const action of effectiveActions) {
|
|
686
836
|
if (groups[action.group]) {
|
|
687
837
|
groups[action.group].push(action);
|
|
@@ -741,6 +891,13 @@ var ToolbarController = class {
|
|
|
741
891
|
action.execute("go", val);
|
|
742
892
|
});
|
|
743
893
|
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
894
|
+
const curVal = action.value ?? 1;
|
|
895
|
+
prevBtn.disabled = curVal <= 1;
|
|
896
|
+
prevBtn.style.opacity = curVal <= 1 ? "0.4" : "1";
|
|
897
|
+
nextBtn.disabled = curVal >= max;
|
|
898
|
+
nextBtn.style.opacity = curVal >= max ? "0.4" : "1";
|
|
899
|
+
this.prevPageBtn = prevBtn;
|
|
900
|
+
this.nextPageBtn = nextBtn;
|
|
744
901
|
this.pageInputEl = input;
|
|
745
902
|
this.pageLabelEl = label;
|
|
746
903
|
groupEl.appendChild(prevBtn);
|
|
@@ -781,9 +938,11 @@ var ToolbarController = class {
|
|
|
781
938
|
type: "button",
|
|
782
939
|
"data-action-id": id
|
|
783
940
|
});
|
|
784
|
-
const
|
|
785
|
-
if (
|
|
786
|
-
btn.innerHTML =
|
|
941
|
+
const internalSvg = ICON_MAP[iconHtml] || ICON_MAP[id];
|
|
942
|
+
if (internalSvg) {
|
|
943
|
+
btn.innerHTML = internalSvg;
|
|
944
|
+
} else if (iconHtml && iconHtml.startsWith("<svg")) {
|
|
945
|
+
btn.innerHTML = sanitizeSVG(iconHtml);
|
|
787
946
|
} else {
|
|
788
947
|
btn.textContent = title || id;
|
|
789
948
|
}
|
|
@@ -794,25 +953,63 @@ var ToolbarController = class {
|
|
|
794
953
|
var ThumbnailPanel = class {
|
|
795
954
|
el;
|
|
796
955
|
panelEl;
|
|
956
|
+
listEl;
|
|
957
|
+
headerEl;
|
|
797
958
|
thumbnails = [];
|
|
798
959
|
onSelect;
|
|
960
|
+
onToggleCallback;
|
|
799
961
|
activeIndex = 0;
|
|
800
|
-
|
|
962
|
+
observer;
|
|
963
|
+
renderedIndices = /* @__PURE__ */ new Set();
|
|
964
|
+
constructor(container, onToggle) {
|
|
801
965
|
this.el = container;
|
|
966
|
+
this.onToggleCallback = onToggle;
|
|
802
967
|
this.panelEl = createElement("div", { className: "fp-thumbnail-panel hidden" });
|
|
968
|
+
this.panelEl.style.width = "0px";
|
|
969
|
+
this.panelEl.style.minWidth = "0px";
|
|
970
|
+
this.panelEl.style.opacity = "0";
|
|
971
|
+
this.headerEl = createElement("div", { className: "fp-thumbnail-header" });
|
|
972
|
+
const title = createElement("span", { className: "fp-thumbnail-title" }, "Pages");
|
|
973
|
+
const closeBtn = createElement("button", {
|
|
974
|
+
className: "fp-thumbnail-close-btn",
|
|
975
|
+
title: "Close Thumbnails",
|
|
976
|
+
type: "button"
|
|
977
|
+
});
|
|
978
|
+
closeBtn.innerHTML = ICON_CLOSE;
|
|
979
|
+
closeBtn.addEventListener("click", (e) => {
|
|
980
|
+
e.stopPropagation();
|
|
981
|
+
this.hide();
|
|
982
|
+
});
|
|
983
|
+
this.headerEl.appendChild(title);
|
|
984
|
+
this.headerEl.appendChild(closeBtn);
|
|
985
|
+
this.listEl = createElement("div", { className: "fp-thumbnail-list" });
|
|
986
|
+
this.panelEl.appendChild(this.headerEl);
|
|
987
|
+
this.panelEl.appendChild(this.listEl);
|
|
803
988
|
this.el.appendChild(this.panelEl);
|
|
804
989
|
}
|
|
990
|
+
isOpen() {
|
|
991
|
+
return !this.panelEl.classList.contains("hidden") && this.panelEl.style.width !== "0px";
|
|
992
|
+
}
|
|
805
993
|
update(thumbnails, onSelect) {
|
|
806
994
|
this.thumbnails = thumbnails;
|
|
807
995
|
this.onSelect = onSelect;
|
|
996
|
+
this.renderedIndices.clear();
|
|
997
|
+
const titleEl = this.headerEl.querySelector(".fp-thumbnail-title");
|
|
998
|
+
if (titleEl) {
|
|
999
|
+
titleEl.textContent = `Pages (${thumbnails.length})`;
|
|
1000
|
+
}
|
|
808
1001
|
this.render();
|
|
1002
|
+
if (this.isOpen()) {
|
|
1003
|
+
this.renderAllVisible();
|
|
1004
|
+
}
|
|
809
1005
|
}
|
|
810
1006
|
setActive(index) {
|
|
811
1007
|
this.activeIndex = index;
|
|
812
|
-
const items = this.
|
|
1008
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
813
1009
|
items.forEach((item, i) => {
|
|
814
1010
|
if (i === index) {
|
|
815
1011
|
item.classList.add("active");
|
|
1012
|
+
item.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
816
1013
|
} else {
|
|
817
1014
|
item.classList.remove("active");
|
|
818
1015
|
}
|
|
@@ -820,37 +1017,102 @@ var ThumbnailPanel = class {
|
|
|
820
1017
|
}
|
|
821
1018
|
show() {
|
|
822
1019
|
this.panelEl.classList.remove("hidden");
|
|
1020
|
+
this.panelEl.style.width = "200px";
|
|
1021
|
+
this.panelEl.style.minWidth = "200px";
|
|
1022
|
+
this.panelEl.style.opacity = "1";
|
|
1023
|
+
this.panelEl.style.display = "flex";
|
|
1024
|
+
this.onToggleCallback?.(true);
|
|
1025
|
+
this.renderAllVisible();
|
|
823
1026
|
}
|
|
824
1027
|
hide() {
|
|
825
1028
|
this.panelEl.classList.add("hidden");
|
|
1029
|
+
this.panelEl.style.width = "0px";
|
|
1030
|
+
this.panelEl.style.minWidth = "0px";
|
|
1031
|
+
this.panelEl.style.opacity = "0";
|
|
1032
|
+
this.onToggleCallback?.(false);
|
|
826
1033
|
}
|
|
827
1034
|
toggle() {
|
|
828
|
-
this.
|
|
1035
|
+
if (this.isOpen()) {
|
|
1036
|
+
this.hide();
|
|
1037
|
+
} else {
|
|
1038
|
+
this.show();
|
|
1039
|
+
}
|
|
829
1040
|
}
|
|
830
1041
|
destroy() {
|
|
1042
|
+
if (this.observer) {
|
|
1043
|
+
this.observer.disconnect();
|
|
1044
|
+
this.observer = void 0;
|
|
1045
|
+
}
|
|
1046
|
+
this.renderedIndices.clear();
|
|
831
1047
|
this.el.innerHTML = "";
|
|
832
1048
|
}
|
|
833
|
-
|
|
834
|
-
this.
|
|
1049
|
+
renderAllVisible() {
|
|
1050
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
1051
|
+
items.forEach((item) => {
|
|
1052
|
+
const idx = parseInt(item.dataset.thumbIndex || "-1", 10);
|
|
1053
|
+
if (idx >= 0 && !this.renderedIndices.has(idx)) {
|
|
1054
|
+
this.renderThumbnailItem(idx, item);
|
|
1055
|
+
}
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
renderThumbnailItem(idx, itemEl) {
|
|
1059
|
+
if (this.renderedIndices.has(idx)) return;
|
|
1060
|
+
this.renderedIndices.add(idx);
|
|
1061
|
+
const canvas = itemEl.querySelector("canvas");
|
|
1062
|
+
const thumb = this.thumbnails[idx];
|
|
1063
|
+
if (canvas && thumb) {
|
|
1064
|
+
Promise.resolve(thumb.render(canvas)).catch((err) => {
|
|
1065
|
+
console.warn(`[FilePreview] Error rendering thumbnail ${idx}:`, err);
|
|
1066
|
+
});
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
render() {
|
|
1070
|
+
if (this.observer) {
|
|
1071
|
+
this.observer.disconnect();
|
|
1072
|
+
}
|
|
1073
|
+
this.listEl.innerHTML = "";
|
|
1074
|
+
const useObserver = typeof IntersectionObserver !== "undefined";
|
|
1075
|
+
if (useObserver) {
|
|
1076
|
+
this.observer = new IntersectionObserver(
|
|
1077
|
+
(entries) => {
|
|
1078
|
+
for (const entry of entries) {
|
|
1079
|
+
if (entry.isIntersecting) {
|
|
1080
|
+
const target = entry.target;
|
|
1081
|
+
const idx = parseInt(target.dataset.thumbIndex || "-1", 10);
|
|
1082
|
+
if (idx >= 0) {
|
|
1083
|
+
this.renderThumbnailItem(idx, target);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
},
|
|
1088
|
+
{
|
|
1089
|
+
root: this.listEl,
|
|
1090
|
+
rootMargin: "120px 0px 120px 0px"
|
|
1091
|
+
}
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
835
1094
|
for (let i = 0; i < this.thumbnails.length; i++) {
|
|
836
1095
|
const thumb = this.thumbnails[i];
|
|
837
|
-
const itemEl = createElement("div", {
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
1096
|
+
const itemEl = createElement("div", {
|
|
1097
|
+
className: "fp-thumbnail-item" + (i === this.activeIndex ? " active" : "")
|
|
1098
|
+
});
|
|
1099
|
+
itemEl.dataset.thumbIndex = i.toString();
|
|
841
1100
|
itemEl.addEventListener("click", () => {
|
|
842
1101
|
this.setActive(i);
|
|
843
1102
|
this.onSelect?.(i);
|
|
844
1103
|
});
|
|
845
|
-
const
|
|
846
|
-
const
|
|
847
|
-
|
|
1104
|
+
const canvasWrapper = createElement("div", { className: "fp-thumbnail-canvas-wrapper" });
|
|
1105
|
+
const canvas = createElement("canvas", { width: "130", height: "170" });
|
|
1106
|
+
canvasWrapper.appendChild(canvas);
|
|
1107
|
+
const label = createElement("span", { className: "fp-thumbnail-label" }, thumb.label || `Page ${i + 1}`);
|
|
1108
|
+
itemEl.appendChild(canvasWrapper);
|
|
848
1109
|
itemEl.appendChild(label);
|
|
849
|
-
this.
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
}
|
|
853
|
-
|
|
1110
|
+
this.listEl.appendChild(itemEl);
|
|
1111
|
+
if (this.observer) {
|
|
1112
|
+
this.observer.observe(itemEl);
|
|
1113
|
+
}
|
|
1114
|
+
if (i < 4) {
|
|
1115
|
+
this.renderThumbnailItem(i, itemEl);
|
|
854
1116
|
}
|
|
855
1117
|
}
|
|
856
1118
|
}
|
|
@@ -871,6 +1133,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
871
1133
|
currentOptions = {};
|
|
872
1134
|
resizeObserver = null;
|
|
873
1135
|
fullscreenHandler = null;
|
|
1136
|
+
titleBarEl = null;
|
|
874
1137
|
/**
|
|
875
1138
|
* Register a preview plugin.
|
|
876
1139
|
*/
|
|
@@ -907,6 +1170,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
907
1170
|
}
|
|
908
1171
|
this.currentBuffer = buffer.slice(0);
|
|
909
1172
|
this.currentMetadata = metadata;
|
|
1173
|
+
this.updateTitleBar(options, metadata);
|
|
910
1174
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
911
1175
|
const fileInfo = { metadata, buffer };
|
|
912
1176
|
const matchedPlugin = await this.findPlugin(fileInfo);
|
|
@@ -930,15 +1194,21 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
930
1194
|
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
931
1195
|
const total = payload.total ?? payload.totalPages;
|
|
932
1196
|
this.toolbar?.setPage(payload.page, total);
|
|
1197
|
+
this.thumbnailPanel?.setActive(payload.page - 1);
|
|
933
1198
|
}
|
|
934
1199
|
this.eventEmitter.emit(event, payload);
|
|
935
|
-
}
|
|
1200
|
+
},
|
|
1201
|
+
toggleThumbnails: () => this.toggleThumbnails()
|
|
936
1202
|
});
|
|
937
1203
|
this.activeInstance = instance;
|
|
938
1204
|
instance.openInSeparateWindow = () => this.openInSeparateWindow();
|
|
1205
|
+
instance.toggleThumbnails = () => this.toggleThumbnails();
|
|
939
1206
|
this.hideLoading();
|
|
940
1207
|
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
941
|
-
|
|
1208
|
+
const isToolbarVisible = options.showToolbar !== false && options.toolbar !== false;
|
|
1209
|
+
if (isToolbarVisible && this.toolbar) {
|
|
1210
|
+
const toolbarConfig = this.extractToolbarConfig(options);
|
|
1211
|
+
this.toolbar.setConfig(toolbarConfig);
|
|
942
1212
|
const actions = matchedPlugin.getToolbarActions(instance);
|
|
943
1213
|
const hasFullscreen = actions.some((a) => a.id === "fullscreen");
|
|
944
1214
|
if (!hasFullscreen && this.wrapperEl) {
|
|
@@ -988,6 +1258,12 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
988
1258
|
}
|
|
989
1259
|
});
|
|
990
1260
|
}
|
|
1261
|
+
const thumbAction = actions.find((a) => a.id === "thumbnails");
|
|
1262
|
+
if (thumbAction) {
|
|
1263
|
+
thumbAction.execute = () => {
|
|
1264
|
+
this.toggleThumbnails();
|
|
1265
|
+
};
|
|
1266
|
+
}
|
|
991
1267
|
this.toolbar.update(actions);
|
|
992
1268
|
this.toolbar.show();
|
|
993
1269
|
}
|
|
@@ -1072,7 +1348,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1072
1348
|
if (targetUrl) {
|
|
1073
1349
|
const newWin2 = window.open(targetUrl, "_blank");
|
|
1074
1350
|
if (!newWin2) {
|
|
1075
|
-
|
|
1351
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
1076
1352
|
return null;
|
|
1077
1353
|
}
|
|
1078
1354
|
return newWin2;
|
|
@@ -1080,7 +1356,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1080
1356
|
const title = (this.currentMetadata?.name || "Document Preview") + " - Full Preview";
|
|
1081
1357
|
const newWin = window.open("", "_blank");
|
|
1082
1358
|
if (!newWin) {
|
|
1083
|
-
|
|
1359
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
1084
1360
|
return null;
|
|
1085
1361
|
}
|
|
1086
1362
|
newWin.document.title = title;
|
|
@@ -1157,6 +1433,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1157
1433
|
this.currentBuffer = null;
|
|
1158
1434
|
this.currentMetadata = null;
|
|
1159
1435
|
this.currentContainer = null;
|
|
1436
|
+
this.titleBarEl = null;
|
|
1160
1437
|
}
|
|
1161
1438
|
/**
|
|
1162
1439
|
* Get the currently active preview instance.
|
|
@@ -1164,7 +1441,218 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1164
1441
|
getInstance() {
|
|
1165
1442
|
return this.activeInstance;
|
|
1166
1443
|
}
|
|
1444
|
+
// --- Toolbar Configuration & Feature Toggles ---
|
|
1445
|
+
/**
|
|
1446
|
+
* Configure toolbar features dynamically through options or methods.
|
|
1447
|
+
* e.g. viewer.setToolbarConfig({ zoomIn: false, print: false })
|
|
1448
|
+
*/
|
|
1449
|
+
setToolbarConfig(config) {
|
|
1450
|
+
this.toolbar?.setConfig(config);
|
|
1451
|
+
}
|
|
1452
|
+
/**
|
|
1453
|
+
* Get current toolbar configuration.
|
|
1454
|
+
*/
|
|
1455
|
+
getToolbarConfig() {
|
|
1456
|
+
return this.toolbar?.getConfig() ?? {};
|
|
1457
|
+
}
|
|
1458
|
+
/**
|
|
1459
|
+
* Hide a specific toolbar action by ID or alias (e.g. 'zoom-in', 'print', 'download').
|
|
1460
|
+
*/
|
|
1461
|
+
hideToolbarAction(actionId) {
|
|
1462
|
+
this.toolbar?.hideAction(actionId);
|
|
1463
|
+
}
|
|
1464
|
+
/**
|
|
1465
|
+
* Show a specific toolbar action by ID or alias.
|
|
1466
|
+
*/
|
|
1467
|
+
showToolbarAction(actionId) {
|
|
1468
|
+
this.toolbar?.showAction(actionId);
|
|
1469
|
+
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Enable a specific toolbar action button.
|
|
1472
|
+
*/
|
|
1473
|
+
enableToolbarAction(actionId) {
|
|
1474
|
+
this.toolbar?.enableAction(actionId);
|
|
1475
|
+
}
|
|
1476
|
+
/**
|
|
1477
|
+
* Disable a specific toolbar action button.
|
|
1478
|
+
*/
|
|
1479
|
+
disableToolbarAction(actionId) {
|
|
1480
|
+
this.toolbar?.disableAction(actionId);
|
|
1481
|
+
}
|
|
1482
|
+
// --- Programmatic Toolbar Action Methods ---
|
|
1483
|
+
/**
|
|
1484
|
+
* Fit document to page so it fills the frame width with minimal margins.
|
|
1485
|
+
*/
|
|
1486
|
+
fitToPage() {
|
|
1487
|
+
this.activeInstance?.fitToPage?.();
|
|
1488
|
+
}
|
|
1489
|
+
/**
|
|
1490
|
+
* Zoom in.
|
|
1491
|
+
*/
|
|
1492
|
+
zoomIn() {
|
|
1493
|
+
this.activeInstance?.zoomIn?.();
|
|
1494
|
+
}
|
|
1495
|
+
/**
|
|
1496
|
+
* Zoom out.
|
|
1497
|
+
*/
|
|
1498
|
+
zoomOut() {
|
|
1499
|
+
this.activeInstance?.zoomOut?.();
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* Set specific zoom level.
|
|
1503
|
+
*/
|
|
1504
|
+
setZoom(level) {
|
|
1505
|
+
this.activeInstance?.setZoom?.(level);
|
|
1506
|
+
}
|
|
1507
|
+
/**
|
|
1508
|
+
* Get current zoom level.
|
|
1509
|
+
*/
|
|
1510
|
+
getZoom() {
|
|
1511
|
+
return this.activeInstance?.getZoom?.() ?? 1;
|
|
1512
|
+
}
|
|
1513
|
+
/**
|
|
1514
|
+
* Rotate 90 degrees clockwise.
|
|
1515
|
+
*/
|
|
1516
|
+
rotateCW() {
|
|
1517
|
+
this.activeInstance?.rotateCW?.();
|
|
1518
|
+
}
|
|
1519
|
+
/**
|
|
1520
|
+
* Rotate 90 degrees counter-clockwise.
|
|
1521
|
+
*/
|
|
1522
|
+
rotateCCW() {
|
|
1523
|
+
this.activeInstance?.rotateCCW?.();
|
|
1524
|
+
}
|
|
1525
|
+
/**
|
|
1526
|
+
* Navigate to a specific page number.
|
|
1527
|
+
*/
|
|
1528
|
+
goToPage(page) {
|
|
1529
|
+
this.activeInstance?.goToPage?.(page);
|
|
1530
|
+
this.toolbar?.setPage(page);
|
|
1531
|
+
}
|
|
1532
|
+
/**
|
|
1533
|
+
* Navigate to next page.
|
|
1534
|
+
*/
|
|
1535
|
+
nextPage() {
|
|
1536
|
+
const cur = this.getCurrentPage();
|
|
1537
|
+
const max = this.getPageCount();
|
|
1538
|
+
if (cur < max) {
|
|
1539
|
+
this.goToPage(cur + 1);
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
/**
|
|
1543
|
+
* Navigate to previous page.
|
|
1544
|
+
*/
|
|
1545
|
+
prevPage() {
|
|
1546
|
+
const cur = this.getCurrentPage();
|
|
1547
|
+
if (cur > 1) {
|
|
1548
|
+
this.goToPage(cur - 1);
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
/**
|
|
1552
|
+
* Get total page count.
|
|
1553
|
+
*/
|
|
1554
|
+
getPageCount() {
|
|
1555
|
+
return this.activeInstance?.getPageCount?.() ?? 1;
|
|
1556
|
+
}
|
|
1557
|
+
/**
|
|
1558
|
+
* Get current page number.
|
|
1559
|
+
*/
|
|
1560
|
+
getCurrentPage() {
|
|
1561
|
+
return this.activeInstance?.getCurrentPage?.() ?? 1;
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* Download the current document.
|
|
1565
|
+
*/
|
|
1566
|
+
download() {
|
|
1567
|
+
this.activeInstance?.download?.();
|
|
1568
|
+
}
|
|
1569
|
+
/**
|
|
1570
|
+
* Print the current document.
|
|
1571
|
+
*/
|
|
1572
|
+
print() {
|
|
1573
|
+
this.activeInstance?.print?.();
|
|
1574
|
+
}
|
|
1575
|
+
/**
|
|
1576
|
+
* Toggle fullscreen mode.
|
|
1577
|
+
*/
|
|
1578
|
+
toggleFullscreen() {
|
|
1579
|
+
try {
|
|
1580
|
+
if (!document.fullscreenElement) {
|
|
1581
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
1582
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
1583
|
+
} else {
|
|
1584
|
+
document.exitFullscreen?.();
|
|
1585
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
1586
|
+
}
|
|
1587
|
+
} catch {
|
|
1588
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
1589
|
+
}
|
|
1590
|
+
setTimeout(() => {
|
|
1591
|
+
this.activeInstance?.fitToPage?.();
|
|
1592
|
+
}, 120);
|
|
1593
|
+
}
|
|
1594
|
+
/**
|
|
1595
|
+
* Toggle thumbnails sidebar panel.
|
|
1596
|
+
*/
|
|
1597
|
+
toggleThumbnails() {
|
|
1598
|
+
if (!this.thumbnailPanel) return;
|
|
1599
|
+
this.thumbnailPanel.toggle();
|
|
1600
|
+
const isOpen = this.thumbnailPanel.isOpen();
|
|
1601
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1602
|
+
setTimeout(() => {
|
|
1603
|
+
this.activeInstance?.fitToPage?.();
|
|
1604
|
+
}, 260);
|
|
1605
|
+
}
|
|
1606
|
+
/**
|
|
1607
|
+
* Set whether to display the file name / title bar above the toolbar.
|
|
1608
|
+
*/
|
|
1609
|
+
setShowFileName(show) {
|
|
1610
|
+
if (this.currentOptions) {
|
|
1611
|
+
this.currentOptions.showFileName = show;
|
|
1612
|
+
}
|
|
1613
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1614
|
+
}
|
|
1615
|
+
/**
|
|
1616
|
+
* Set or override the displayed file name in the preview panel.
|
|
1617
|
+
*/
|
|
1618
|
+
setFileName(name) {
|
|
1619
|
+
if (this.currentOptions) {
|
|
1620
|
+
this.currentOptions.fileName = name;
|
|
1621
|
+
}
|
|
1622
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1623
|
+
}
|
|
1167
1624
|
// --- Private methods ---
|
|
1625
|
+
updateTitleBar(options, metadata) {
|
|
1626
|
+
if (!this.titleBarEl) return;
|
|
1627
|
+
const show = options?.showFileName !== false;
|
|
1628
|
+
if (!show) {
|
|
1629
|
+
this.titleBarEl.style.display = "none";
|
|
1630
|
+
return;
|
|
1631
|
+
}
|
|
1632
|
+
const name = options?.fileName || metadata?.name || this.currentMetadata?.name || "";
|
|
1633
|
+
if (!name) {
|
|
1634
|
+
this.titleBarEl.style.display = "none";
|
|
1635
|
+
return;
|
|
1636
|
+
}
|
|
1637
|
+
this.titleBarEl.style.display = "flex";
|
|
1638
|
+
const ext = metadata?.extension || (name.includes(".") ? "." + name.split(".").pop() : "");
|
|
1639
|
+
const badge = ext ? ext.replace(".", "").toUpperCase() : "";
|
|
1640
|
+
this.titleBarEl.innerHTML = `
|
|
1641
|
+
<div class="fp-titlebar-info">
|
|
1642
|
+
<span class="fp-titlebar-icon">\u{1F4C4}</span>
|
|
1643
|
+
<span class="fp-titlebar-name" title="${name}">${name}</span>
|
|
1644
|
+
${badge ? `<span class="fp-titlebar-badge">${badge}</span>` : ""}
|
|
1645
|
+
</div>
|
|
1646
|
+
`;
|
|
1647
|
+
}
|
|
1648
|
+
extractToolbarConfig(options) {
|
|
1649
|
+
if (!options) return {};
|
|
1650
|
+
const nested = typeof options.toolbar === "object" ? options.toolbar : {};
|
|
1651
|
+
return {
|
|
1652
|
+
...options,
|
|
1653
|
+
...nested
|
|
1654
|
+
};
|
|
1655
|
+
}
|
|
1168
1656
|
abort() {
|
|
1169
1657
|
if (this.abortController) {
|
|
1170
1658
|
this.abortController.abort();
|
|
@@ -1207,17 +1695,29 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1207
1695
|
bodyEl.className = "fp-body";
|
|
1208
1696
|
bodyEl.appendChild(thumbnailEl);
|
|
1209
1697
|
bodyEl.appendChild(this.contentEl);
|
|
1698
|
+
const titleBarEl = document.createElement("div");
|
|
1699
|
+
titleBarEl.className = "fp-titlebar";
|
|
1700
|
+
this.titleBarEl = titleBarEl;
|
|
1701
|
+
this.updateTitleBar(options, this.currentMetadata);
|
|
1210
1702
|
if (toolbarPos === "top") {
|
|
1703
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1211
1704
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1212
1705
|
this.wrapperEl.appendChild(bodyEl);
|
|
1213
1706
|
} else {
|
|
1707
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1214
1708
|
this.wrapperEl.appendChild(bodyEl);
|
|
1215
1709
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1216
1710
|
}
|
|
1217
1711
|
container.innerHTML = "";
|
|
1218
1712
|
container.appendChild(this.wrapperEl);
|
|
1219
|
-
|
|
1220
|
-
this.
|
|
1713
|
+
const initialToolbarConfig = this.extractToolbarConfig(options);
|
|
1714
|
+
this.toolbar = new ToolbarController(toolbarEl, initialToolbarConfig);
|
|
1715
|
+
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl, (isOpen) => {
|
|
1716
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1717
|
+
setTimeout(() => {
|
|
1718
|
+
this.activeInstance?.fitToPage?.();
|
|
1719
|
+
}, 260);
|
|
1720
|
+
});
|
|
1221
1721
|
this.setupKeyboardShortcuts();
|
|
1222
1722
|
this.setupDragAndDrop(container, options);
|
|
1223
1723
|
this.setupResizeAndFullscreenListeners();
|
|
@@ -1607,6 +2107,14 @@ var PdfPlugin = class {
|
|
|
1607
2107
|
group: "zoom",
|
|
1608
2108
|
execute: () => instance.fitToPage?.()
|
|
1609
2109
|
},
|
|
2110
|
+
{
|
|
2111
|
+
id: "fit-width",
|
|
2112
|
+
icon: "fit-width",
|
|
2113
|
+
label: "Fit to Width",
|
|
2114
|
+
type: "button",
|
|
2115
|
+
group: "zoom",
|
|
2116
|
+
execute: () => instance.fitToWidth?.()
|
|
2117
|
+
},
|
|
1610
2118
|
{
|
|
1611
2119
|
id: "rotate-cw",
|
|
1612
2120
|
icon: "rotate-cw",
|
|
@@ -1615,6 +2123,14 @@ var PdfPlugin = class {
|
|
|
1615
2123
|
group: "view",
|
|
1616
2124
|
execute: () => instance.rotateCW?.()
|
|
1617
2125
|
},
|
|
2126
|
+
{
|
|
2127
|
+
id: "rotate-ccw",
|
|
2128
|
+
icon: "rotate-ccw",
|
|
2129
|
+
label: "Rotate Counter-Clockwise",
|
|
2130
|
+
type: "button",
|
|
2131
|
+
group: "view",
|
|
2132
|
+
execute: () => instance.rotateCCW?.()
|
|
2133
|
+
},
|
|
1618
2134
|
{
|
|
1619
2135
|
id: "download",
|
|
1620
2136
|
icon: "download",
|
|
@@ -1646,12 +2162,13 @@ var PdfPlugin = class {
|
|
|
1646
2162
|
container.className = "fp-pdf-container";
|
|
1647
2163
|
container.style.width = "100%";
|
|
1648
2164
|
container.style.height = "100%";
|
|
1649
|
-
container.style.
|
|
2165
|
+
container.style.overflowX = "hidden";
|
|
2166
|
+
container.style.overflowY = "auto";
|
|
1650
2167
|
container.style.display = "flex";
|
|
1651
2168
|
container.style.flexDirection = "column";
|
|
1652
2169
|
container.style.alignItems = "center";
|
|
1653
2170
|
container.style.justifyContent = "flex-start";
|
|
1654
|
-
container.style.padding = "
|
|
2171
|
+
container.style.padding = "16px 8px";
|
|
1655
2172
|
container.style.backgroundColor = "#0f172a";
|
|
1656
2173
|
container.style.boxSizing = "border-box";
|
|
1657
2174
|
container.style.position = "relative";
|
|
@@ -1662,30 +2179,12 @@ var PdfPlugin = class {
|
|
|
1662
2179
|
pageCard.style.borderRadius = "4px";
|
|
1663
2180
|
pageCard.style.overflow = "hidden";
|
|
1664
2181
|
pageCard.style.lineHeight = "0";
|
|
1665
|
-
pageCard.style.transition = "transform 0.15s ease";
|
|
1666
2182
|
pageCard.style.position = "relative";
|
|
1667
2183
|
pageCard.style.flexShrink = "0";
|
|
2184
|
+
pageCard.style.transition = "box-shadow 0.2s ease";
|
|
1668
2185
|
let canvas = document.createElement("canvas");
|
|
1669
2186
|
pageCard.appendChild(canvas);
|
|
1670
2187
|
container.appendChild(pageCard);
|
|
1671
|
-
const indicator = document.createElement("div");
|
|
1672
|
-
indicator.className = "fp-pdf-page-indicator";
|
|
1673
|
-
indicator.style.position = "sticky";
|
|
1674
|
-
indicator.style.bottom = "16px";
|
|
1675
|
-
indicator.style.marginTop = "16px";
|
|
1676
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1677
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
1678
|
-
indicator.style.color = "#f8fafc";
|
|
1679
|
-
indicator.style.fontSize = "12px";
|
|
1680
|
-
indicator.style.fontWeight = "600";
|
|
1681
|
-
indicator.style.padding = "5px 14px";
|
|
1682
|
-
indicator.style.borderRadius = "20px";
|
|
1683
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1684
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1685
|
-
indicator.style.zIndex = "10";
|
|
1686
|
-
indicator.style.userSelect = "none";
|
|
1687
|
-
indicator.style.pointerEvents = "none";
|
|
1688
|
-
container.appendChild(indicator);
|
|
1689
2188
|
ctx.container.appendChild(container);
|
|
1690
2189
|
const standardFontsUrl = typeof window !== "undefined" && window.__PDF_STANDARD_FONTS_URL__ || "./standard_fonts/";
|
|
1691
2190
|
const cmapsUrl = typeof window !== "undefined" && window.__PDF_CMAPS_URL__ || "./cmaps/";
|
|
@@ -1701,8 +2200,9 @@ var PdfPlugin = class {
|
|
|
1701
2200
|
let currentPage = 1;
|
|
1702
2201
|
let zoomScale = 1;
|
|
1703
2202
|
let rotation = 0;
|
|
1704
|
-
let fitMode = "
|
|
2203
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
1705
2204
|
let currentRenderTask = null;
|
|
2205
|
+
let textLayerDiv = null;
|
|
1706
2206
|
const renderPage = async (pageNum) => {
|
|
1707
2207
|
if (currentRenderTask) {
|
|
1708
2208
|
try {
|
|
@@ -1714,30 +2214,37 @@ var PdfPlugin = class {
|
|
|
1714
2214
|
const newCanvas = document.createElement("canvas");
|
|
1715
2215
|
pageCard.replaceChild(newCanvas, canvas);
|
|
1716
2216
|
canvas = newCanvas;
|
|
2217
|
+
if (textLayerDiv) {
|
|
2218
|
+
textLayerDiv.remove();
|
|
2219
|
+
textLayerDiv = null;
|
|
2220
|
+
}
|
|
1717
2221
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1718
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1719
2222
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1720
2223
|
const page = await pdfDoc.getPage(currentPage);
|
|
1721
2224
|
const containerWidth = container.clientWidth || 900;
|
|
1722
2225
|
const containerHeight = container.clientHeight || 700;
|
|
1723
2226
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1724
|
-
const availWidth = Math.max(
|
|
1725
|
-
const availHeight = Math.max(
|
|
2227
|
+
const availWidth = Math.max(280, containerWidth - 36);
|
|
2228
|
+
const availHeight = Math.max(280, containerHeight - 32);
|
|
1726
2229
|
const scaleW = availWidth / unscaledVp.width;
|
|
1727
2230
|
const scaleH = availHeight / unscaledVp.height;
|
|
1728
2231
|
let fitScale;
|
|
1729
2232
|
if (fitMode === "page") {
|
|
1730
|
-
fitScale = Math.max(0.4, Math.min(scaleW, scaleH));
|
|
2233
|
+
fitScale = Math.max(0.2, Math.min(4, Math.min(scaleW, scaleH)));
|
|
1731
2234
|
} else {
|
|
1732
|
-
fitScale = Math.max(0.
|
|
2235
|
+
fitScale = Math.max(0.2, Math.min(4, scaleW));
|
|
1733
2236
|
}
|
|
1734
2237
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1735
2238
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1736
2239
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
2240
|
+
const displayWidth = Math.floor(viewport.width);
|
|
2241
|
+
const displayHeight = Math.floor(viewport.height);
|
|
1737
2242
|
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1738
2243
|
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1739
|
-
canvas.style.width = `${
|
|
1740
|
-
canvas.style.height = `${
|
|
2244
|
+
canvas.style.width = `${displayWidth}px`;
|
|
2245
|
+
canvas.style.height = `${displayHeight}px`;
|
|
2246
|
+
pageCard.style.width = `${displayWidth}px`;
|
|
2247
|
+
pageCard.style.height = `${displayHeight}px`;
|
|
1741
2248
|
const canvasCtx = canvas.getContext("2d");
|
|
1742
2249
|
if (!canvasCtx) return;
|
|
1743
2250
|
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
@@ -1751,9 +2258,31 @@ var PdfPlugin = class {
|
|
|
1751
2258
|
if (err?.name !== "RenderingCancelledException") {
|
|
1752
2259
|
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1753
2260
|
}
|
|
2261
|
+
return;
|
|
1754
2262
|
} finally {
|
|
1755
2263
|
currentRenderTask = null;
|
|
1756
2264
|
}
|
|
2265
|
+
try {
|
|
2266
|
+
textLayerDiv = document.createElement("div");
|
|
2267
|
+
textLayerDiv.className = "textLayer";
|
|
2268
|
+
textLayerDiv.style.width = `${displayWidth}px`;
|
|
2269
|
+
textLayerDiv.style.height = `${displayHeight}px`;
|
|
2270
|
+
textLayerDiv.style.position = "absolute";
|
|
2271
|
+
textLayerDiv.style.top = "0";
|
|
2272
|
+
textLayerDiv.style.left = "0";
|
|
2273
|
+
textLayerDiv.style.lineHeight = "1";
|
|
2274
|
+
pageCard.appendChild(textLayerDiv);
|
|
2275
|
+
if (pdfjsLib__namespace.TextLayer) {
|
|
2276
|
+
const textLayer = new pdfjsLib__namespace.TextLayer({
|
|
2277
|
+
textContentSource: page.streamTextContent(),
|
|
2278
|
+
container: textLayerDiv,
|
|
2279
|
+
viewport
|
|
2280
|
+
});
|
|
2281
|
+
await textLayer.render();
|
|
2282
|
+
}
|
|
2283
|
+
} catch (err) {
|
|
2284
|
+
console.debug("[PdfPlugin] TextLayer notice:", err);
|
|
2285
|
+
}
|
|
1757
2286
|
};
|
|
1758
2287
|
renderPage(1);
|
|
1759
2288
|
let resizeTimer = null;
|
|
@@ -1763,11 +2292,48 @@ var PdfPlugin = class {
|
|
|
1763
2292
|
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1764
2293
|
renderPage(currentPage);
|
|
1765
2294
|
}
|
|
1766
|
-
},
|
|
2295
|
+
}, 120);
|
|
1767
2296
|
});
|
|
1768
2297
|
resizeObserver.observe(container);
|
|
2298
|
+
const onWheel = (e) => {
|
|
2299
|
+
if (e.ctrlKey || e.metaKey) {
|
|
2300
|
+
e.preventDefault();
|
|
2301
|
+
const delta = e.deltaY > 0 ? -0.15 : 0.15;
|
|
2302
|
+
zoomScale = Math.max(0.25, Math.min(4, Math.round((zoomScale + delta) * 100) / 100));
|
|
2303
|
+
renderPage(currentPage);
|
|
2304
|
+
}
|
|
2305
|
+
};
|
|
2306
|
+
container.addEventListener("wheel", onWheel, { passive: false });
|
|
2307
|
+
const onKeyDown = (e) => {
|
|
2308
|
+
const tag = e.target?.tagName?.toLowerCase();
|
|
2309
|
+
if (tag === "input" || tag === "textarea" || tag === "select") return;
|
|
2310
|
+
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
2311
|
+
if (currentPage < totalPages) {
|
|
2312
|
+
e.preventDefault();
|
|
2313
|
+
container.scrollTop = 0;
|
|
2314
|
+
renderPage(currentPage + 1);
|
|
2315
|
+
}
|
|
2316
|
+
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
2317
|
+
if (currentPage > 1) {
|
|
2318
|
+
e.preventDefault();
|
|
2319
|
+
container.scrollTop = 0;
|
|
2320
|
+
renderPage(currentPage - 1);
|
|
2321
|
+
}
|
|
2322
|
+
} else if (e.key === "Home") {
|
|
2323
|
+
e.preventDefault();
|
|
2324
|
+
container.scrollTop = 0;
|
|
2325
|
+
renderPage(1);
|
|
2326
|
+
} else if (e.key === "End") {
|
|
2327
|
+
e.preventDefault();
|
|
2328
|
+
container.scrollTop = 0;
|
|
2329
|
+
renderPage(totalPages);
|
|
2330
|
+
}
|
|
2331
|
+
};
|
|
2332
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1769
2333
|
const cleanup = () => {
|
|
1770
2334
|
resizeObserver.disconnect();
|
|
2335
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
2336
|
+
container.removeEventListener("wheel", onWheel);
|
|
1771
2337
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1772
2338
|
if (currentRenderTask) {
|
|
1773
2339
|
try {
|
|
@@ -1786,22 +2352,26 @@ var PdfPlugin = class {
|
|
|
1786
2352
|
const instance = {
|
|
1787
2353
|
destroy: cleanup,
|
|
1788
2354
|
zoomIn: () => {
|
|
1789
|
-
zoomScale = Math.min(
|
|
2355
|
+
zoomScale = Math.min(4, Math.round((zoomScale + 0.2) * 10) / 10);
|
|
1790
2356
|
renderPage(currentPage);
|
|
1791
2357
|
},
|
|
1792
2358
|
zoomOut: () => {
|
|
1793
|
-
zoomScale = Math.max(0.
|
|
2359
|
+
zoomScale = Math.max(0.25, Math.round((zoomScale - 0.2) * 10) / 10);
|
|
1794
2360
|
renderPage(currentPage);
|
|
1795
2361
|
},
|
|
1796
2362
|
getZoom: () => zoomScale,
|
|
1797
2363
|
setZoom: (level) => {
|
|
1798
|
-
zoomScale = Math.max(0.
|
|
2364
|
+
zoomScale = Math.max(0.25, Math.min(4, level));
|
|
1799
2365
|
renderPage(currentPage);
|
|
1800
2366
|
},
|
|
1801
2367
|
fitToPage: () => {
|
|
1802
|
-
fitMode =
|
|
2368
|
+
fitMode = "page";
|
|
2369
|
+
zoomScale = 1;
|
|
2370
|
+
renderPage(currentPage);
|
|
2371
|
+
},
|
|
2372
|
+
fitToWidth: () => {
|
|
2373
|
+
fitMode = "width";
|
|
1803
2374
|
zoomScale = 1;
|
|
1804
|
-
rotation = 0;
|
|
1805
2375
|
renderPage(currentPage);
|
|
1806
2376
|
},
|
|
1807
2377
|
rotateCW: () => {
|
|
@@ -1819,6 +2389,9 @@ var PdfPlugin = class {
|
|
|
1819
2389
|
container.scrollTop = 0;
|
|
1820
2390
|
renderPage(page);
|
|
1821
2391
|
},
|
|
2392
|
+
toggleThumbnails: () => {
|
|
2393
|
+
ctx?.toggleThumbnails?.();
|
|
2394
|
+
},
|
|
1822
2395
|
download: () => {
|
|
1823
2396
|
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1824
2397
|
const url = URL.createObjectURL(blob);
|
|
@@ -1852,7 +2425,7 @@ var PdfPlugin = class {
|
|
|
1852
2425
|
},
|
|
1853
2426
|
getThumbnails: async () => {
|
|
1854
2427
|
const thumbnails = [];
|
|
1855
|
-
const count =
|
|
2428
|
+
const count = totalPages;
|
|
1856
2429
|
for (let i = 1; i <= count; i++) {
|
|
1857
2430
|
thumbnails.push({
|
|
1858
2431
|
index: i,
|
|
@@ -1860,9 +2433,10 @@ var PdfPlugin = class {
|
|
|
1860
2433
|
render: async (thumbCanvas) => {
|
|
1861
2434
|
try {
|
|
1862
2435
|
const p = await pdfDoc.getPage(i);
|
|
1863
|
-
const baseVp = p.getViewport({ scale: 1 });
|
|
1864
|
-
const
|
|
1865
|
-
const
|
|
2436
|
+
const baseVp = p.getViewport({ scale: 1, rotation });
|
|
2437
|
+
const targetW = thumbCanvas.width || 130;
|
|
2438
|
+
const thumbScale = targetW / baseVp.width;
|
|
2439
|
+
const thumbVp = p.getViewport({ scale: thumbScale, rotation });
|
|
1866
2440
|
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1867
2441
|
const tCtx = thumbCanvas.getContext("2d");
|
|
1868
2442
|
if (tCtx) {
|
|
@@ -2206,28 +2780,26 @@ var DocxPlugin = class {
|
|
|
2206
2780
|
getToolbarActions(instance) {
|
|
2207
2781
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2208
2782
|
const actions = [];
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
if (
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
instance.goToPage?.(page);
|
|
2227
|
-
}
|
|
2783
|
+
actions.push({
|
|
2784
|
+
id: "page-nav",
|
|
2785
|
+
icon: "",
|
|
2786
|
+
label: "Page Navigation",
|
|
2787
|
+
type: "page-nav",
|
|
2788
|
+
group: "navigation",
|
|
2789
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2790
|
+
max: totalPages,
|
|
2791
|
+
execute: (action, page) => {
|
|
2792
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2793
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2794
|
+
if (action === "prev") {
|
|
2795
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2796
|
+
} else if (action === "next") {
|
|
2797
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2798
|
+
} else if (typeof page === "number") {
|
|
2799
|
+
instance.goToPage?.(page);
|
|
2228
2800
|
}
|
|
2229
|
-
}
|
|
2230
|
-
}
|
|
2801
|
+
}
|
|
2802
|
+
});
|
|
2231
2803
|
actions.push(
|
|
2232
2804
|
{
|
|
2233
2805
|
id: "zoom-out",
|
|
@@ -2293,11 +2865,17 @@ var DocxPlugin = class {
|
|
|
2293
2865
|
wrapper.className = "fp-docx-wrapper";
|
|
2294
2866
|
wrapper.style.transformOrigin = "top center";
|
|
2295
2867
|
wrapper.style.transition = "transform 0.2s ease";
|
|
2296
|
-
wrapper.style.padding = "
|
|
2297
|
-
wrapper.style.maxWidth = "
|
|
2868
|
+
wrapper.style.padding = "0";
|
|
2869
|
+
wrapper.style.maxWidth = "none";
|
|
2870
|
+
wrapper.style.width = "816px";
|
|
2298
2871
|
wrapper.style.margin = "0 auto";
|
|
2872
|
+
wrapper.style.display = "flex";
|
|
2873
|
+
wrapper.style.flexDirection = "column";
|
|
2874
|
+
wrapper.style.alignItems = "center";
|
|
2299
2875
|
wrapper.style.boxSizing = "border-box";
|
|
2300
|
-
ctx.container.style.
|
|
2876
|
+
ctx.container.style.overflowX = "hidden";
|
|
2877
|
+
ctx.container.style.overflowY = "auto";
|
|
2878
|
+
ctx.container.style.padding = "16px 8px";
|
|
2301
2879
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
2302
2880
|
ctx.container.appendChild(wrapper);
|
|
2303
2881
|
const styleOverride = document.createElement("style");
|
|
@@ -2471,39 +3049,13 @@ var DocxPlugin = class {
|
|
|
2471
3049
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2472
3050
|
const totalPages = Math.max(1, pageElements.length);
|
|
2473
3051
|
let currentPage = 1;
|
|
2474
|
-
let indicator = null;
|
|
2475
|
-
if (totalPages > 1) {
|
|
2476
|
-
indicator = document.createElement("div");
|
|
2477
|
-
indicator.className = "fp-docx-page-indicator";
|
|
2478
|
-
indicator.style.position = "sticky";
|
|
2479
|
-
indicator.style.bottom = "16px";
|
|
2480
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2481
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
2482
|
-
indicator.style.color = "#f8fafc";
|
|
2483
|
-
indicator.style.fontSize = "12px";
|
|
2484
|
-
indicator.style.fontWeight = "600";
|
|
2485
|
-
indicator.style.padding = "5px 14px";
|
|
2486
|
-
indicator.style.borderRadius = "20px";
|
|
2487
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2488
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2489
|
-
indicator.style.zIndex = "10";
|
|
2490
|
-
indicator.style.userSelect = "none";
|
|
2491
|
-
indicator.style.pointerEvents = "none";
|
|
2492
|
-
indicator.style.textAlign = "center";
|
|
2493
|
-
indicator.style.width = "fit-content";
|
|
2494
|
-
indicator.style.margin = "16px auto 0";
|
|
2495
|
-
ctx.container.appendChild(indicator);
|
|
2496
|
-
}
|
|
2497
3052
|
const showPage = (pageNum) => {
|
|
2498
3053
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2499
3054
|
if (pageElements.length > 1) {
|
|
2500
3055
|
pageElements.forEach((sec, idx) => {
|
|
2501
|
-
sec.style.display = idx + 1 === currentPage ? "
|
|
3056
|
+
sec.style.display = idx + 1 === currentPage ? "" : "none";
|
|
2502
3057
|
});
|
|
2503
3058
|
}
|
|
2504
|
-
if (indicator) {
|
|
2505
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2506
|
-
}
|
|
2507
3059
|
ctx.container.scrollTop = 0;
|
|
2508
3060
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2509
3061
|
};
|
|
@@ -2512,31 +3064,46 @@ var DocxPlugin = class {
|
|
|
2512
3064
|
}
|
|
2513
3065
|
scale = 1;
|
|
2514
3066
|
let rotation = 0;
|
|
2515
|
-
let fitMode = "
|
|
2516
|
-
|
|
2517
|
-
|
|
3067
|
+
let fitMode = "page";
|
|
3068
|
+
let isUserZoomed = false;
|
|
3069
|
+
const calculateFitScale = (_mode = fitMode) => {
|
|
3070
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
2518
3071
|
const elW = activeEl.offsetWidth || 816;
|
|
2519
|
-
const
|
|
2520
|
-
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
2521
|
-
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
3072
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
2522
3073
|
const sW = availW / elW;
|
|
2523
|
-
|
|
2524
|
-
if (mode === "page") {
|
|
2525
|
-
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
2526
|
-
}
|
|
2527
|
-
return Math.max(0.65, Math.min(1.05, sW));
|
|
3074
|
+
return Math.max(0.35, Math.min(3, sW));
|
|
2528
3075
|
};
|
|
2529
3076
|
const applyTransform = () => {
|
|
2530
3077
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2531
3078
|
wrapper.style.transformOrigin = "top center";
|
|
3079
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
3080
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
3081
|
+
if (scale > 1) {
|
|
3082
|
+
wrapper.style.marginBottom = `${Math.round(elH * scale - elH + 32)}px`;
|
|
3083
|
+
} else {
|
|
3084
|
+
wrapper.style.marginBottom = "32px";
|
|
3085
|
+
}
|
|
2532
3086
|
};
|
|
3087
|
+
let resizeObserver = null;
|
|
3088
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
3089
|
+
resizeObserver = new ResizeObserver(() => {
|
|
3090
|
+
if (!isUserZoomed) {
|
|
3091
|
+
const newFit = calculateFitScale("page");
|
|
3092
|
+
if (Math.abs(scale - newFit) > 0.015) {
|
|
3093
|
+
scale = newFit;
|
|
3094
|
+
applyTransform();
|
|
3095
|
+
}
|
|
3096
|
+
}
|
|
3097
|
+
});
|
|
3098
|
+
resizeObserver.observe(ctx.container);
|
|
3099
|
+
}
|
|
2533
3100
|
setTimeout(() => {
|
|
2534
|
-
|
|
2535
|
-
scale = calculateFitScale("width");
|
|
3101
|
+
scale = calculateFitScale("page");
|
|
2536
3102
|
applyTransform();
|
|
2537
|
-
},
|
|
3103
|
+
}, 40);
|
|
2538
3104
|
const cleanup = () => {
|
|
2539
|
-
|
|
3105
|
+
resizeObserver?.disconnect();
|
|
3106
|
+
resizeObserver = null;
|
|
2540
3107
|
for (const url of createdBlobUrls) {
|
|
2541
3108
|
URL.revokeObjectURL(url);
|
|
2542
3109
|
}
|
|
@@ -2553,21 +3120,24 @@ var DocxPlugin = class {
|
|
|
2553
3120
|
showPage(page);
|
|
2554
3121
|
},
|
|
2555
3122
|
zoomIn: () => {
|
|
2556
|
-
|
|
3123
|
+
isUserZoomed = true;
|
|
3124
|
+
scale = Math.min(3.5, scale + 0.15);
|
|
2557
3125
|
applyTransform();
|
|
2558
3126
|
},
|
|
2559
3127
|
zoomOut: () => {
|
|
3128
|
+
isUserZoomed = true;
|
|
2560
3129
|
scale = Math.max(0.2, scale - 0.15);
|
|
2561
3130
|
applyTransform();
|
|
2562
3131
|
},
|
|
2563
3132
|
getZoom: () => scale,
|
|
2564
3133
|
setZoom: (level) => {
|
|
3134
|
+
isUserZoomed = true;
|
|
2565
3135
|
scale = level;
|
|
2566
3136
|
applyTransform();
|
|
2567
3137
|
},
|
|
2568
3138
|
fitToPage: () => {
|
|
2569
|
-
|
|
2570
|
-
scale = calculateFitScale(
|
|
3139
|
+
isUserZoomed = false;
|
|
3140
|
+
scale = calculateFitScale("page");
|
|
2571
3141
|
rotation = 0;
|
|
2572
3142
|
applyTransform();
|
|
2573
3143
|
},
|
|
@@ -2957,7 +3527,7 @@ var ExcelPlugin = class {
|
|
|
2957
3527
|
"application/vnd.ms-excel.template.macroEnabled.12",
|
|
2958
3528
|
"application/vnd.oasis.opendocument.spreadsheet"
|
|
2959
3529
|
];
|
|
2960
|
-
weight =
|
|
3530
|
+
weight = 85;
|
|
2961
3531
|
supports(file) {
|
|
2962
3532
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2963
3533
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
@@ -2969,6 +3539,14 @@ var ExcelPlugin = class {
|
|
|
2969
3539
|
getToolbarActions(instance) {
|
|
2970
3540
|
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2971
3541
|
const actions = [];
|
|
3542
|
+
actions.push({
|
|
3543
|
+
id: "thumbnails",
|
|
3544
|
+
icon: "thumbnails",
|
|
3545
|
+
label: "Sheet Thumbnails",
|
|
3546
|
+
type: "button",
|
|
3547
|
+
group: "navigation",
|
|
3548
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3549
|
+
});
|
|
2972
3550
|
if (totalSheets > 1) {
|
|
2973
3551
|
actions.push({
|
|
2974
3552
|
id: "page-nav",
|
|
@@ -3051,6 +3629,16 @@ var ExcelPlugin = class {
|
|
|
3051
3629
|
execute: () => {
|
|
3052
3630
|
instance.print?.();
|
|
3053
3631
|
}
|
|
3632
|
+
},
|
|
3633
|
+
{
|
|
3634
|
+
id: "open-window",
|
|
3635
|
+
icon: "open-window",
|
|
3636
|
+
label: "Open in Separate Full Window",
|
|
3637
|
+
type: "button",
|
|
3638
|
+
group: "actions",
|
|
3639
|
+
execute: () => {
|
|
3640
|
+
instance.openInSeparateWindow?.();
|
|
3641
|
+
}
|
|
3054
3642
|
}
|
|
3055
3643
|
);
|
|
3056
3644
|
return actions;
|
|
@@ -3216,6 +3804,63 @@ var ExcelPlugin = class {
|
|
|
3216
3804
|
},
|
|
3217
3805
|
getPageCount: () => sheetNames.length,
|
|
3218
3806
|
getCurrentPage: () => currentSheetIndex,
|
|
3807
|
+
getThumbnails: () => {
|
|
3808
|
+
return sheetNames.map((name, idx) => ({
|
|
3809
|
+
index: idx,
|
|
3810
|
+
label: name,
|
|
3811
|
+
render: async (canvas) => {
|
|
3812
|
+
canvas.width = 140;
|
|
3813
|
+
canvas.height = 100;
|
|
3814
|
+
const c = canvas.getContext("2d");
|
|
3815
|
+
if (!c) return;
|
|
3816
|
+
c.fillStyle = "#ffffff";
|
|
3817
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
3818
|
+
c.fillStyle = "#107c41";
|
|
3819
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
3820
|
+
c.fillStyle = "#ffffff";
|
|
3821
|
+
c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
3822
|
+
c.fillText(`\u{1F4CA} ${name.slice(0, 16)}`, 6, 11);
|
|
3823
|
+
const startY = 17;
|
|
3824
|
+
const rowH = 13;
|
|
3825
|
+
const colW = 30;
|
|
3826
|
+
const colHeaders = ["A", "B", "C", "D"];
|
|
3827
|
+
c.fillStyle = "#f1f5f9";
|
|
3828
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
3829
|
+
c.strokeStyle = "#cbd5e1";
|
|
3830
|
+
c.lineWidth = 0.8;
|
|
3831
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
3832
|
+
c.fillStyle = "#64748b";
|
|
3833
|
+
c.font = "bold 7px sans-serif";
|
|
3834
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3835
|
+
c.fillText(colHeaders[ci], 14 + ci * colW, startY + 9);
|
|
3836
|
+
}
|
|
3837
|
+
const ws = wb?.Sheets[name];
|
|
3838
|
+
for (let ri = 1; ri <= 5; ri++) {
|
|
3839
|
+
const y = startY + ri * rowH;
|
|
3840
|
+
if (y > canvas.height - 2) break;
|
|
3841
|
+
c.fillStyle = "#f8fafc";
|
|
3842
|
+
c.fillRect(0, y, 12, rowH);
|
|
3843
|
+
c.fillStyle = "#94a3b8";
|
|
3844
|
+
c.font = "6px sans-serif";
|
|
3845
|
+
c.fillText(String(ri), 3, y + 9);
|
|
3846
|
+
c.strokeStyle = "#e2e8f0";
|
|
3847
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
3848
|
+
c.fillStyle = "#334155";
|
|
3849
|
+
c.font = "6px sans-serif";
|
|
3850
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3851
|
+
const cellRef = `${colHeaders[ci]}${ri}`;
|
|
3852
|
+
const cellVal = ws?.[cellRef]?.w || ws?.[cellRef]?.v;
|
|
3853
|
+
if (cellVal !== void 0) {
|
|
3854
|
+
c.fillText(String(cellVal).slice(0, 6), 14 + ci * colW, y + 9);
|
|
3855
|
+
}
|
|
3856
|
+
}
|
|
3857
|
+
}
|
|
3858
|
+
c.strokeStyle = "#cbd5e1";
|
|
3859
|
+
c.lineWidth = 1;
|
|
3860
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
3861
|
+
}
|
|
3862
|
+
}));
|
|
3863
|
+
},
|
|
3219
3864
|
download: () => {
|
|
3220
3865
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
3221
3866
|
const url = URL.createObjectURL(blob);
|
|
@@ -3248,7 +3893,39 @@ var CsvPlugin = class {
|
|
|
3248
3893
|
return ext === ".csv" || ext === ".tsv" || mime === "text/csv" || mime === "text/tab-separated-values";
|
|
3249
3894
|
}
|
|
3250
3895
|
getToolbarActions(instance) {
|
|
3251
|
-
|
|
3896
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3897
|
+
const actions = [];
|
|
3898
|
+
actions.push({
|
|
3899
|
+
id: "thumbnails",
|
|
3900
|
+
icon: "thumbnails",
|
|
3901
|
+
label: "Page Thumbnails",
|
|
3902
|
+
type: "button",
|
|
3903
|
+
group: "navigation",
|
|
3904
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3905
|
+
});
|
|
3906
|
+
if (totalPages > 1) {
|
|
3907
|
+
actions.push({
|
|
3908
|
+
id: "page-nav",
|
|
3909
|
+
icon: "",
|
|
3910
|
+
label: "Page Navigation",
|
|
3911
|
+
type: "page-nav",
|
|
3912
|
+
group: "navigation",
|
|
3913
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3914
|
+
max: totalPages,
|
|
3915
|
+
execute: (action, page) => {
|
|
3916
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3917
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
3918
|
+
if (action === "prev") {
|
|
3919
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3920
|
+
} else if (action === "next") {
|
|
3921
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
3922
|
+
} else if (typeof page === "number") {
|
|
3923
|
+
instance.goToPage?.(page);
|
|
3924
|
+
}
|
|
3925
|
+
}
|
|
3926
|
+
});
|
|
3927
|
+
}
|
|
3928
|
+
actions.push(
|
|
3252
3929
|
{
|
|
3253
3930
|
id: "zoom-out",
|
|
3254
3931
|
icon: "zoom-out",
|
|
@@ -3269,6 +3946,16 @@ var CsvPlugin = class {
|
|
|
3269
3946
|
instance.zoomIn?.();
|
|
3270
3947
|
}
|
|
3271
3948
|
},
|
|
3949
|
+
{
|
|
3950
|
+
id: "fit-page",
|
|
3951
|
+
icon: "fit-page",
|
|
3952
|
+
label: "Fit to View",
|
|
3953
|
+
type: "button",
|
|
3954
|
+
group: "zoom",
|
|
3955
|
+
execute: () => {
|
|
3956
|
+
instance.fitToPage?.();
|
|
3957
|
+
}
|
|
3958
|
+
},
|
|
3272
3959
|
{
|
|
3273
3960
|
id: "download",
|
|
3274
3961
|
icon: "download",
|
|
@@ -3286,10 +3973,21 @@ var CsvPlugin = class {
|
|
|
3286
3973
|
type: "button",
|
|
3287
3974
|
group: "actions",
|
|
3288
3975
|
execute: () => {
|
|
3289
|
-
instance.print?.();
|
|
3976
|
+
instance.print?.();
|
|
3977
|
+
}
|
|
3978
|
+
},
|
|
3979
|
+
{
|
|
3980
|
+
id: "open-window",
|
|
3981
|
+
icon: "open-window",
|
|
3982
|
+
label: "Open in Separate Full Window",
|
|
3983
|
+
type: "button",
|
|
3984
|
+
group: "actions",
|
|
3985
|
+
execute: () => {
|
|
3986
|
+
instance.openInSeparateWindow?.();
|
|
3290
3987
|
}
|
|
3291
3988
|
}
|
|
3292
|
-
|
|
3989
|
+
);
|
|
3990
|
+
return actions;
|
|
3293
3991
|
}
|
|
3294
3992
|
async render(ctx) {
|
|
3295
3993
|
const decoder = new TextDecoder("utf-8");
|
|
@@ -3301,33 +3999,62 @@ var CsvPlugin = class {
|
|
|
3301
3999
|
container.style.padding = "16px";
|
|
3302
4000
|
container.style.boxSizing = "border-box";
|
|
3303
4001
|
container.style.transformOrigin = "top left";
|
|
4002
|
+
const delimiter = ctx.metadata.extension === ".tsv" ? " " : ",";
|
|
4003
|
+
const allLines = text.split(/\r?\n/).filter((r) => r.trim().length > 0);
|
|
4004
|
+
const headerLine = allLines[0] || "";
|
|
4005
|
+
const headerCells = headerLine.split(delimiter);
|
|
4006
|
+
const dataLines = allLines.slice(1);
|
|
4007
|
+
const ROWS_PER_PAGE = 100;
|
|
4008
|
+
const totalPages = Math.max(1, Math.ceil(dataLines.length / ROWS_PER_PAGE));
|
|
4009
|
+
let currentPage = 1;
|
|
3304
4010
|
const table = document.createElement("table");
|
|
3305
4011
|
table.style.borderCollapse = "collapse";
|
|
3306
4012
|
table.style.width = "100%";
|
|
3307
|
-
table.style.fontFamily = "monospace
|
|
4013
|
+
table.style.fontFamily = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace';
|
|
3308
4014
|
table.style.fontSize = "13px";
|
|
3309
|
-
const
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
td.style.fontWeight = "bold";
|
|
3323
|
-
}
|
|
3324
|
-
tr.appendChild(td);
|
|
4015
|
+
const renderPage = (pageNum) => {
|
|
4016
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4017
|
+
table.innerHTML = "";
|
|
4018
|
+
const headerTr = document.createElement("tr");
|
|
4019
|
+
headerCells.forEach((cell) => {
|
|
4020
|
+
const th = document.createElement("th");
|
|
4021
|
+
th.textContent = cell.trim();
|
|
4022
|
+
th.style.border = "1px solid #d0d7de";
|
|
4023
|
+
th.style.padding = "8px 12px";
|
|
4024
|
+
th.style.backgroundColor = "#f6f8fa";
|
|
4025
|
+
th.style.fontWeight = "600";
|
|
4026
|
+
th.style.whiteSpace = "nowrap";
|
|
4027
|
+
headerTr.appendChild(th);
|
|
3325
4028
|
});
|
|
3326
|
-
table.appendChild(
|
|
3327
|
-
|
|
4029
|
+
table.appendChild(headerTr);
|
|
4030
|
+
const start = (currentPage - 1) * ROWS_PER_PAGE;
|
|
4031
|
+
const end = Math.min(dataLines.length, start + ROWS_PER_PAGE);
|
|
4032
|
+
const pageRows = dataLines.slice(start, end);
|
|
4033
|
+
pageRows.forEach((row, idx) => {
|
|
4034
|
+
const tr = document.createElement("tr");
|
|
4035
|
+
if (idx % 2 === 1) tr.style.backgroundColor = "#f8fafc";
|
|
4036
|
+
const cells = row.split(delimiter);
|
|
4037
|
+
cells.forEach((cell) => {
|
|
4038
|
+
const td = document.createElement("td");
|
|
4039
|
+
td.textContent = cell.trim();
|
|
4040
|
+
td.style.border = "1px solid #d0d7de";
|
|
4041
|
+
td.style.padding = "6px 12px";
|
|
4042
|
+
td.style.whiteSpace = "nowrap";
|
|
4043
|
+
tr.appendChild(td);
|
|
4044
|
+
});
|
|
4045
|
+
table.appendChild(tr);
|
|
4046
|
+
});
|
|
4047
|
+
container.scrollTop = 0;
|
|
4048
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4049
|
+
};
|
|
4050
|
+
renderPage(1);
|
|
3328
4051
|
container.appendChild(table);
|
|
3329
4052
|
ctx.container.appendChild(container);
|
|
3330
4053
|
let scale = 1;
|
|
4054
|
+
const applyScale = () => {
|
|
4055
|
+
container.style.transform = `scale(${scale})`;
|
|
4056
|
+
container.style.transformOrigin = "top left";
|
|
4057
|
+
};
|
|
3331
4058
|
const cleanup = () => {
|
|
3332
4059
|
container.remove();
|
|
3333
4060
|
ctx.container.innerHTML = "";
|
|
@@ -3335,22 +4062,86 @@ var CsvPlugin = class {
|
|
|
3335
4062
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3336
4063
|
return {
|
|
3337
4064
|
destroy: cleanup,
|
|
4065
|
+
getPageCount: () => totalPages,
|
|
4066
|
+
getCurrentPage: () => currentPage,
|
|
4067
|
+
goToPage: (page) => renderPage(page),
|
|
4068
|
+
getThumbnails: () => {
|
|
4069
|
+
const thumbnails = [];
|
|
4070
|
+
for (let i = 0; i < totalPages; i++) {
|
|
4071
|
+
const pageIdx = i;
|
|
4072
|
+
const startRow = pageIdx * ROWS_PER_PAGE + 1;
|
|
4073
|
+
const endRow = Math.min(dataLines.length, (pageIdx + 1) * ROWS_PER_PAGE);
|
|
4074
|
+
const label = totalPages === 1 ? "Table" : `Page ${pageIdx + 1} (${startRow}-${endRow})`;
|
|
4075
|
+
thumbnails.push({
|
|
4076
|
+
index: pageIdx,
|
|
4077
|
+
label,
|
|
4078
|
+
render: async (canvas) => {
|
|
4079
|
+
canvas.width = 140;
|
|
4080
|
+
canvas.height = 100;
|
|
4081
|
+
const c = canvas.getContext("2d");
|
|
4082
|
+
if (!c) return;
|
|
4083
|
+
c.fillStyle = "#ffffff";
|
|
4084
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4085
|
+
c.fillStyle = "#2563eb";
|
|
4086
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
4087
|
+
c.fillStyle = "#ffffff";
|
|
4088
|
+
c.font = "bold 8px sans-serif";
|
|
4089
|
+
c.fillText(`\u{1F4C8} ${label.slice(0, 18)}`, 6, 11);
|
|
4090
|
+
const startY = 17;
|
|
4091
|
+
const rowH = 13;
|
|
4092
|
+
const colW = 28;
|
|
4093
|
+
const cols = Math.min(4, headerCells.length || 4);
|
|
4094
|
+
c.fillStyle = "#f1f5f9";
|
|
4095
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
4096
|
+
c.strokeStyle = "#cbd5e1";
|
|
4097
|
+
c.lineWidth = 0.8;
|
|
4098
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
4099
|
+
c.fillStyle = "#64748b";
|
|
4100
|
+
c.font = "bold 7px sans-serif";
|
|
4101
|
+
for (let ci = 0; ci < cols; ci++) {
|
|
4102
|
+
const hName = headerCells[ci] || `Col ${ci + 1}`;
|
|
4103
|
+
c.fillText(hName.slice(0, 5), 8 + ci * colW, startY + 9);
|
|
4104
|
+
}
|
|
4105
|
+
const rowsToPreview = dataLines.slice(pageIdx * ROWS_PER_PAGE, pageIdx * ROWS_PER_PAGE + 5);
|
|
4106
|
+
for (let ri = 0; ri < rowsToPreview.length; ri++) {
|
|
4107
|
+
const y = startY + (ri + 1) * rowH;
|
|
4108
|
+
if (y > canvas.height - 2) break;
|
|
4109
|
+
c.strokeStyle = "#e2e8f0";
|
|
4110
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
4111
|
+
const cVals = rowsToPreview[ri].split(delimiter);
|
|
4112
|
+
c.fillStyle = "#334155";
|
|
4113
|
+
c.font = "6px sans-serif";
|
|
4114
|
+
for (let ci = 0; ci < cols; ci++) {
|
|
4115
|
+
const val = cVals[ci] || "";
|
|
4116
|
+
c.fillText(val.trim().slice(0, 6), 8 + ci * colW, y + 9);
|
|
4117
|
+
}
|
|
4118
|
+
}
|
|
4119
|
+
c.strokeStyle = "#cbd5e1";
|
|
4120
|
+
c.lineWidth = 1;
|
|
4121
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4122
|
+
}
|
|
4123
|
+
});
|
|
4124
|
+
}
|
|
4125
|
+
return thumbnails;
|
|
4126
|
+
},
|
|
3338
4127
|
zoomIn: () => {
|
|
3339
4128
|
scale += 0.1;
|
|
3340
|
-
|
|
4129
|
+
applyScale();
|
|
3341
4130
|
},
|
|
3342
4131
|
zoomOut: () => {
|
|
3343
4132
|
scale = Math.max(0.2, scale - 0.1);
|
|
3344
|
-
|
|
4133
|
+
applyScale();
|
|
3345
4134
|
},
|
|
3346
4135
|
getZoom: () => scale,
|
|
3347
4136
|
setZoom: (level) => {
|
|
3348
4137
|
scale = level;
|
|
3349
|
-
|
|
4138
|
+
applyScale();
|
|
3350
4139
|
},
|
|
3351
4140
|
fitToPage: () => {
|
|
3352
|
-
|
|
3353
|
-
|
|
4141
|
+
const availW = Math.max(280, (ctx.container.clientWidth || window.innerWidth) - 48);
|
|
4142
|
+
const tW = table.offsetWidth || 600;
|
|
4143
|
+
scale = Math.max(0.35, Math.min(1, availW / tW));
|
|
4144
|
+
applyScale();
|
|
3354
4145
|
},
|
|
3355
4146
|
download: () => {
|
|
3356
4147
|
const blob = new Blob([ctx.buffer], { type: "text/csv" });
|
|
@@ -3414,28 +4205,34 @@ var CodePlugin = class {
|
|
|
3414
4205
|
getToolbarActions(instance) {
|
|
3415
4206
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3416
4207
|
const actions = [];
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
4208
|
+
actions.push({
|
|
4209
|
+
id: "thumbnails",
|
|
4210
|
+
icon: "thumbnails",
|
|
4211
|
+
label: "Page Thumbnails",
|
|
4212
|
+
type: "button",
|
|
4213
|
+
group: "navigation",
|
|
4214
|
+
execute: () => instance.toggleThumbnails?.()
|
|
4215
|
+
});
|
|
4216
|
+
actions.push({
|
|
4217
|
+
id: "page-nav",
|
|
4218
|
+
icon: "",
|
|
4219
|
+
label: "Page Navigation",
|
|
4220
|
+
type: "page-nav",
|
|
4221
|
+
group: "navigation",
|
|
4222
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4223
|
+
max: totalPages,
|
|
4224
|
+
execute: (action, page) => {
|
|
4225
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4226
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4227
|
+
if (action === "prev") {
|
|
4228
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4229
|
+
} else if (action === "next") {
|
|
4230
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4231
|
+
} else if (typeof page === "number") {
|
|
4232
|
+
instance.goToPage?.(page);
|
|
3436
4233
|
}
|
|
3437
|
-
}
|
|
3438
|
-
}
|
|
4234
|
+
}
|
|
4235
|
+
});
|
|
3439
4236
|
actions.push(
|
|
3440
4237
|
{
|
|
3441
4238
|
id: "zoom-out",
|
|
@@ -3579,16 +4376,19 @@ var CodePlugin = class {
|
|
|
3579
4376
|
let fontSize = 13;
|
|
3580
4377
|
let rotation = 0;
|
|
3581
4378
|
let zoomLevel = 1;
|
|
4379
|
+
let isUserZoomed = false;
|
|
3582
4380
|
const pre = document.createElement("pre");
|
|
3583
4381
|
const code = document.createElement("code");
|
|
3584
4382
|
if (isTxt) {
|
|
4383
|
+
container.style.overflowX = "hidden";
|
|
4384
|
+
container.style.overflowY = "auto";
|
|
3585
4385
|
container.style.backgroundColor = "#f1f5f9";
|
|
3586
|
-
container.style.padding = "
|
|
4386
|
+
container.style.padding = "16px 8px";
|
|
3587
4387
|
container.style.boxSizing = "border-box";
|
|
3588
4388
|
container.style.display = "flex";
|
|
3589
4389
|
container.style.flexDirection = "column";
|
|
3590
4390
|
container.style.alignItems = "center";
|
|
3591
|
-
pre.style.margin = "0";
|
|
4391
|
+
pre.style.margin = "0 auto";
|
|
3592
4392
|
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3593
4393
|
pre.style.fontSize = "13px";
|
|
3594
4394
|
pre.style.color = "#1e293b";
|
|
@@ -3600,10 +4400,12 @@ var CodePlugin = class {
|
|
|
3600
4400
|
pre.style.minHeight = "1056px";
|
|
3601
4401
|
pre.style.padding = "72px 56px";
|
|
3602
4402
|
pre.style.boxSizing = "border-box";
|
|
3603
|
-
pre.style.boxShadow = "0 4px
|
|
4403
|
+
pre.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
3604
4404
|
pre.style.borderRadius = "4px";
|
|
3605
4405
|
pre.style.transformOrigin = "top center";
|
|
4406
|
+
pre.style.transition = "transform 0.15s ease";
|
|
3606
4407
|
} else {
|
|
4408
|
+
container.style.overflow = "auto";
|
|
3607
4409
|
container.style.backgroundColor = "#1e1e1e";
|
|
3608
4410
|
container.style.color = "#d4d4d4";
|
|
3609
4411
|
container.style.padding = "16px";
|
|
@@ -3635,42 +4437,9 @@ var CodePlugin = class {
|
|
|
3635
4437
|
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
3636
4438
|
pre.appendChild(code);
|
|
3637
4439
|
container.appendChild(pre);
|
|
3638
|
-
let indicator = null;
|
|
3639
|
-
if (totalPages > 1) {
|
|
3640
|
-
indicator = document.createElement("div");
|
|
3641
|
-
indicator.className = "fp-code-page-indicator";
|
|
3642
|
-
indicator.style.position = "sticky";
|
|
3643
|
-
indicator.style.bottom = "16px";
|
|
3644
|
-
if (isTxt) {
|
|
3645
|
-
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3646
|
-
indicator.style.color = "#334155";
|
|
3647
|
-
indicator.style.border = "1px solid #e2e8f0";
|
|
3648
|
-
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3649
|
-
} else {
|
|
3650
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3651
|
-
indicator.style.color = "#f8fafc";
|
|
3652
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3653
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3654
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
3655
|
-
}
|
|
3656
|
-
indicator.style.fontSize = "12px";
|
|
3657
|
-
indicator.style.fontWeight = "600";
|
|
3658
|
-
indicator.style.padding = "5px 14px";
|
|
3659
|
-
indicator.style.borderRadius = "20px";
|
|
3660
|
-
indicator.style.zIndex = "10";
|
|
3661
|
-
indicator.style.userSelect = "none";
|
|
3662
|
-
indicator.style.pointerEvents = "none";
|
|
3663
|
-
indicator.style.textAlign = "center";
|
|
3664
|
-
indicator.style.width = "fit-content";
|
|
3665
|
-
indicator.style.margin = "16px auto 0";
|
|
3666
|
-
container.appendChild(indicator);
|
|
3667
|
-
}
|
|
3668
4440
|
const showPage = (pageNum) => {
|
|
3669
4441
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3670
4442
|
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
3671
|
-
if (indicator) {
|
|
3672
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3673
|
-
}
|
|
3674
4443
|
container.scrollTop = 0;
|
|
3675
4444
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3676
4445
|
};
|
|
@@ -3678,36 +4447,90 @@ var CodePlugin = class {
|
|
|
3678
4447
|
showPage(1);
|
|
3679
4448
|
}
|
|
3680
4449
|
ctx.container.appendChild(container);
|
|
3681
|
-
const
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
ctx.container.innerHTML = "";
|
|
4450
|
+
const calculateTxtFit = () => {
|
|
4451
|
+
const availW = Math.max(280, container.clientWidth - 32);
|
|
4452
|
+
return Math.max(0.4, Math.min(3, availW / 816));
|
|
3685
4453
|
};
|
|
3686
|
-
ctx.signal.addEventListener("abort", cleanup);
|
|
3687
4454
|
const updateTransform = () => {
|
|
3688
4455
|
if (isTxt) {
|
|
3689
4456
|
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
4457
|
+
const scaledH = 1056 * zoomLevel;
|
|
4458
|
+
const extraH = Math.max(0, scaledH - 1056);
|
|
4459
|
+
pre.style.marginBottom = `${extraH + 32}px`;
|
|
3690
4460
|
} else {
|
|
3691
4461
|
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3692
4462
|
pre.style.fontSize = `${fontSize}px`;
|
|
3693
4463
|
}
|
|
3694
4464
|
};
|
|
4465
|
+
let resizeObserver = null;
|
|
4466
|
+
if (isTxt) {
|
|
4467
|
+
setTimeout(() => {
|
|
4468
|
+
zoomLevel = calculateTxtFit();
|
|
4469
|
+
updateTransform();
|
|
4470
|
+
}, 60);
|
|
4471
|
+
resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
4472
|
+
if (!isUserZoomed) {
|
|
4473
|
+
zoomLevel = calculateTxtFit();
|
|
4474
|
+
updateTransform();
|
|
4475
|
+
}
|
|
4476
|
+
}) : null;
|
|
4477
|
+
resizeObserver?.observe(container);
|
|
4478
|
+
}
|
|
4479
|
+
const cleanup = () => {
|
|
4480
|
+
resizeObserver?.disconnect();
|
|
4481
|
+
container.remove();
|
|
4482
|
+
ctx.container.innerHTML = "";
|
|
4483
|
+
};
|
|
4484
|
+
ctx.signal.addEventListener("abort", cleanup);
|
|
3695
4485
|
return {
|
|
3696
4486
|
destroy: cleanup,
|
|
3697
4487
|
getPageCount: () => totalPages,
|
|
3698
4488
|
getCurrentPage: () => currentPage,
|
|
3699
4489
|
goToPage: (page) => showPage(page),
|
|
4490
|
+
getThumbnails: () => {
|
|
4491
|
+
return rawPages.map((pageText, idx) => ({
|
|
4492
|
+
index: idx,
|
|
4493
|
+
label: `Page ${idx + 1}`,
|
|
4494
|
+
render: async (canvas) => {
|
|
4495
|
+
canvas.width = 140;
|
|
4496
|
+
canvas.height = 180;
|
|
4497
|
+
const c = canvas.getContext("2d");
|
|
4498
|
+
if (!c) return;
|
|
4499
|
+
c.fillStyle = "#ffffff";
|
|
4500
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4501
|
+
c.strokeStyle = "#cbd5e1";
|
|
4502
|
+
c.lineWidth = 1;
|
|
4503
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4504
|
+
c.fillStyle = "#64748b";
|
|
4505
|
+
const lines = (pageText || "").split("\n").slice(0, 24);
|
|
4506
|
+
const lineH = 6;
|
|
4507
|
+
const startY = 14;
|
|
4508
|
+
const startX = 12;
|
|
4509
|
+
const maxW = canvas.width - 24;
|
|
4510
|
+
c.font = "5px monospace";
|
|
4511
|
+
for (let li = 0; li < lines.length; li++) {
|
|
4512
|
+
const l = lines[li].trim();
|
|
4513
|
+
if (!l) continue;
|
|
4514
|
+
const y = startY + li * lineH;
|
|
4515
|
+
if (y > canvas.height - 12) break;
|
|
4516
|
+
c.fillText(l.slice(0, 30), startX, y, maxW);
|
|
4517
|
+
}
|
|
4518
|
+
}
|
|
4519
|
+
}));
|
|
4520
|
+
},
|
|
3700
4521
|
zoomIn: () => {
|
|
4522
|
+
isUserZoomed = true;
|
|
3701
4523
|
if (isTxt) {
|
|
3702
|
-
zoomLevel = Math.min(3, zoomLevel + 0.
|
|
4524
|
+
zoomLevel = Math.min(3.5, zoomLevel + 0.15);
|
|
3703
4525
|
} else {
|
|
3704
4526
|
fontSize = Math.min(32, fontSize + 2);
|
|
3705
4527
|
}
|
|
3706
4528
|
updateTransform();
|
|
3707
4529
|
},
|
|
3708
4530
|
zoomOut: () => {
|
|
4531
|
+
isUserZoomed = true;
|
|
3709
4532
|
if (isTxt) {
|
|
3710
|
-
zoomLevel = Math.max(0.1, zoomLevel - 0.
|
|
4533
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.15);
|
|
3711
4534
|
} else {
|
|
3712
4535
|
fontSize = Math.max(8, fontSize - 2);
|
|
3713
4536
|
}
|
|
@@ -3715,6 +4538,7 @@ var CodePlugin = class {
|
|
|
3715
4538
|
},
|
|
3716
4539
|
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
3717
4540
|
setZoom: (level) => {
|
|
4541
|
+
isUserZoomed = true;
|
|
3718
4542
|
if (isTxt) {
|
|
3719
4543
|
zoomLevel = level;
|
|
3720
4544
|
} else {
|
|
@@ -3723,9 +4547,10 @@ var CodePlugin = class {
|
|
|
3723
4547
|
updateTransform();
|
|
3724
4548
|
},
|
|
3725
4549
|
fitToPage: () => {
|
|
4550
|
+
isUserZoomed = false;
|
|
3726
4551
|
fontSize = 13;
|
|
3727
4552
|
rotation = 0;
|
|
3728
|
-
zoomLevel = isTxt ?
|
|
4553
|
+
zoomLevel = isTxt ? calculateTxtFit() : 1;
|
|
3729
4554
|
updateTransform();
|
|
3730
4555
|
},
|
|
3731
4556
|
rotateCW: () => {
|
|
@@ -4606,28 +5431,26 @@ var RtfPlugin = class {
|
|
|
4606
5431
|
getToolbarActions(instance) {
|
|
4607
5432
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4608
5433
|
const actions = [];
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
if (
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
instance.goToPage?.(page);
|
|
4627
|
-
}
|
|
5434
|
+
actions.push({
|
|
5435
|
+
id: "page-nav",
|
|
5436
|
+
icon: "",
|
|
5437
|
+
label: "Page Navigation",
|
|
5438
|
+
type: "page-nav",
|
|
5439
|
+
group: "navigation",
|
|
5440
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5441
|
+
max: totalPages,
|
|
5442
|
+
execute: (action, page) => {
|
|
5443
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5444
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5445
|
+
if (action === "prev") {
|
|
5446
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5447
|
+
} else if (action === "next") {
|
|
5448
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5449
|
+
} else if (typeof page === "number") {
|
|
5450
|
+
instance.goToPage?.(page);
|
|
4628
5451
|
}
|
|
4629
|
-
}
|
|
4630
|
-
}
|
|
5452
|
+
}
|
|
5453
|
+
});
|
|
4631
5454
|
actions.push(
|
|
4632
5455
|
{
|
|
4633
5456
|
id: "zoom-out",
|
|
@@ -4699,43 +5522,57 @@ var RtfPlugin = class {
|
|
|
4699
5522
|
async render(ctx) {
|
|
4700
5523
|
const wrapper = document.createElement("div");
|
|
4701
5524
|
wrapper.className = "fp-rtf-wrapper";
|
|
4702
|
-
wrapper.style.padding = "
|
|
4703
|
-
wrapper.style.
|
|
5525
|
+
wrapper.style.padding = "0";
|
|
5526
|
+
wrapper.style.width = "816px";
|
|
4704
5527
|
wrapper.style.margin = "0 auto";
|
|
4705
|
-
wrapper.style.
|
|
4706
|
-
wrapper.style.
|
|
4707
|
-
wrapper.style.
|
|
4708
|
-
wrapper.style.
|
|
5528
|
+
wrapper.style.boxSizing = "border-box";
|
|
5529
|
+
wrapper.style.display = "flex";
|
|
5530
|
+
wrapper.style.flexDirection = "column";
|
|
5531
|
+
wrapper.style.alignItems = "center";
|
|
5532
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4709
5533
|
wrapper.style.transformOrigin = "top center";
|
|
4710
|
-
wrapper.style.transition = "transform 0.
|
|
4711
|
-
ctx.container.style.
|
|
4712
|
-
ctx.container.style.
|
|
5534
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5535
|
+
ctx.container.style.overflowX = "hidden";
|
|
5536
|
+
ctx.container.style.overflowY = "auto";
|
|
5537
|
+
ctx.container.style.padding = "16px 8px";
|
|
4713
5538
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
4714
5539
|
ctx.container.appendChild(wrapper);
|
|
4715
5540
|
let scale = 1;
|
|
4716
5541
|
let rotation = 0;
|
|
4717
5542
|
let pageElements = [];
|
|
4718
|
-
let
|
|
5543
|
+
let isUserZoomed = false;
|
|
5544
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
4719
5545
|
const calculateFitScale = (mode = fitMode) => {
|
|
4720
5546
|
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4721
|
-
const elW =
|
|
4722
|
-
const singlePageH =
|
|
4723
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
4724
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
5547
|
+
const elW = 816;
|
|
5548
|
+
const singlePageH = activeEl?.offsetHeight || 1056;
|
|
5549
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
5550
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
4725
5551
|
const sW = availW / elW;
|
|
4726
5552
|
const sH = availH / singlePageH;
|
|
4727
5553
|
if (mode === "page") {
|
|
4728
|
-
return Math.max(0.
|
|
5554
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
4729
5555
|
}
|
|
4730
|
-
return Math.max(0.
|
|
5556
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
4731
5557
|
};
|
|
4732
5558
|
const applyTransform = () => {
|
|
4733
5559
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4734
5560
|
wrapper.style.transformOrigin = "top center";
|
|
5561
|
+
const activeEl = pageElements[currentPage - 1];
|
|
5562
|
+
const baseH = activeEl?.offsetHeight || 1056;
|
|
5563
|
+
const scaledH = baseH * scale;
|
|
5564
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
5565
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
4735
5566
|
};
|
|
5567
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
5568
|
+
if (!isUserZoomed) {
|
|
5569
|
+
scale = calculateFitScale(fitMode);
|
|
5570
|
+
applyTransform();
|
|
5571
|
+
}
|
|
5572
|
+
}) : null;
|
|
5573
|
+
resizeObserver?.observe(ctx.container);
|
|
4736
5574
|
setTimeout(() => {
|
|
4737
|
-
|
|
4738
|
-
scale = calculateFitScale("width");
|
|
5575
|
+
scale = calculateFitScale(fitMode);
|
|
4739
5576
|
applyTransform();
|
|
4740
5577
|
}, 60);
|
|
4741
5578
|
try {
|
|
@@ -4745,20 +5582,34 @@ var RtfPlugin = class {
|
|
|
4745
5582
|
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
4746
5583
|
const htmlElements = await doc.render();
|
|
4747
5584
|
const contentNodes = [];
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
5585
|
+
const extractBlocks = (nodes) => {
|
|
5586
|
+
for (const item of nodes) {
|
|
5587
|
+
if (!item || !(item instanceof HTMLElement)) continue;
|
|
5588
|
+
const tag = item.tagName.toLowerCase();
|
|
5589
|
+
const hasChildBlocks = Array.from(item.children).some((c) => {
|
|
5590
|
+
const ct = c.tagName.toLowerCase();
|
|
5591
|
+
return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
|
|
5592
|
+
});
|
|
5593
|
+
if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
|
|
5594
|
+
extractBlocks(Array.from(item.children));
|
|
5595
|
+
} else {
|
|
5596
|
+
if (tag === "p" || tag === "div") {
|
|
5597
|
+
item.style.display = "block";
|
|
5598
|
+
item.style.marginBottom = "12px";
|
|
5599
|
+
item.style.lineHeight = "1.6";
|
|
5600
|
+
}
|
|
5601
|
+
contentNodes.push(item);
|
|
5602
|
+
}
|
|
4753
5603
|
}
|
|
4754
|
-
}
|
|
5604
|
+
};
|
|
5605
|
+
extractBlocks(htmlElements);
|
|
4755
5606
|
wrapper.innerHTML = "";
|
|
4756
5607
|
contentNodes.forEach((node) => wrapper.appendChild(node));
|
|
4757
5608
|
const childHeights = contentNodes.map((c) => {
|
|
4758
5609
|
const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
|
|
4759
5610
|
const offH = c.offsetHeight || 0;
|
|
4760
5611
|
const textLen = c.textContent?.trim().length || 0;
|
|
4761
|
-
const estH = Math.max(
|
|
5612
|
+
const estH = Math.max(28, Math.ceil(textLen / 75) * 24 + 16);
|
|
4762
5613
|
return Math.max(rectH, offH, estH);
|
|
4763
5614
|
});
|
|
4764
5615
|
wrapper.innerHTML = "";
|
|
@@ -4775,6 +5626,7 @@ var RtfPlugin = class {
|
|
|
4775
5626
|
card.style.marginBottom = "24px";
|
|
4776
5627
|
card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4777
5628
|
card.style.lineHeight = "1.6";
|
|
5629
|
+
card.style.color = "#1e293b";
|
|
4778
5630
|
return card;
|
|
4779
5631
|
};
|
|
4780
5632
|
let curCard = createRtfCard();
|
|
@@ -4810,9 +5662,8 @@ var RtfPlugin = class {
|
|
|
4810
5662
|
pageCard.style.padding = "72px 56px";
|
|
4811
5663
|
pageCard.style.width = "816px";
|
|
4812
5664
|
pageCard.style.minHeight = "1056px";
|
|
4813
|
-
pageCard.style.maxWidth = "100%";
|
|
4814
5665
|
pageCard.style.boxSizing = "border-box";
|
|
4815
|
-
pageCard.style.fontFamily = "serif
|
|
5666
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4816
5667
|
pageCard.style.fontSize = "12pt";
|
|
4817
5668
|
pageCard.style.lineHeight = "1.6";
|
|
4818
5669
|
pageCard.style.color = "#1e293b";
|
|
@@ -4825,29 +5676,6 @@ var RtfPlugin = class {
|
|
|
4825
5676
|
}
|
|
4826
5677
|
const totalPages = Math.max(1, pageElements.length);
|
|
4827
5678
|
let currentPage = 1;
|
|
4828
|
-
let indicator = null;
|
|
4829
|
-
if (totalPages > 1) {
|
|
4830
|
-
indicator = document.createElement("div");
|
|
4831
|
-
indicator.className = "fp-rtf-page-indicator";
|
|
4832
|
-
indicator.style.position = "sticky";
|
|
4833
|
-
indicator.style.bottom = "16px";
|
|
4834
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4835
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
4836
|
-
indicator.style.color = "#f8fafc";
|
|
4837
|
-
indicator.style.fontSize = "12px";
|
|
4838
|
-
indicator.style.fontWeight = "600";
|
|
4839
|
-
indicator.style.padding = "5px 14px";
|
|
4840
|
-
indicator.style.borderRadius = "20px";
|
|
4841
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4842
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4843
|
-
indicator.style.zIndex = "10";
|
|
4844
|
-
indicator.style.userSelect = "none";
|
|
4845
|
-
indicator.style.pointerEvents = "none";
|
|
4846
|
-
indicator.style.textAlign = "center";
|
|
4847
|
-
indicator.style.width = "fit-content";
|
|
4848
|
-
indicator.style.margin = "16px auto 0";
|
|
4849
|
-
ctx.container.appendChild(indicator);
|
|
4850
|
-
}
|
|
4851
5679
|
const showPage = (pageNum) => {
|
|
4852
5680
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4853
5681
|
if (totalPages > 1) {
|
|
@@ -4855,9 +5683,6 @@ var RtfPlugin = class {
|
|
|
4855
5683
|
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4856
5684
|
});
|
|
4857
5685
|
}
|
|
4858
|
-
if (indicator) {
|
|
4859
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4860
|
-
}
|
|
4861
5686
|
ctx.container.scrollTop = 0;
|
|
4862
5687
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4863
5688
|
};
|
|
@@ -4865,7 +5690,7 @@ var RtfPlugin = class {
|
|
|
4865
5690
|
showPage(1);
|
|
4866
5691
|
}
|
|
4867
5692
|
const cleanup = () => {
|
|
4868
|
-
|
|
5693
|
+
resizeObserver?.disconnect();
|
|
4869
5694
|
wrapper.remove();
|
|
4870
5695
|
ctx.container.innerHTML = "";
|
|
4871
5696
|
};
|
|
@@ -4876,21 +5701,25 @@ var RtfPlugin = class {
|
|
|
4876
5701
|
getCurrentPage: () => currentPage,
|
|
4877
5702
|
goToPage: (page) => showPage(page),
|
|
4878
5703
|
zoomIn: () => {
|
|
5704
|
+
isUserZoomed = true;
|
|
4879
5705
|
scale += 0.15;
|
|
4880
5706
|
applyTransform();
|
|
4881
5707
|
},
|
|
4882
5708
|
zoomOut: () => {
|
|
5709
|
+
isUserZoomed = true;
|
|
4883
5710
|
scale = Math.max(0.2, scale - 0.15);
|
|
4884
5711
|
applyTransform();
|
|
4885
5712
|
},
|
|
4886
5713
|
getZoom: () => scale,
|
|
4887
5714
|
setZoom: (level) => {
|
|
5715
|
+
isUserZoomed = true;
|
|
4888
5716
|
scale = level;
|
|
4889
5717
|
applyTransform();
|
|
4890
5718
|
},
|
|
4891
5719
|
fitToPage: () => {
|
|
4892
|
-
|
|
4893
|
-
|
|
5720
|
+
isUserZoomed = false;
|
|
5721
|
+
fitMode = "width";
|
|
5722
|
+
scale = calculateFitScale("width");
|
|
4894
5723
|
rotation = 0;
|
|
4895
5724
|
applyTransform();
|
|
4896
5725
|
},
|
|
@@ -5078,40 +5907,36 @@ var OpenDocumentPlugin = class {
|
|
|
5078
5907
|
const isPresentation = instance.isPresentation;
|
|
5079
5908
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5080
5909
|
const actions = [];
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
max
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
if (
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
instance.goToPage?.(page);
|
|
5109
|
-
} else if (typeof action === "number") {
|
|
5110
|
-
instance.goToPage?.(action);
|
|
5111
|
-
}
|
|
5910
|
+
actions.push({
|
|
5911
|
+
id: "thumbnails",
|
|
5912
|
+
icon: "thumbnails",
|
|
5913
|
+
label: isPresentation ? "Slide Thumbnails" : "Page Thumbnails",
|
|
5914
|
+
type: "button",
|
|
5915
|
+
group: "navigation",
|
|
5916
|
+
execute: () => instance.toggleThumbnails?.()
|
|
5917
|
+
});
|
|
5918
|
+
actions.push({
|
|
5919
|
+
id: "page-nav",
|
|
5920
|
+
icon: "",
|
|
5921
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
5922
|
+
type: "page-nav",
|
|
5923
|
+
group: "navigation",
|
|
5924
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5925
|
+
max: totalPages,
|
|
5926
|
+
execute: (action, page) => {
|
|
5927
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5928
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5929
|
+
if (action === "prev") {
|
|
5930
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5931
|
+
} else if (action === "next") {
|
|
5932
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5933
|
+
} else if (typeof page === "number") {
|
|
5934
|
+
instance.goToPage?.(page);
|
|
5935
|
+
} else if (typeof action === "number") {
|
|
5936
|
+
instance.goToPage?.(action);
|
|
5112
5937
|
}
|
|
5113
|
-
}
|
|
5114
|
-
}
|
|
5938
|
+
}
|
|
5939
|
+
});
|
|
5115
5940
|
actions.push(
|
|
5116
5941
|
{
|
|
5117
5942
|
id: "zoom-out",
|
|
@@ -5202,49 +6027,65 @@ var OpenDocumentPlugin = class {
|
|
|
5202
6027
|
container.className = "fp-odf-container";
|
|
5203
6028
|
container.style.width = "100%";
|
|
5204
6029
|
container.style.height = "100%";
|
|
5205
|
-
container.style.
|
|
5206
|
-
container.style.
|
|
6030
|
+
container.style.overflowX = "hidden";
|
|
6031
|
+
container.style.overflowY = "auto";
|
|
6032
|
+
container.style.padding = "16px 8px";
|
|
5207
6033
|
container.style.backgroundColor = "#f1f5f9";
|
|
5208
6034
|
const wrapper = document.createElement("div");
|
|
5209
6035
|
wrapper.className = "fp-odf-wrapper";
|
|
5210
6036
|
wrapper.style.margin = "0 auto";
|
|
6037
|
+
wrapper.style.width = isPresentation ? "960px" : "816px";
|
|
6038
|
+
wrapper.style.boxSizing = "border-box";
|
|
5211
6039
|
wrapper.style.backgroundColor = "#ffffff";
|
|
5212
6040
|
wrapper.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
5213
6041
|
wrapper.style.borderRadius = "4px";
|
|
5214
6042
|
wrapper.style.transformOrigin = "top center";
|
|
5215
|
-
wrapper.style.transition = "transform 0.
|
|
6043
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5216
6044
|
container.appendChild(wrapper);
|
|
5217
6045
|
ctx.container.appendChild(container);
|
|
5218
6046
|
let scale = 1;
|
|
5219
6047
|
let rotation = 0;
|
|
5220
|
-
let
|
|
6048
|
+
let isUserZoomed = false;
|
|
6049
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6050
|
+
let currentPage = 1;
|
|
6051
|
+
let totalPages = 1;
|
|
6052
|
+
let slides = [];
|
|
5221
6053
|
const calculateFitScale = (mode = fitMode) => {
|
|
5222
|
-
const
|
|
5223
|
-
const
|
|
5224
|
-
const
|
|
5225
|
-
const
|
|
6054
|
+
const activeSlide = slides[currentPage - 1];
|
|
6055
|
+
const elW = isPresentation ? 960 : 816;
|
|
6056
|
+
const singlePageH = Math.min(activeSlide?.offsetHeight || wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
6057
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6058
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5226
6059
|
const sW = availW / elW;
|
|
5227
6060
|
const sH = availH / (isPresentation ? 540 : singlePageH);
|
|
5228
6061
|
if (isPresentation) {
|
|
5229
|
-
return Math.min(
|
|
6062
|
+
return Math.min(2.5, Math.min(sW, sH));
|
|
5230
6063
|
}
|
|
5231
6064
|
if (mode === "page") {
|
|
5232
|
-
return Math.max(0.
|
|
6065
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5233
6066
|
}
|
|
5234
|
-
return Math.max(0.
|
|
6067
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5235
6068
|
};
|
|
5236
6069
|
const applyTransform = () => {
|
|
5237
6070
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5238
6071
|
wrapper.style.transformOrigin = "top center";
|
|
6072
|
+
const activeSlide = slides[currentPage - 1];
|
|
6073
|
+
const baseH = activeSlide?.offsetHeight || wrapper.offsetHeight || 1056;
|
|
6074
|
+
const scaledH = baseH * scale;
|
|
6075
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6076
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
5239
6077
|
};
|
|
6078
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6079
|
+
if (!isUserZoomed) {
|
|
6080
|
+
scale = calculateFitScale(fitMode);
|
|
6081
|
+
applyTransform();
|
|
6082
|
+
}
|
|
6083
|
+
}) : null;
|
|
6084
|
+
resizeObserver?.observe(ctx.container);
|
|
5240
6085
|
setTimeout(() => {
|
|
5241
|
-
|
|
5242
|
-
scale = calculateFitScale("width");
|
|
6086
|
+
scale = calculateFitScale(fitMode);
|
|
5243
6087
|
applyTransform();
|
|
5244
6088
|
}, 60);
|
|
5245
|
-
let currentPage = 1;
|
|
5246
|
-
let totalPages = 1;
|
|
5247
|
-
let slides = [];
|
|
5248
6089
|
if (isPresentation) {
|
|
5249
6090
|
wrapper.style.maxWidth = "960px";
|
|
5250
6091
|
wrapper.style.aspectRatio = "16 / 9";
|
|
@@ -5345,24 +6186,9 @@ var OpenDocumentPlugin = class {
|
|
|
5345
6186
|
wrapper.appendChild(page);
|
|
5346
6187
|
slides.push(page);
|
|
5347
6188
|
});
|
|
5348
|
-
const pageIndicator = document.createElement("div");
|
|
5349
|
-
pageIndicator.className = "fp-odt-page-indicator";
|
|
5350
|
-
pageIndicator.style.position = "sticky";
|
|
5351
|
-
pageIndicator.style.bottom = "16px";
|
|
5352
|
-
pageIndicator.style.left = "50%";
|
|
5353
|
-
pageIndicator.style.transform = "translateX(-50%)";
|
|
5354
|
-
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
5355
|
-
pageIndicator.style.color = "#fff";
|
|
5356
|
-
pageIndicator.style.padding = "6px 12px";
|
|
5357
|
-
pageIndicator.style.borderRadius = "16px";
|
|
5358
|
-
pageIndicator.style.fontSize = "12px";
|
|
5359
|
-
pageIndicator.style.zIndex = "100";
|
|
5360
|
-
pageIndicator.style.display = "inline-block";
|
|
5361
|
-
pageIndicator.style.width = "fit-content";
|
|
5362
|
-
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
5363
|
-
container.appendChild(pageIndicator);
|
|
5364
6189
|
}
|
|
5365
6190
|
const cleanup = () => {
|
|
6191
|
+
resizeObserver?.disconnect();
|
|
5366
6192
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
5367
6193
|
container.remove();
|
|
5368
6194
|
ctx.container.innerHTML = "";
|
|
@@ -5374,10 +6200,6 @@ var OpenDocumentPlugin = class {
|
|
|
5374
6200
|
slides.forEach((s, idx) => {
|
|
5375
6201
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
5376
6202
|
});
|
|
5377
|
-
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
5378
|
-
if (indicator) {
|
|
5379
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5380
|
-
}
|
|
5381
6203
|
container.scrollTop = 0;
|
|
5382
6204
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5383
6205
|
};
|
|
@@ -5385,21 +6207,25 @@ var OpenDocumentPlugin = class {
|
|
|
5385
6207
|
destroy: cleanup,
|
|
5386
6208
|
isPresentation,
|
|
5387
6209
|
zoomIn: () => {
|
|
6210
|
+
isUserZoomed = true;
|
|
5388
6211
|
scale += 0.15;
|
|
5389
6212
|
applyTransform();
|
|
5390
6213
|
},
|
|
5391
6214
|
zoomOut: () => {
|
|
6215
|
+
isUserZoomed = true;
|
|
5392
6216
|
scale = Math.max(0.2, scale - 0.15);
|
|
5393
6217
|
applyTransform();
|
|
5394
6218
|
},
|
|
5395
6219
|
getZoom: () => scale,
|
|
5396
6220
|
setZoom: (level) => {
|
|
6221
|
+
isUserZoomed = true;
|
|
5397
6222
|
scale = level;
|
|
5398
6223
|
applyTransform();
|
|
5399
6224
|
},
|
|
5400
6225
|
fitToPage: () => {
|
|
5401
|
-
|
|
5402
|
-
|
|
6226
|
+
isUserZoomed = false;
|
|
6227
|
+
fitMode = "width";
|
|
6228
|
+
scale = calculateFitScale("width");
|
|
5403
6229
|
rotation = 0;
|
|
5404
6230
|
applyTransform();
|
|
5405
6231
|
},
|
|
@@ -5415,23 +6241,45 @@ var OpenDocumentPlugin = class {
|
|
|
5415
6241
|
getPageCount: () => totalPages,
|
|
5416
6242
|
getCurrentPage: () => currentPage,
|
|
5417
6243
|
getThumbnails: async () => {
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
canvas
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
6244
|
+
const count = totalPages || slides.length || 1;
|
|
6245
|
+
const items = [];
|
|
6246
|
+
for (let idx = 0; idx < count; idx++) {
|
|
6247
|
+
const itemIdx = idx;
|
|
6248
|
+
items.push({
|
|
6249
|
+
index: itemIdx,
|
|
6250
|
+
label: isPresentation ? `Slide ${itemIdx + 1}` : `Page ${itemIdx + 1}`,
|
|
6251
|
+
render: async (canvas) => {
|
|
6252
|
+
const ctx2d = canvas.getContext("2d");
|
|
6253
|
+
if (!ctx2d) return;
|
|
6254
|
+
if (isPresentation) {
|
|
6255
|
+
canvas.width = 160;
|
|
6256
|
+
canvas.height = 90;
|
|
6257
|
+
ctx2d.fillStyle = "#f8fafc";
|
|
6258
|
+
ctx2d.fillRect(0, 0, 160, 90);
|
|
6259
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6260
|
+
ctx2d.lineWidth = 1;
|
|
6261
|
+
ctx2d.strokeRect(0.5, 0.5, 159, 89);
|
|
6262
|
+
ctx2d.fillStyle = "#334155";
|
|
6263
|
+
ctx2d.font = "bold 11px sans-serif";
|
|
6264
|
+
ctx2d.textAlign = "center";
|
|
6265
|
+
ctx2d.fillText(`Slide ${itemIdx + 1}`, 80, 50);
|
|
6266
|
+
} else {
|
|
6267
|
+
canvas.width = 140;
|
|
6268
|
+
canvas.height = 180;
|
|
6269
|
+
ctx2d.fillStyle = "#ffffff";
|
|
6270
|
+
ctx2d.fillRect(0, 0, 140, 180);
|
|
6271
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6272
|
+
ctx2d.lineWidth = 1;
|
|
6273
|
+
ctx2d.strokeRect(0.5, 0.5, 139, 179);
|
|
6274
|
+
ctx2d.fillStyle = "#64748b";
|
|
6275
|
+
ctx2d.font = "bold 10px sans-serif";
|
|
6276
|
+
ctx2d.textAlign = "center";
|
|
6277
|
+
ctx2d.fillText(`Page ${itemIdx + 1}`, 70, 90);
|
|
6278
|
+
}
|
|
6279
|
+
}
|
|
6280
|
+
});
|
|
6281
|
+
}
|
|
6282
|
+
return items;
|
|
5435
6283
|
},
|
|
5436
6284
|
download: () => {
|
|
5437
6285
|
const mimeType = this.mimeTypes.find((m) => m.includes(ext.replace(".", ""))) || "application/octet-stream";
|
|
@@ -5536,23 +6384,24 @@ var OpenDocumentPlugin = class {
|
|
|
5536
6384
|
case "h": {
|
|
5537
6385
|
const level = Math.min(6, Math.max(1, Number(node.getAttribute("text:outline-level") || 1)));
|
|
5538
6386
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5539
|
-
html += `<h${level} style="${style}; font-family:
|
|
6387
|
+
html += `<h${level} style="${style}; margin: 18px 0 8px; color: #1e3a8a; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${node.textContent || ""}</h${level}>`;
|
|
5540
6388
|
break;
|
|
5541
6389
|
}
|
|
5542
6390
|
case "p": {
|
|
5543
6391
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5544
6392
|
const inner = this.renderSpans(node, styles, images);
|
|
5545
|
-
|
|
6393
|
+
const isInsideLi = node.parentElement?.localName === "list-item" || node.parentElement?.tagName?.toLowerCase() === "list-item";
|
|
6394
|
+
html += `<p style="${style}; line-height: 1.5; margin: ${isInsideLi ? "0" : "8px 0 12px"}; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${inner}</p>`;
|
|
5546
6395
|
break;
|
|
5547
6396
|
}
|
|
5548
6397
|
case "list": {
|
|
5549
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
6398
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
5550
6399
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5551
6400
|
html += "</ul>";
|
|
5552
6401
|
break;
|
|
5553
6402
|
}
|
|
5554
6403
|
case "list-item": {
|
|
5555
|
-
html +=
|
|
6404
|
+
html += '<li style="margin: 4px 0; font-size: 11pt; line-height: 1.5; color: #1e293b;">';
|
|
5556
6405
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5557
6406
|
html += "</li>";
|
|
5558
6407
|
break;
|
|
@@ -5678,28 +6527,26 @@ var DocPlugin = class {
|
|
|
5678
6527
|
getToolbarActions(instance) {
|
|
5679
6528
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5680
6529
|
const actions = [];
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
if (
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
instance.goToPage?.(page);
|
|
5699
|
-
}
|
|
6530
|
+
actions.push({
|
|
6531
|
+
id: "page-nav",
|
|
6532
|
+
icon: "",
|
|
6533
|
+
label: "Page Navigation",
|
|
6534
|
+
type: "page-nav",
|
|
6535
|
+
group: "navigation",
|
|
6536
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
6537
|
+
max: totalPages,
|
|
6538
|
+
execute: (action, page) => {
|
|
6539
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
6540
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
6541
|
+
if (action === "prev") {
|
|
6542
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
6543
|
+
} else if (action === "next") {
|
|
6544
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
6545
|
+
} else if (typeof page === "number") {
|
|
6546
|
+
instance.goToPage?.(page);
|
|
5700
6547
|
}
|
|
5701
|
-
}
|
|
5702
|
-
}
|
|
6548
|
+
}
|
|
6549
|
+
});
|
|
5703
6550
|
actions.push(
|
|
5704
6551
|
{
|
|
5705
6552
|
id: "zoom-out",
|
|
@@ -5773,8 +6620,9 @@ var DocPlugin = class {
|
|
|
5773
6620
|
container.className = "fp-doc-container";
|
|
5774
6621
|
container.style.width = "100%";
|
|
5775
6622
|
container.style.height = "100%";
|
|
5776
|
-
container.style.
|
|
5777
|
-
container.style.
|
|
6623
|
+
container.style.overflowX = "hidden";
|
|
6624
|
+
container.style.overflowY = "auto";
|
|
6625
|
+
container.style.padding = "16px 8px";
|
|
5778
6626
|
container.style.backgroundColor = "#f1f5f9";
|
|
5779
6627
|
container.style.display = "flex";
|
|
5780
6628
|
container.style.justifyContent = "center";
|
|
@@ -5783,8 +6631,17 @@ var DocPlugin = class {
|
|
|
5783
6631
|
let scale = 1;
|
|
5784
6632
|
let extractedRawText = "";
|
|
5785
6633
|
let isFallback = false;
|
|
6634
|
+
let chartSvg = "";
|
|
5786
6635
|
try {
|
|
5787
6636
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
6637
|
+
try {
|
|
6638
|
+
const pkg = cfbf.readStream("package_stream");
|
|
6639
|
+
if (pkg && pkg.length > 100) {
|
|
6640
|
+
chartSvg = this.parseOdfChartToSvg(pkg);
|
|
6641
|
+
}
|
|
6642
|
+
} catch (chartErr) {
|
|
6643
|
+
console.warn("[DocPlugin] Chart stream parsing info:", chartErr);
|
|
6644
|
+
}
|
|
5788
6645
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
5789
6646
|
if (!wordDocStream || wordDocStream.length < 512) {
|
|
5790
6647
|
throw new Error("WordDocument stream not found or invalid in CFBF archive");
|
|
@@ -5802,7 +6659,7 @@ var DocPlugin = class {
|
|
|
5802
6659
|
extractedRawText = fallback;
|
|
5803
6660
|
isFallback = true;
|
|
5804
6661
|
}
|
|
5805
|
-
const rawPages = this.splitIntoPages(extractedRawText);
|
|
6662
|
+
const rawPages = this.splitIntoPages(extractedRawText, chartSvg);
|
|
5806
6663
|
const totalPages = Math.max(1, rawPages.length);
|
|
5807
6664
|
let currentPage = 1;
|
|
5808
6665
|
const pageCards = [];
|
|
@@ -5810,16 +6667,15 @@ var DocPlugin = class {
|
|
|
5810
6667
|
const pageCard = document.createElement("div");
|
|
5811
6668
|
pageCard.className = "fp-doc-page-card";
|
|
5812
6669
|
pageCard.style.width = "816px";
|
|
5813
|
-
pageCard.style.
|
|
6670
|
+
pageCard.style.minHeight = "1056px";
|
|
5814
6671
|
pageCard.style.backgroundColor = "#ffffff";
|
|
5815
|
-
pageCard.style.boxShadow = "0
|
|
6672
|
+
pageCard.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
5816
6673
|
pageCard.style.borderRadius = "4px";
|
|
5817
|
-
pageCard.style.padding = "
|
|
6674
|
+
pageCard.style.padding = "72px 56px";
|
|
5818
6675
|
pageCard.style.boxSizing = "border-box";
|
|
5819
|
-
pageCard.style.overflow = "hidden";
|
|
5820
6676
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5821
6677
|
pageCard.style.transformOrigin = "top center";
|
|
5822
|
-
pageCard.style.transition = "transform 0.
|
|
6678
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
5823
6679
|
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5824
6680
|
pageCard.style.color = "#1e293b";
|
|
5825
6681
|
if (isFallback && i === 0) {
|
|
@@ -5836,34 +6692,15 @@ var DocPlugin = class {
|
|
|
5836
6692
|
container.appendChild(pageCard);
|
|
5837
6693
|
pageCards.push(pageCard);
|
|
5838
6694
|
}
|
|
5839
|
-
let indicator = null;
|
|
5840
|
-
if (totalPages > 1) {
|
|
5841
|
-
indicator = document.createElement("div");
|
|
5842
|
-
indicator.className = "fp-doc-page-indicator";
|
|
5843
|
-
indicator.style.position = "fixed";
|
|
5844
|
-
indicator.style.bottom = "16px";
|
|
5845
|
-
indicator.style.left = "50%";
|
|
5846
|
-
indicator.style.transform = "translateX(-50%)";
|
|
5847
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
5848
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
5849
|
-
indicator.style.color = "#f8fafc";
|
|
5850
|
-
indicator.style.fontSize = "12px";
|
|
5851
|
-
indicator.style.fontWeight = "600";
|
|
5852
|
-
indicator.style.padding = "5px 14px";
|
|
5853
|
-
indicator.style.borderRadius = "20px";
|
|
5854
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
5855
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
5856
|
-
indicator.style.zIndex = "10";
|
|
5857
|
-
indicator.style.userSelect = "none";
|
|
5858
|
-
indicator.style.pointerEvents = "none";
|
|
5859
|
-
indicator.style.textAlign = "center";
|
|
5860
|
-
container.appendChild(indicator);
|
|
5861
|
-
}
|
|
5862
6695
|
let rotation = 0;
|
|
5863
6696
|
const applyTransform = () => {
|
|
5864
6697
|
const activeCard = pageCards[currentPage - 1];
|
|
5865
6698
|
if (activeCard) {
|
|
5866
6699
|
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
6700
|
+
const baseH = activeCard.offsetHeight || 1056;
|
|
6701
|
+
const scaledH = baseH * scale;
|
|
6702
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6703
|
+
activeCard.style.marginBottom = `${extraH + 32}px`;
|
|
5867
6704
|
}
|
|
5868
6705
|
};
|
|
5869
6706
|
const showPage = (pageNum) => {
|
|
@@ -5876,35 +6713,39 @@ var DocPlugin = class {
|
|
|
5876
6713
|
card.style.display = "none";
|
|
5877
6714
|
}
|
|
5878
6715
|
});
|
|
5879
|
-
if (indicator) {
|
|
5880
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5881
|
-
}
|
|
5882
6716
|
container.scrollTop = 0;
|
|
5883
6717
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5884
6718
|
};
|
|
5885
6719
|
if (totalPages > 1) {
|
|
5886
6720
|
showPage(1);
|
|
5887
6721
|
}
|
|
5888
|
-
let fitMode = "width";
|
|
6722
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6723
|
+
let isUserZoomed = false;
|
|
5889
6724
|
const calculateFitScale = (mode = fitMode) => {
|
|
5890
6725
|
const elW = 816;
|
|
5891
6726
|
const elH = 1056;
|
|
5892
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
5893
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
6727
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6728
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5894
6729
|
const sW = availW / elW;
|
|
5895
6730
|
const sH = availH / elH;
|
|
5896
6731
|
if (mode === "page") {
|
|
5897
|
-
return Math.max(0.
|
|
6732
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5898
6733
|
}
|
|
5899
|
-
return Math.max(0.
|
|
6734
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5900
6735
|
};
|
|
6736
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6737
|
+
if (!isUserZoomed) {
|
|
6738
|
+
scale = calculateFitScale(fitMode);
|
|
6739
|
+
applyTransform();
|
|
6740
|
+
}
|
|
6741
|
+
}) : null;
|
|
6742
|
+
resizeObserver?.observe(ctx.container);
|
|
5901
6743
|
setTimeout(() => {
|
|
5902
|
-
|
|
5903
|
-
scale = calculateFitScale("width");
|
|
6744
|
+
scale = calculateFitScale(fitMode);
|
|
5904
6745
|
applyTransform();
|
|
5905
6746
|
}, 60);
|
|
5906
6747
|
const cleanup = () => {
|
|
5907
|
-
|
|
6748
|
+
resizeObserver?.disconnect();
|
|
5908
6749
|
container.remove();
|
|
5909
6750
|
ctx.container.innerHTML = "";
|
|
5910
6751
|
};
|
|
@@ -5915,21 +6756,25 @@ var DocPlugin = class {
|
|
|
5915
6756
|
getCurrentPage: () => currentPage,
|
|
5916
6757
|
goToPage: (page) => showPage(page),
|
|
5917
6758
|
zoomIn: () => {
|
|
6759
|
+
isUserZoomed = true;
|
|
5918
6760
|
scale += 0.15;
|
|
5919
6761
|
applyTransform();
|
|
5920
6762
|
},
|
|
5921
6763
|
zoomOut: () => {
|
|
6764
|
+
isUserZoomed = true;
|
|
5922
6765
|
scale = Math.max(0.2, scale - 0.15);
|
|
5923
6766
|
applyTransform();
|
|
5924
6767
|
},
|
|
5925
6768
|
getZoom: () => scale,
|
|
5926
6769
|
setZoom: (level) => {
|
|
6770
|
+
isUserZoomed = true;
|
|
5927
6771
|
scale = level;
|
|
5928
6772
|
applyTransform();
|
|
5929
6773
|
},
|
|
5930
6774
|
fitToPage: () => {
|
|
5931
|
-
|
|
5932
|
-
|
|
6775
|
+
isUserZoomed = false;
|
|
6776
|
+
fitMode = "width";
|
|
6777
|
+
scale = calculateFitScale("width");
|
|
5933
6778
|
rotation = 0;
|
|
5934
6779
|
applyTransform();
|
|
5935
6780
|
},
|
|
@@ -6044,7 +6889,7 @@ var DocPlugin = class {
|
|
|
6044
6889
|
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
6045
6890
|
const trimmed = run.trim();
|
|
6046
6891
|
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
6047
|
-
if (!trimmed.includes("Normal.dot") && !trimmed.includes("Microsoft Word") && !trimmed.includes("Times New Roman") && !trimmed.startsWith("\xD0\xCF\xE0\xA1\xB1\xE1") && !/^[\W_0-9]+$/.test(trimmed)) {
|
|
6892
|
+
if (!trimmed.includes("Normal.dot") && !trimmed.includes("Microsoft Word") && !trimmed.includes("Times New Roman") && !trimmed.startsWith("\xD0\xCF\xE0\xA1\xB1\xE1") && !/^EMBED\b/i.test(trimmed) && !trimmed.includes("ChartDocument") && !/^[\W_0-9]+$/.test(trimmed)) {
|
|
6048
6893
|
seen.add(trimmed);
|
|
6049
6894
|
candidateLines.push(trimmed);
|
|
6050
6895
|
}
|
|
@@ -6055,9 +6900,114 @@ var DocPlugin = class {
|
|
|
6055
6900
|
heuristicTextExtraction(buffer) {
|
|
6056
6901
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
6057
6902
|
}
|
|
6058
|
-
|
|
6903
|
+
/**
|
|
6904
|
+
* Parses an embedded OpenDocument Chart package into a vector SVG bar/column chart
|
|
6905
|
+
*/
|
|
6906
|
+
parseOdfChartToSvg(zipBytes) {
|
|
6907
|
+
try {
|
|
6908
|
+
const unzipped = fflate__namespace.unzipSync(zipBytes);
|
|
6909
|
+
const contentXml = unzipped["content.xml"] ? new TextDecoder("utf-8").decode(unzipped["content.xml"]) : "";
|
|
6910
|
+
if (!contentXml) return "";
|
|
6911
|
+
const rowsMatch = contentXml.match(/<table:table-row[\s\S]*?<\/table:table-row>/g) || [];
|
|
6912
|
+
if (rowsMatch.length < 2) return "";
|
|
6913
|
+
const headers = [];
|
|
6914
|
+
const firstRow = rowsMatch[0];
|
|
6915
|
+
const headerCells = firstRow ? firstRow.match(/<text:p>([^<]+)<\/text:p>/g) || [] : [];
|
|
6916
|
+
for (const h of headerCells) {
|
|
6917
|
+
headers.push(h.replace(/<\/?text:p>/g, "").trim());
|
|
6918
|
+
}
|
|
6919
|
+
const categories = [];
|
|
6920
|
+
const seriesValues = headers.map(() => []);
|
|
6921
|
+
for (let r = 1; r < rowsMatch.length; r++) {
|
|
6922
|
+
const rowStr = rowsMatch[r];
|
|
6923
|
+
if (!rowStr) continue;
|
|
6924
|
+
const cells = rowStr.match(/<table:table-cell[\s\S]*?<\/table:table-cell>/g) || [];
|
|
6925
|
+
if (cells.length > 0 && cells[0]) {
|
|
6926
|
+
const catMatch = cells[0].match(/<text:p>([^<]+)<\/text:p>/);
|
|
6927
|
+
categories.push(catMatch ? catMatch[1] : "Row " + r);
|
|
6928
|
+
for (let c = 1; c < cells.length && c - 1 < headers.length; c++) {
|
|
6929
|
+
const cellStr = cells[c];
|
|
6930
|
+
if (!cellStr) continue;
|
|
6931
|
+
const valMatch = cellStr.match(/office:value="([0-9.]+)"/) || cellStr.match(/<text:p>([0-9.]+)<\/text:p>/);
|
|
6932
|
+
const series = seriesValues[c - 1];
|
|
6933
|
+
if (series) {
|
|
6934
|
+
series.push(valMatch ? parseFloat(valMatch[1]) : 0);
|
|
6935
|
+
}
|
|
6936
|
+
}
|
|
6937
|
+
}
|
|
6938
|
+
}
|
|
6939
|
+
const colors = ["#004586", "#ff420e", "#ffd320", "#579d1c", "#7e0021"];
|
|
6940
|
+
const colorMatches = contentXml.matchAll(/draw:fill-color="(#[0-9a-fA-F]{6})"/g);
|
|
6941
|
+
let cIdx = 0;
|
|
6942
|
+
for (const cm of colorMatches) {
|
|
6943
|
+
if (cIdx < colors.length) colors[cIdx] = cm[1];
|
|
6944
|
+
cIdx++;
|
|
6945
|
+
}
|
|
6946
|
+
let maxVal = 10;
|
|
6947
|
+
for (const s of seriesValues) {
|
|
6948
|
+
for (const v of s) {
|
|
6949
|
+
if (v > maxVal) maxVal = v;
|
|
6950
|
+
}
|
|
6951
|
+
}
|
|
6952
|
+
maxVal = Math.ceil(maxVal * 1.15);
|
|
6953
|
+
const width = 560;
|
|
6954
|
+
const height = 280;
|
|
6955
|
+
const padLeft = 45;
|
|
6956
|
+
const padRight = 100;
|
|
6957
|
+
const padTop = 20;
|
|
6958
|
+
const padBottom = 40;
|
|
6959
|
+
const chartW = width - padLeft - padRight;
|
|
6960
|
+
const chartH = height - padTop - padBottom;
|
|
6961
|
+
let svg = `<svg viewBox="0 0 ${width} ${height}" width="100%" height="auto" style="max-width: 560px; height: 280px; margin: 16px auto; display: block; font-family: Calibri, sans-serif; background: #ffffff; border: 1px solid #e2e8f0; border-radius: 6px; box-shadow: 0 1px 4px rgba(0,0,0,0.05);">`;
|
|
6962
|
+
for (let step = 0; step <= 4; step++) {
|
|
6963
|
+
const yVal = (maxVal / 4 * step).toFixed(1);
|
|
6964
|
+
const yPos = padTop + chartH - step / 4 * chartH;
|
|
6965
|
+
svg += `<line x1="${padLeft}" y1="${yPos}" x2="${padLeft + chartW}" y2="${yPos}" stroke="#e2e8f0" stroke-dasharray="2,2" />`;
|
|
6966
|
+
svg += `<text x="${padLeft - 8}" y="${yPos + 4}" font-size="11" fill="#64748b" text-anchor="end">${yVal}</text>`;
|
|
6967
|
+
}
|
|
6968
|
+
const numCats = categories.length;
|
|
6969
|
+
const numSeries = headers.length;
|
|
6970
|
+
const groupW = chartW / numCats;
|
|
6971
|
+
const barW = Math.max(8, groupW * 0.7 / numSeries);
|
|
6972
|
+
const groupPad = (groupW - barW * numSeries) / 2;
|
|
6973
|
+
for (let catIdx = 0; catIdx < numCats; catIdx++) {
|
|
6974
|
+
const groupX = padLeft + catIdx * groupW + groupPad;
|
|
6975
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6976
|
+
const val = seriesValues[sIdx][catIdx] || 0;
|
|
6977
|
+
const barH = val / maxVal * chartH;
|
|
6978
|
+
const barX = groupX + sIdx * barW;
|
|
6979
|
+
const barY = padTop + chartH - barH;
|
|
6980
|
+
const col = colors[sIdx % colors.length];
|
|
6981
|
+
svg += `<rect x="${barX}" y="${barY}" width="${barW - 2}" height="${barH}" fill="${col}" rx="2"><title>${headers[sIdx]}: ${val}</title></rect>`;
|
|
6982
|
+
}
|
|
6983
|
+
const catX = padLeft + catIdx * groupW + groupW / 2;
|
|
6984
|
+
svg += `<text x="${catX}" y="${padTop + chartH + 18}" font-size="11" fill="#475569" text-anchor="middle">${categories[catIdx]}</text>`;
|
|
6985
|
+
}
|
|
6986
|
+
let legendY = padTop + 20;
|
|
6987
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6988
|
+
const col = colors[sIdx % colors.length];
|
|
6989
|
+
svg += `<rect x="${padLeft + chartW + 15}" y="${legendY}" width="12" height="12" fill="${col}" rx="2" />`;
|
|
6990
|
+
svg += `<text x="${padLeft + chartW + 32}" y="${legendY + 10}" font-size="11" fill="#334155">${headers[sIdx]}</text>`;
|
|
6991
|
+
legendY += 20;
|
|
6992
|
+
}
|
|
6993
|
+
svg += "</svg>";
|
|
6994
|
+
return svg;
|
|
6995
|
+
} catch (e) {
|
|
6996
|
+
console.warn("[DocPlugin] Error generating chart SVG:", e);
|
|
6997
|
+
return "";
|
|
6998
|
+
}
|
|
6999
|
+
}
|
|
7000
|
+
cleanWordDocFields(text, chartSvg = "") {
|
|
6059
7001
|
if (!text) return "";
|
|
6060
7002
|
let cleaned = text.replace(
|
|
7003
|
+
/\x13\s*EMBED\b[\s\S]*?\x15/gi,
|
|
7004
|
+
() => chartSvg ? `
|
|
7005
|
+
|
|
7006
|
+
${chartSvg}
|
|
7007
|
+
|
|
7008
|
+
` : ""
|
|
7009
|
+
);
|
|
7010
|
+
cleaned = cleaned.replace(
|
|
6061
7011
|
/\x13\s*HYPERLINK\s*"?([^"\x14]+)"?\s*\x14([\s\S]*?)\x15/gi,
|
|
6062
7012
|
(_match, url, label) => {
|
|
6063
7013
|
const cleanUrl = url.trim();
|
|
@@ -6065,18 +7015,23 @@ var DocPlugin = class {
|
|
|
6065
7015
|
return `<a href="${cleanUrl}" target="_blank" rel="noopener noreferrer" style="color: #2563eb; text-decoration: underline;">${cleanLabel}</a>`;
|
|
6066
7016
|
}
|
|
6067
7017
|
);
|
|
6068
|
-
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g,
|
|
7018
|
+
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g, (_m, res) => {
|
|
7019
|
+
if (/[\x00-\x1F]/.test(res)) return "";
|
|
7020
|
+
return res.trim();
|
|
7021
|
+
});
|
|
6069
7022
|
cleaned = cleaned.replace(/\x13[^\x15]*\x15/g, "");
|
|
6070
7023
|
cleaned = cleaned.replace(/[\x13\x14\x15]/g, "");
|
|
7024
|
+
cleaned = cleaned.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/g, "");
|
|
7025
|
+
cleaned = cleaned.replace(/EMBED\s+LibreOffice\.ChartDocument\.[0-9]+/gi, chartSvg || "");
|
|
6071
7026
|
return cleaned;
|
|
6072
7027
|
}
|
|
6073
|
-
splitIntoPages(text) {
|
|
7028
|
+
splitIntoPages(text, chartSvg = "") {
|
|
6074
7029
|
if (!text) return [""];
|
|
6075
|
-
const cleanedText = this.cleanWordDocFields(text);
|
|
7030
|
+
const cleanedText = this.cleanWordDocFields(text, chartSvg);
|
|
6076
7031
|
const normalized = cleanedText.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ");
|
|
6077
7032
|
const explicitParts = normalized.split(/[\x0C\f]|\n\s*[-=_]{3,}\s*(?:PAGE|Page|page break)[\s\d\w-]*[-=_]{3,}\s*\n/i).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
6078
7033
|
if (explicitParts.length === 0) explicitParts.push(normalized);
|
|
6079
|
-
const maxLinesPerPage =
|
|
7034
|
+
const maxLinesPerPage = 34;
|
|
6080
7035
|
const charsPerLine = 80;
|
|
6081
7036
|
const finalPages = [];
|
|
6082
7037
|
for (const part of explicitParts) {
|
|
@@ -6084,8 +7039,8 @@ var DocPlugin = class {
|
|
|
6084
7039
|
let currentLines = [];
|
|
6085
7040
|
let count = 0;
|
|
6086
7041
|
for (const line of lines) {
|
|
6087
|
-
const
|
|
6088
|
-
const vLines = Math.max(1, Math.ceil((
|
|
7042
|
+
const isSvg = line.includes("<svg");
|
|
7043
|
+
const vLines = isSvg ? 12 : Math.max(1, Math.ceil((line.replace(/<[^>]+>/g, "").length || 1) / charsPerLine));
|
|
6089
7044
|
if (count + vLines > maxLinesPerPage && currentLines.length > 0) {
|
|
6090
7045
|
finalPages.push(currentLines.join("\n"));
|
|
6091
7046
|
currentLines = [];
|
|
@@ -6125,9 +7080,44 @@ var DocPlugin = class {
|
|
|
6125
7080
|
tableLines = [];
|
|
6126
7081
|
}
|
|
6127
7082
|
};
|
|
7083
|
+
const sanitizeOptions = {
|
|
7084
|
+
ADD_TAGS: ["a", "svg", "g", "path", "line", "rect", "circle", "text", "title"],
|
|
7085
|
+
ADD_ATTR: [
|
|
7086
|
+
"href",
|
|
7087
|
+
"target",
|
|
7088
|
+
"rel",
|
|
7089
|
+
"style",
|
|
7090
|
+
"viewBox",
|
|
7091
|
+
"width",
|
|
7092
|
+
"height",
|
|
7093
|
+
"x",
|
|
7094
|
+
"y",
|
|
7095
|
+
"x1",
|
|
7096
|
+
"y1",
|
|
7097
|
+
"x2",
|
|
7098
|
+
"y2",
|
|
7099
|
+
"fill",
|
|
7100
|
+
"stroke",
|
|
7101
|
+
"stroke-width",
|
|
7102
|
+
"stroke-dasharray",
|
|
7103
|
+
"rx",
|
|
7104
|
+
"font-size",
|
|
7105
|
+
"text-anchor"
|
|
7106
|
+
]
|
|
7107
|
+
};
|
|
6128
7108
|
let i = 0;
|
|
6129
7109
|
while (i < lines.length) {
|
|
6130
7110
|
let line = lines[i];
|
|
7111
|
+
if (line.includes("<svg")) {
|
|
7112
|
+
if (inList) {
|
|
7113
|
+
html += "</ul>";
|
|
7114
|
+
inList = false;
|
|
7115
|
+
}
|
|
7116
|
+
flushTable();
|
|
7117
|
+
html += line;
|
|
7118
|
+
i++;
|
|
7119
|
+
continue;
|
|
7120
|
+
}
|
|
6131
7121
|
let tabCount = (line.match(/\t/g) || []).length;
|
|
6132
7122
|
if (tabCount > 0) {
|
|
6133
7123
|
let j = i;
|
|
@@ -6161,26 +7151,31 @@ var DocPlugin = class {
|
|
|
6161
7151
|
i++;
|
|
6162
7152
|
continue;
|
|
6163
7153
|
}
|
|
6164
|
-
|
|
6165
|
-
|
|
7154
|
+
if (/^\d{1,2}$/.test(line.trim())) {
|
|
7155
|
+
i++;
|
|
7156
|
+
continue;
|
|
7157
|
+
}
|
|
7158
|
+
const isShortLine = line.length < 60 && !line.endsWith(".") && !line.endsWith(",");
|
|
7159
|
+
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));
|
|
7160
|
+
if (isTitleLike) {
|
|
6166
7161
|
if (inList) {
|
|
6167
7162
|
html += "</ul>";
|
|
6168
7163
|
inList = false;
|
|
6169
7164
|
}
|
|
6170
|
-
html += `<h2 style="font-size:
|
|
7165
|
+
html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 18px 0 10px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6__default.default.sanitize(line, sanitizeOptions)}</h2>`;
|
|
6171
7166
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
6172
7167
|
if (!inList) {
|
|
6173
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
7168
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
6174
7169
|
inList = true;
|
|
6175
7170
|
}
|
|
6176
7171
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
6177
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
7172
|
+
html += `<li style="margin: 4px 0; line-height: 1.5; font-size: 11pt; color: #1e293b;">${DOMPurify6__default.default.sanitize(bulletText, sanitizeOptions)}</li>`;
|
|
6178
7173
|
} else {
|
|
6179
7174
|
if (inList) {
|
|
6180
7175
|
html += "</ul>";
|
|
6181
7176
|
inList = false;
|
|
6182
7177
|
}
|
|
6183
|
-
html += `<p style="line-height: 1.
|
|
7178
|
+
html += `<p style="line-height: 1.5; margin: 0 0 12px 0; font-size: 11pt; color: #1e293b; text-align: justify;">${DOMPurify6__default.default.sanitize(line, sanitizeOptions)}</p>`;
|
|
6184
7179
|
}
|
|
6185
7180
|
i++;
|
|
6186
7181
|
}
|