@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/vue.cjs
CHANGED
|
@@ -41,6 +41,7 @@ function _interopNamespace(e) {
|
|
|
41
41
|
var DOMPurify6__default = /*#__PURE__*/_interopDefault(DOMPurify6);
|
|
42
42
|
var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
|
|
43
43
|
var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
44
|
+
var fflate__namespace = /*#__PURE__*/_interopNamespace(fflate);
|
|
44
45
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
45
46
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
46
47
|
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
@@ -526,8 +527,7 @@ var ICON_FULLSCREEN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="non
|
|
|
526
527
|
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>`;
|
|
527
528
|
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>`;
|
|
528
529
|
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>`;
|
|
529
|
-
var
|
|
530
|
-
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>`;
|
|
530
|
+
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>`;
|
|
531
531
|
var ICON_MAP = {
|
|
532
532
|
"zoom-in": ICON_ZOOM_IN,
|
|
533
533
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -554,28 +554,177 @@ var ICON_MAP = {
|
|
|
554
554
|
"forward-10": ICON_FAST_FORWARD,
|
|
555
555
|
"rewind": ICON_REWIND,
|
|
556
556
|
"replay-10": ICON_REWIND,
|
|
557
|
-
"speed": ICON_SPEED,
|
|
558
557
|
"open-window": ICON_EXTERNAL_WINDOW,
|
|
559
|
-
"external-window": ICON_EXTERNAL_WINDOW
|
|
558
|
+
"external-window": ICON_EXTERNAL_WINDOW,
|
|
559
|
+
"openWindow": ICON_EXTERNAL_WINDOW,
|
|
560
|
+
"openSeparateWindow": ICON_EXTERNAL_WINDOW
|
|
560
561
|
};
|
|
561
562
|
var ToolbarController = class {
|
|
562
563
|
el;
|
|
563
564
|
toolbarEl;
|
|
564
565
|
actions = [];
|
|
566
|
+
config = {};
|
|
565
567
|
pageInputEl = null;
|
|
566
568
|
pageLabelEl = null;
|
|
567
|
-
|
|
569
|
+
prevPageBtn = null;
|
|
570
|
+
nextPageBtn = null;
|
|
571
|
+
constructor(container, config) {
|
|
568
572
|
this.el = container;
|
|
573
|
+
if (config) this.config = { ...config };
|
|
569
574
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
570
575
|
this.el.appendChild(this.toolbarEl);
|
|
571
576
|
}
|
|
577
|
+
setConfig(config) {
|
|
578
|
+
this.config = { ...config };
|
|
579
|
+
this.render();
|
|
580
|
+
}
|
|
581
|
+
getConfig() {
|
|
582
|
+
return { ...this.config };
|
|
583
|
+
}
|
|
584
|
+
hideAction(actionId) {
|
|
585
|
+
this.config[actionId] = false;
|
|
586
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = false;
|
|
587
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = false;
|
|
588
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
589
|
+
this.config.fitPage = false;
|
|
590
|
+
this.config.fitToPage = false;
|
|
591
|
+
this.config.fitWidth = false;
|
|
592
|
+
}
|
|
593
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = false;
|
|
594
|
+
if (actionId === "fullscreen") this.config.fullscreen = false;
|
|
595
|
+
if (actionId === "download") this.config.download = false;
|
|
596
|
+
if (actionId === "print") this.config.print = false;
|
|
597
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
598
|
+
this.config.openWindow = false;
|
|
599
|
+
this.config.openSeparateWindow = false;
|
|
600
|
+
}
|
|
601
|
+
if (actionId === "copy") this.config.copy = false;
|
|
602
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
603
|
+
this.config.pageNav = false;
|
|
604
|
+
this.config.pagination = false;
|
|
605
|
+
}
|
|
606
|
+
this.render();
|
|
607
|
+
}
|
|
608
|
+
showAction(actionId) {
|
|
609
|
+
this.config[actionId] = true;
|
|
610
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = true;
|
|
611
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = true;
|
|
612
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
613
|
+
this.config.fitPage = true;
|
|
614
|
+
this.config.fitToPage = true;
|
|
615
|
+
this.config.fitWidth = true;
|
|
616
|
+
}
|
|
617
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = true;
|
|
618
|
+
if (actionId === "fullscreen") this.config.fullscreen = true;
|
|
619
|
+
if (actionId === "download") this.config.download = true;
|
|
620
|
+
if (actionId === "print") this.config.print = true;
|
|
621
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
622
|
+
this.config.openWindow = true;
|
|
623
|
+
this.config.openSeparateWindow = true;
|
|
624
|
+
}
|
|
625
|
+
if (actionId === "copy") this.config.copy = true;
|
|
626
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
627
|
+
this.config.pageNav = true;
|
|
628
|
+
this.config.pagination = true;
|
|
629
|
+
}
|
|
630
|
+
this.render();
|
|
631
|
+
}
|
|
632
|
+
normalizeActionId(actionId) {
|
|
633
|
+
if (actionId === "zoomIn") return "zoom-in";
|
|
634
|
+
if (actionId === "zoomOut") return "zoom-out";
|
|
635
|
+
if (actionId === "fitPage" || actionId === "fitToPage" || actionId === "fitWidth") return "fit-page";
|
|
636
|
+
if (actionId === "rotateCW") return "rotate-cw";
|
|
637
|
+
if (actionId === "rotateCCW") return "rotate-ccw";
|
|
638
|
+
if (actionId === "openWindow" || actionId === "openSeparateWindow") return "open-window";
|
|
639
|
+
if (actionId === "pageNav") return "page-nav";
|
|
640
|
+
return actionId;
|
|
641
|
+
}
|
|
642
|
+
enableAction(actionId) {
|
|
643
|
+
const norm = this.normalizeActionId(actionId);
|
|
644
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
645
|
+
if (btn) {
|
|
646
|
+
btn.disabled = false;
|
|
647
|
+
btn.classList.remove("disabled");
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
disableAction(actionId) {
|
|
651
|
+
const norm = this.normalizeActionId(actionId);
|
|
652
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
653
|
+
if (btn) {
|
|
654
|
+
btn.disabled = true;
|
|
655
|
+
btn.classList.add("disabled");
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
setActionActive(actionId, active) {
|
|
659
|
+
const norm = this.normalizeActionId(actionId);
|
|
660
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
661
|
+
if (btn) {
|
|
662
|
+
if (active) {
|
|
663
|
+
btn.classList.add("active");
|
|
664
|
+
} else {
|
|
665
|
+
btn.classList.remove("active");
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
isActionEnabled(action) {
|
|
670
|
+
const c = this.config;
|
|
671
|
+
const id = action.id;
|
|
672
|
+
if (c[id] === false) return false;
|
|
673
|
+
if (id === "zoom-in" && (c.zoomIn === false || c["zoom-in"] === false)) return false;
|
|
674
|
+
if (id === "zoom-out" && (c.zoomOut === false || c["zoom-out"] === false)) return false;
|
|
675
|
+
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)) {
|
|
676
|
+
return false;
|
|
677
|
+
}
|
|
678
|
+
if ((id === "rotate-cw" || id === "rotate-ccw" || id === "rotate") && (c.rotate === false || c.rotateCW === false || c.rotateCCW === false || c["rotate-cw"] === false)) {
|
|
679
|
+
return false;
|
|
680
|
+
}
|
|
681
|
+
if (id === "fullscreen" && c.fullscreen === false) return false;
|
|
682
|
+
if (id === "download" && c.download === false) return false;
|
|
683
|
+
if (id === "print" && c.print === false) return false;
|
|
684
|
+
if ((id === "open-window" || id === "external-window") && (c.openWindow === false || c.openSeparateWindow === false || c["open-window"] === false)) {
|
|
685
|
+
return false;
|
|
686
|
+
}
|
|
687
|
+
if (id === "copy" && c.copy === false) return false;
|
|
688
|
+
if (id === "thumbnails" && c.thumbnails === false) return false;
|
|
689
|
+
if (id === "page-nav" && (c.pageNav === false || c.pagination === false || c["page-nav"] === false)) {
|
|
690
|
+
return false;
|
|
691
|
+
}
|
|
692
|
+
if ((id === "prev" || id === "page-prev") && (c.prevPage === false || c.prev === false || c["prev"] === false || c.pageNav === false || c.pagination === false)) {
|
|
693
|
+
return false;
|
|
694
|
+
}
|
|
695
|
+
if ((id === "next" || id === "page-next") && (c.nextPage === false || c.next === false || c["next"] === false || c.pageNav === false || c.pagination === false)) {
|
|
696
|
+
return false;
|
|
697
|
+
}
|
|
698
|
+
if (id === "play" && c.play === false) return false;
|
|
699
|
+
if (id === "pause" && c.pause === false) return false;
|
|
700
|
+
if ((id === "fast-forward" || id === "forward-10") && (c.fastForward === false || c["fast-forward"] === false)) {
|
|
701
|
+
return false;
|
|
702
|
+
}
|
|
703
|
+
if ((id === "rewind" || id === "replay-10") && (c.rewind === false || c["rewind"] === false)) {
|
|
704
|
+
return false;
|
|
705
|
+
}
|
|
706
|
+
if (id === "speed" && c.speed === false) return false;
|
|
707
|
+
return true;
|
|
708
|
+
}
|
|
572
709
|
setPage(page, max) {
|
|
573
710
|
if (this.pageInputEl) {
|
|
574
711
|
this.pageInputEl.value = page.toString();
|
|
712
|
+
if (max !== void 0) {
|
|
713
|
+
this.pageInputEl.max = max.toString();
|
|
714
|
+
}
|
|
575
715
|
}
|
|
576
716
|
if (max !== void 0 && this.pageLabelEl) {
|
|
577
717
|
this.pageLabelEl.textContent = ` / ${max}`;
|
|
578
718
|
}
|
|
719
|
+
const currentMax = max !== void 0 ? max : parseInt(this.pageInputEl?.max || "1", 10) || 1;
|
|
720
|
+
if (this.prevPageBtn) {
|
|
721
|
+
this.prevPageBtn.disabled = page <= 1;
|
|
722
|
+
this.prevPageBtn.style.opacity = page <= 1 ? "0.4" : "1";
|
|
723
|
+
}
|
|
724
|
+
if (this.nextPageBtn) {
|
|
725
|
+
this.nextPageBtn.disabled = page >= currentMax;
|
|
726
|
+
this.nextPageBtn.style.opacity = page >= currentMax ? "0.4" : "1";
|
|
727
|
+
}
|
|
579
728
|
}
|
|
580
729
|
update(actions) {
|
|
581
730
|
this.actions = actions;
|
|
@@ -598,8 +747,9 @@ var ToolbarController = class {
|
|
|
598
747
|
view: [],
|
|
599
748
|
actions: []
|
|
600
749
|
};
|
|
601
|
-
const
|
|
602
|
-
const
|
|
750
|
+
const enabledActions = this.actions.filter((a) => this.isActionEnabled(a));
|
|
751
|
+
const hasPageNav = enabledActions.some((a) => a.type === "page-nav");
|
|
752
|
+
const effectiveActions = hasPageNav ? enabledActions.filter((a) => a.id !== "page-prev" && a.id !== "page-next" && a.id !== "prev" && a.id !== "next") : enabledActions;
|
|
603
753
|
for (const action of effectiveActions) {
|
|
604
754
|
if (groups[action.group]) {
|
|
605
755
|
groups[action.group].push(action);
|
|
@@ -659,6 +809,13 @@ var ToolbarController = class {
|
|
|
659
809
|
action.execute("go", val);
|
|
660
810
|
});
|
|
661
811
|
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
812
|
+
const curVal = action.value ?? 1;
|
|
813
|
+
prevBtn.disabled = curVal <= 1;
|
|
814
|
+
prevBtn.style.opacity = curVal <= 1 ? "0.4" : "1";
|
|
815
|
+
nextBtn.disabled = curVal >= max;
|
|
816
|
+
nextBtn.style.opacity = curVal >= max ? "0.4" : "1";
|
|
817
|
+
this.prevPageBtn = prevBtn;
|
|
818
|
+
this.nextPageBtn = nextBtn;
|
|
662
819
|
this.pageInputEl = input;
|
|
663
820
|
this.pageLabelEl = label;
|
|
664
821
|
groupEl.appendChild(prevBtn);
|
|
@@ -699,9 +856,11 @@ var ToolbarController = class {
|
|
|
699
856
|
type: "button",
|
|
700
857
|
"data-action-id": id
|
|
701
858
|
});
|
|
702
|
-
const
|
|
703
|
-
if (
|
|
704
|
-
btn.innerHTML =
|
|
859
|
+
const internalSvg = ICON_MAP[iconHtml] || ICON_MAP[id];
|
|
860
|
+
if (internalSvg) {
|
|
861
|
+
btn.innerHTML = internalSvg;
|
|
862
|
+
} else if (iconHtml && iconHtml.startsWith("<svg")) {
|
|
863
|
+
btn.innerHTML = sanitizeSVG(iconHtml);
|
|
705
864
|
} else {
|
|
706
865
|
btn.textContent = title || id;
|
|
707
866
|
}
|
|
@@ -712,25 +871,63 @@ var ToolbarController = class {
|
|
|
712
871
|
var ThumbnailPanel = class {
|
|
713
872
|
el;
|
|
714
873
|
panelEl;
|
|
874
|
+
listEl;
|
|
875
|
+
headerEl;
|
|
715
876
|
thumbnails = [];
|
|
716
877
|
onSelect;
|
|
878
|
+
onToggleCallback;
|
|
717
879
|
activeIndex = 0;
|
|
718
|
-
|
|
880
|
+
observer;
|
|
881
|
+
renderedIndices = /* @__PURE__ */ new Set();
|
|
882
|
+
constructor(container, onToggle) {
|
|
719
883
|
this.el = container;
|
|
884
|
+
this.onToggleCallback = onToggle;
|
|
720
885
|
this.panelEl = createElement("div", { className: "fp-thumbnail-panel hidden" });
|
|
886
|
+
this.panelEl.style.width = "0px";
|
|
887
|
+
this.panelEl.style.minWidth = "0px";
|
|
888
|
+
this.panelEl.style.opacity = "0";
|
|
889
|
+
this.headerEl = createElement("div", { className: "fp-thumbnail-header" });
|
|
890
|
+
const title = createElement("span", { className: "fp-thumbnail-title" }, "Pages");
|
|
891
|
+
const closeBtn = createElement("button", {
|
|
892
|
+
className: "fp-thumbnail-close-btn",
|
|
893
|
+
title: "Close Thumbnails",
|
|
894
|
+
type: "button"
|
|
895
|
+
});
|
|
896
|
+
closeBtn.innerHTML = ICON_CLOSE;
|
|
897
|
+
closeBtn.addEventListener("click", (e) => {
|
|
898
|
+
e.stopPropagation();
|
|
899
|
+
this.hide();
|
|
900
|
+
});
|
|
901
|
+
this.headerEl.appendChild(title);
|
|
902
|
+
this.headerEl.appendChild(closeBtn);
|
|
903
|
+
this.listEl = createElement("div", { className: "fp-thumbnail-list" });
|
|
904
|
+
this.panelEl.appendChild(this.headerEl);
|
|
905
|
+
this.panelEl.appendChild(this.listEl);
|
|
721
906
|
this.el.appendChild(this.panelEl);
|
|
722
907
|
}
|
|
908
|
+
isOpen() {
|
|
909
|
+
return !this.panelEl.classList.contains("hidden") && this.panelEl.style.width !== "0px";
|
|
910
|
+
}
|
|
723
911
|
update(thumbnails, onSelect) {
|
|
724
912
|
this.thumbnails = thumbnails;
|
|
725
913
|
this.onSelect = onSelect;
|
|
914
|
+
this.renderedIndices.clear();
|
|
915
|
+
const titleEl = this.headerEl.querySelector(".fp-thumbnail-title");
|
|
916
|
+
if (titleEl) {
|
|
917
|
+
titleEl.textContent = `Pages (${thumbnails.length})`;
|
|
918
|
+
}
|
|
726
919
|
this.render();
|
|
920
|
+
if (this.isOpen()) {
|
|
921
|
+
this.renderAllVisible();
|
|
922
|
+
}
|
|
727
923
|
}
|
|
728
924
|
setActive(index) {
|
|
729
925
|
this.activeIndex = index;
|
|
730
|
-
const items = this.
|
|
926
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
731
927
|
items.forEach((item, i) => {
|
|
732
928
|
if (i === index) {
|
|
733
929
|
item.classList.add("active");
|
|
930
|
+
item.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
734
931
|
} else {
|
|
735
932
|
item.classList.remove("active");
|
|
736
933
|
}
|
|
@@ -738,37 +935,102 @@ var ThumbnailPanel = class {
|
|
|
738
935
|
}
|
|
739
936
|
show() {
|
|
740
937
|
this.panelEl.classList.remove("hidden");
|
|
938
|
+
this.panelEl.style.width = "200px";
|
|
939
|
+
this.panelEl.style.minWidth = "200px";
|
|
940
|
+
this.panelEl.style.opacity = "1";
|
|
941
|
+
this.panelEl.style.display = "flex";
|
|
942
|
+
this.onToggleCallback?.(true);
|
|
943
|
+
this.renderAllVisible();
|
|
741
944
|
}
|
|
742
945
|
hide() {
|
|
743
946
|
this.panelEl.classList.add("hidden");
|
|
947
|
+
this.panelEl.style.width = "0px";
|
|
948
|
+
this.panelEl.style.minWidth = "0px";
|
|
949
|
+
this.panelEl.style.opacity = "0";
|
|
950
|
+
this.onToggleCallback?.(false);
|
|
744
951
|
}
|
|
745
952
|
toggle() {
|
|
746
|
-
this.
|
|
953
|
+
if (this.isOpen()) {
|
|
954
|
+
this.hide();
|
|
955
|
+
} else {
|
|
956
|
+
this.show();
|
|
957
|
+
}
|
|
747
958
|
}
|
|
748
959
|
destroy() {
|
|
960
|
+
if (this.observer) {
|
|
961
|
+
this.observer.disconnect();
|
|
962
|
+
this.observer = void 0;
|
|
963
|
+
}
|
|
964
|
+
this.renderedIndices.clear();
|
|
749
965
|
this.el.innerHTML = "";
|
|
750
966
|
}
|
|
751
|
-
|
|
752
|
-
this.
|
|
967
|
+
renderAllVisible() {
|
|
968
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
969
|
+
items.forEach((item) => {
|
|
970
|
+
const idx = parseInt(item.dataset.thumbIndex || "-1", 10);
|
|
971
|
+
if (idx >= 0 && !this.renderedIndices.has(idx)) {
|
|
972
|
+
this.renderThumbnailItem(idx, item);
|
|
973
|
+
}
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
renderThumbnailItem(idx, itemEl) {
|
|
977
|
+
if (this.renderedIndices.has(idx)) return;
|
|
978
|
+
this.renderedIndices.add(idx);
|
|
979
|
+
const canvas = itemEl.querySelector("canvas");
|
|
980
|
+
const thumb = this.thumbnails[idx];
|
|
981
|
+
if (canvas && thumb) {
|
|
982
|
+
Promise.resolve(thumb.render(canvas)).catch((err) => {
|
|
983
|
+
console.warn(`[FilePreview] Error rendering thumbnail ${idx}:`, err);
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
render() {
|
|
988
|
+
if (this.observer) {
|
|
989
|
+
this.observer.disconnect();
|
|
990
|
+
}
|
|
991
|
+
this.listEl.innerHTML = "";
|
|
992
|
+
const useObserver = typeof IntersectionObserver !== "undefined";
|
|
993
|
+
if (useObserver) {
|
|
994
|
+
this.observer = new IntersectionObserver(
|
|
995
|
+
(entries) => {
|
|
996
|
+
for (const entry of entries) {
|
|
997
|
+
if (entry.isIntersecting) {
|
|
998
|
+
const target = entry.target;
|
|
999
|
+
const idx = parseInt(target.dataset.thumbIndex || "-1", 10);
|
|
1000
|
+
if (idx >= 0) {
|
|
1001
|
+
this.renderThumbnailItem(idx, target);
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
},
|
|
1006
|
+
{
|
|
1007
|
+
root: this.listEl,
|
|
1008
|
+
rootMargin: "120px 0px 120px 0px"
|
|
1009
|
+
}
|
|
1010
|
+
);
|
|
1011
|
+
}
|
|
753
1012
|
for (let i = 0; i < this.thumbnails.length; i++) {
|
|
754
1013
|
const thumb = this.thumbnails[i];
|
|
755
|
-
const itemEl = createElement("div", {
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
1014
|
+
const itemEl = createElement("div", {
|
|
1015
|
+
className: "fp-thumbnail-item" + (i === this.activeIndex ? " active" : "")
|
|
1016
|
+
});
|
|
1017
|
+
itemEl.dataset.thumbIndex = i.toString();
|
|
759
1018
|
itemEl.addEventListener("click", () => {
|
|
760
1019
|
this.setActive(i);
|
|
761
1020
|
this.onSelect?.(i);
|
|
762
1021
|
});
|
|
763
|
-
const
|
|
764
|
-
const
|
|
765
|
-
|
|
1022
|
+
const canvasWrapper = createElement("div", { className: "fp-thumbnail-canvas-wrapper" });
|
|
1023
|
+
const canvas = createElement("canvas", { width: "130", height: "170" });
|
|
1024
|
+
canvasWrapper.appendChild(canvas);
|
|
1025
|
+
const label = createElement("span", { className: "fp-thumbnail-label" }, thumb.label || `Page ${i + 1}`);
|
|
1026
|
+
itemEl.appendChild(canvasWrapper);
|
|
766
1027
|
itemEl.appendChild(label);
|
|
767
|
-
this.
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
}
|
|
771
|
-
|
|
1028
|
+
this.listEl.appendChild(itemEl);
|
|
1029
|
+
if (this.observer) {
|
|
1030
|
+
this.observer.observe(itemEl);
|
|
1031
|
+
}
|
|
1032
|
+
if (i < 4) {
|
|
1033
|
+
this.renderThumbnailItem(i, itemEl);
|
|
772
1034
|
}
|
|
773
1035
|
}
|
|
774
1036
|
}
|
|
@@ -789,6 +1051,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
789
1051
|
currentOptions = {};
|
|
790
1052
|
resizeObserver = null;
|
|
791
1053
|
fullscreenHandler = null;
|
|
1054
|
+
titleBarEl = null;
|
|
792
1055
|
/**
|
|
793
1056
|
* Register a preview plugin.
|
|
794
1057
|
*/
|
|
@@ -825,6 +1088,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
825
1088
|
}
|
|
826
1089
|
this.currentBuffer = buffer.slice(0);
|
|
827
1090
|
this.currentMetadata = metadata;
|
|
1091
|
+
this.updateTitleBar(options, metadata);
|
|
828
1092
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
829
1093
|
const fileInfo = { metadata, buffer };
|
|
830
1094
|
const matchedPlugin = await this.findPlugin(fileInfo);
|
|
@@ -848,15 +1112,21 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
848
1112
|
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
849
1113
|
const total = payload.total ?? payload.totalPages;
|
|
850
1114
|
this.toolbar?.setPage(payload.page, total);
|
|
1115
|
+
this.thumbnailPanel?.setActive(payload.page - 1);
|
|
851
1116
|
}
|
|
852
1117
|
this.eventEmitter.emit(event, payload);
|
|
853
|
-
}
|
|
1118
|
+
},
|
|
1119
|
+
toggleThumbnails: () => this.toggleThumbnails()
|
|
854
1120
|
});
|
|
855
1121
|
this.activeInstance = instance;
|
|
856
1122
|
instance.openInSeparateWindow = () => this.openInSeparateWindow();
|
|
1123
|
+
instance.toggleThumbnails = () => this.toggleThumbnails();
|
|
857
1124
|
this.hideLoading();
|
|
858
1125
|
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
859
|
-
|
|
1126
|
+
const isToolbarVisible = options.showToolbar !== false && options.toolbar !== false;
|
|
1127
|
+
if (isToolbarVisible && this.toolbar) {
|
|
1128
|
+
const toolbarConfig = this.extractToolbarConfig(options);
|
|
1129
|
+
this.toolbar.setConfig(toolbarConfig);
|
|
860
1130
|
const actions = matchedPlugin.getToolbarActions(instance);
|
|
861
1131
|
const hasFullscreen = actions.some((a) => a.id === "fullscreen");
|
|
862
1132
|
if (!hasFullscreen && this.wrapperEl) {
|
|
@@ -906,6 +1176,12 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
906
1176
|
}
|
|
907
1177
|
});
|
|
908
1178
|
}
|
|
1179
|
+
const thumbAction = actions.find((a) => a.id === "thumbnails");
|
|
1180
|
+
if (thumbAction) {
|
|
1181
|
+
thumbAction.execute = () => {
|
|
1182
|
+
this.toggleThumbnails();
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
909
1185
|
this.toolbar.update(actions);
|
|
910
1186
|
this.toolbar.show();
|
|
911
1187
|
}
|
|
@@ -990,7 +1266,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
990
1266
|
if (targetUrl) {
|
|
991
1267
|
const newWin2 = window.open(targetUrl, "_blank");
|
|
992
1268
|
if (!newWin2) {
|
|
993
|
-
|
|
1269
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
994
1270
|
return null;
|
|
995
1271
|
}
|
|
996
1272
|
return newWin2;
|
|
@@ -998,7 +1274,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
998
1274
|
const title = (this.currentMetadata?.name || "Document Preview") + " - Full Preview";
|
|
999
1275
|
const newWin = window.open("", "_blank");
|
|
1000
1276
|
if (!newWin) {
|
|
1001
|
-
|
|
1277
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
1002
1278
|
return null;
|
|
1003
1279
|
}
|
|
1004
1280
|
newWin.document.title = title;
|
|
@@ -1075,6 +1351,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1075
1351
|
this.currentBuffer = null;
|
|
1076
1352
|
this.currentMetadata = null;
|
|
1077
1353
|
this.currentContainer = null;
|
|
1354
|
+
this.titleBarEl = null;
|
|
1078
1355
|
}
|
|
1079
1356
|
/**
|
|
1080
1357
|
* Get the currently active preview instance.
|
|
@@ -1082,7 +1359,218 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1082
1359
|
getInstance() {
|
|
1083
1360
|
return this.activeInstance;
|
|
1084
1361
|
}
|
|
1362
|
+
// --- Toolbar Configuration & Feature Toggles ---
|
|
1363
|
+
/**
|
|
1364
|
+
* Configure toolbar features dynamically through options or methods.
|
|
1365
|
+
* e.g. viewer.setToolbarConfig({ zoomIn: false, print: false })
|
|
1366
|
+
*/
|
|
1367
|
+
setToolbarConfig(config) {
|
|
1368
|
+
this.toolbar?.setConfig(config);
|
|
1369
|
+
}
|
|
1370
|
+
/**
|
|
1371
|
+
* Get current toolbar configuration.
|
|
1372
|
+
*/
|
|
1373
|
+
getToolbarConfig() {
|
|
1374
|
+
return this.toolbar?.getConfig() ?? {};
|
|
1375
|
+
}
|
|
1376
|
+
/**
|
|
1377
|
+
* Hide a specific toolbar action by ID or alias (e.g. 'zoom-in', 'print', 'download').
|
|
1378
|
+
*/
|
|
1379
|
+
hideToolbarAction(actionId) {
|
|
1380
|
+
this.toolbar?.hideAction(actionId);
|
|
1381
|
+
}
|
|
1382
|
+
/**
|
|
1383
|
+
* Show a specific toolbar action by ID or alias.
|
|
1384
|
+
*/
|
|
1385
|
+
showToolbarAction(actionId) {
|
|
1386
|
+
this.toolbar?.showAction(actionId);
|
|
1387
|
+
}
|
|
1388
|
+
/**
|
|
1389
|
+
* Enable a specific toolbar action button.
|
|
1390
|
+
*/
|
|
1391
|
+
enableToolbarAction(actionId) {
|
|
1392
|
+
this.toolbar?.enableAction(actionId);
|
|
1393
|
+
}
|
|
1394
|
+
/**
|
|
1395
|
+
* Disable a specific toolbar action button.
|
|
1396
|
+
*/
|
|
1397
|
+
disableToolbarAction(actionId) {
|
|
1398
|
+
this.toolbar?.disableAction(actionId);
|
|
1399
|
+
}
|
|
1400
|
+
// --- Programmatic Toolbar Action Methods ---
|
|
1401
|
+
/**
|
|
1402
|
+
* Fit document to page so it fills the frame width with minimal margins.
|
|
1403
|
+
*/
|
|
1404
|
+
fitToPage() {
|
|
1405
|
+
this.activeInstance?.fitToPage?.();
|
|
1406
|
+
}
|
|
1407
|
+
/**
|
|
1408
|
+
* Zoom in.
|
|
1409
|
+
*/
|
|
1410
|
+
zoomIn() {
|
|
1411
|
+
this.activeInstance?.zoomIn?.();
|
|
1412
|
+
}
|
|
1413
|
+
/**
|
|
1414
|
+
* Zoom out.
|
|
1415
|
+
*/
|
|
1416
|
+
zoomOut() {
|
|
1417
|
+
this.activeInstance?.zoomOut?.();
|
|
1418
|
+
}
|
|
1419
|
+
/**
|
|
1420
|
+
* Set specific zoom level.
|
|
1421
|
+
*/
|
|
1422
|
+
setZoom(level) {
|
|
1423
|
+
this.activeInstance?.setZoom?.(level);
|
|
1424
|
+
}
|
|
1425
|
+
/**
|
|
1426
|
+
* Get current zoom level.
|
|
1427
|
+
*/
|
|
1428
|
+
getZoom() {
|
|
1429
|
+
return this.activeInstance?.getZoom?.() ?? 1;
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* Rotate 90 degrees clockwise.
|
|
1433
|
+
*/
|
|
1434
|
+
rotateCW() {
|
|
1435
|
+
this.activeInstance?.rotateCW?.();
|
|
1436
|
+
}
|
|
1437
|
+
/**
|
|
1438
|
+
* Rotate 90 degrees counter-clockwise.
|
|
1439
|
+
*/
|
|
1440
|
+
rotateCCW() {
|
|
1441
|
+
this.activeInstance?.rotateCCW?.();
|
|
1442
|
+
}
|
|
1443
|
+
/**
|
|
1444
|
+
* Navigate to a specific page number.
|
|
1445
|
+
*/
|
|
1446
|
+
goToPage(page) {
|
|
1447
|
+
this.activeInstance?.goToPage?.(page);
|
|
1448
|
+
this.toolbar?.setPage(page);
|
|
1449
|
+
}
|
|
1450
|
+
/**
|
|
1451
|
+
* Navigate to next page.
|
|
1452
|
+
*/
|
|
1453
|
+
nextPage() {
|
|
1454
|
+
const cur = this.getCurrentPage();
|
|
1455
|
+
const max = this.getPageCount();
|
|
1456
|
+
if (cur < max) {
|
|
1457
|
+
this.goToPage(cur + 1);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
/**
|
|
1461
|
+
* Navigate to previous page.
|
|
1462
|
+
*/
|
|
1463
|
+
prevPage() {
|
|
1464
|
+
const cur = this.getCurrentPage();
|
|
1465
|
+
if (cur > 1) {
|
|
1466
|
+
this.goToPage(cur - 1);
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
/**
|
|
1470
|
+
* Get total page count.
|
|
1471
|
+
*/
|
|
1472
|
+
getPageCount() {
|
|
1473
|
+
return this.activeInstance?.getPageCount?.() ?? 1;
|
|
1474
|
+
}
|
|
1475
|
+
/**
|
|
1476
|
+
* Get current page number.
|
|
1477
|
+
*/
|
|
1478
|
+
getCurrentPage() {
|
|
1479
|
+
return this.activeInstance?.getCurrentPage?.() ?? 1;
|
|
1480
|
+
}
|
|
1481
|
+
/**
|
|
1482
|
+
* Download the current document.
|
|
1483
|
+
*/
|
|
1484
|
+
download() {
|
|
1485
|
+
this.activeInstance?.download?.();
|
|
1486
|
+
}
|
|
1487
|
+
/**
|
|
1488
|
+
* Print the current document.
|
|
1489
|
+
*/
|
|
1490
|
+
print() {
|
|
1491
|
+
this.activeInstance?.print?.();
|
|
1492
|
+
}
|
|
1493
|
+
/**
|
|
1494
|
+
* Toggle fullscreen mode.
|
|
1495
|
+
*/
|
|
1496
|
+
toggleFullscreen() {
|
|
1497
|
+
try {
|
|
1498
|
+
if (!document.fullscreenElement) {
|
|
1499
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
1500
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
1501
|
+
} else {
|
|
1502
|
+
document.exitFullscreen?.();
|
|
1503
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
1504
|
+
}
|
|
1505
|
+
} catch {
|
|
1506
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
1507
|
+
}
|
|
1508
|
+
setTimeout(() => {
|
|
1509
|
+
this.activeInstance?.fitToPage?.();
|
|
1510
|
+
}, 120);
|
|
1511
|
+
}
|
|
1512
|
+
/**
|
|
1513
|
+
* Toggle thumbnails sidebar panel.
|
|
1514
|
+
*/
|
|
1515
|
+
toggleThumbnails() {
|
|
1516
|
+
if (!this.thumbnailPanel) return;
|
|
1517
|
+
this.thumbnailPanel.toggle();
|
|
1518
|
+
const isOpen = this.thumbnailPanel.isOpen();
|
|
1519
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1520
|
+
setTimeout(() => {
|
|
1521
|
+
this.activeInstance?.fitToPage?.();
|
|
1522
|
+
}, 260);
|
|
1523
|
+
}
|
|
1524
|
+
/**
|
|
1525
|
+
* Set whether to display the file name / title bar above the toolbar.
|
|
1526
|
+
*/
|
|
1527
|
+
setShowFileName(show) {
|
|
1528
|
+
if (this.currentOptions) {
|
|
1529
|
+
this.currentOptions.showFileName = show;
|
|
1530
|
+
}
|
|
1531
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1532
|
+
}
|
|
1533
|
+
/**
|
|
1534
|
+
* Set or override the displayed file name in the preview panel.
|
|
1535
|
+
*/
|
|
1536
|
+
setFileName(name) {
|
|
1537
|
+
if (this.currentOptions) {
|
|
1538
|
+
this.currentOptions.fileName = name;
|
|
1539
|
+
}
|
|
1540
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1541
|
+
}
|
|
1085
1542
|
// --- Private methods ---
|
|
1543
|
+
updateTitleBar(options, metadata) {
|
|
1544
|
+
if (!this.titleBarEl) return;
|
|
1545
|
+
const show = options?.showFileName !== false;
|
|
1546
|
+
if (!show) {
|
|
1547
|
+
this.titleBarEl.style.display = "none";
|
|
1548
|
+
return;
|
|
1549
|
+
}
|
|
1550
|
+
const name = options?.fileName || metadata?.name || this.currentMetadata?.name || "";
|
|
1551
|
+
if (!name) {
|
|
1552
|
+
this.titleBarEl.style.display = "none";
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1555
|
+
this.titleBarEl.style.display = "flex";
|
|
1556
|
+
const ext = metadata?.extension || (name.includes(".") ? "." + name.split(".").pop() : "");
|
|
1557
|
+
const badge = ext ? ext.replace(".", "").toUpperCase() : "";
|
|
1558
|
+
this.titleBarEl.innerHTML = `
|
|
1559
|
+
<div class="fp-titlebar-info">
|
|
1560
|
+
<span class="fp-titlebar-icon">\u{1F4C4}</span>
|
|
1561
|
+
<span class="fp-titlebar-name" title="${name}">${name}</span>
|
|
1562
|
+
${badge ? `<span class="fp-titlebar-badge">${badge}</span>` : ""}
|
|
1563
|
+
</div>
|
|
1564
|
+
`;
|
|
1565
|
+
}
|
|
1566
|
+
extractToolbarConfig(options) {
|
|
1567
|
+
if (!options) return {};
|
|
1568
|
+
const nested = typeof options.toolbar === "object" ? options.toolbar : {};
|
|
1569
|
+
return {
|
|
1570
|
+
...options,
|
|
1571
|
+
...nested
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1086
1574
|
abort() {
|
|
1087
1575
|
if (this.abortController) {
|
|
1088
1576
|
this.abortController.abort();
|
|
@@ -1125,17 +1613,29 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1125
1613
|
bodyEl.className = "fp-body";
|
|
1126
1614
|
bodyEl.appendChild(thumbnailEl);
|
|
1127
1615
|
bodyEl.appendChild(this.contentEl);
|
|
1616
|
+
const titleBarEl = document.createElement("div");
|
|
1617
|
+
titleBarEl.className = "fp-titlebar";
|
|
1618
|
+
this.titleBarEl = titleBarEl;
|
|
1619
|
+
this.updateTitleBar(options, this.currentMetadata);
|
|
1128
1620
|
if (toolbarPos === "top") {
|
|
1621
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1129
1622
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1130
1623
|
this.wrapperEl.appendChild(bodyEl);
|
|
1131
1624
|
} else {
|
|
1625
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1132
1626
|
this.wrapperEl.appendChild(bodyEl);
|
|
1133
1627
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1134
1628
|
}
|
|
1135
1629
|
container.innerHTML = "";
|
|
1136
1630
|
container.appendChild(this.wrapperEl);
|
|
1137
|
-
|
|
1138
|
-
this.
|
|
1631
|
+
const initialToolbarConfig = this.extractToolbarConfig(options);
|
|
1632
|
+
this.toolbar = new ToolbarController(toolbarEl, initialToolbarConfig);
|
|
1633
|
+
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl, (isOpen) => {
|
|
1634
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1635
|
+
setTimeout(() => {
|
|
1636
|
+
this.activeInstance?.fitToPage?.();
|
|
1637
|
+
}, 260);
|
|
1638
|
+
});
|
|
1139
1639
|
this.setupKeyboardShortcuts();
|
|
1140
1640
|
this.setupDragAndDrop(container, options);
|
|
1141
1641
|
this.setupResizeAndFullscreenListeners();
|
|
@@ -1525,6 +2025,14 @@ var PdfPlugin = class {
|
|
|
1525
2025
|
group: "zoom",
|
|
1526
2026
|
execute: () => instance.fitToPage?.()
|
|
1527
2027
|
},
|
|
2028
|
+
{
|
|
2029
|
+
id: "fit-width",
|
|
2030
|
+
icon: "fit-width",
|
|
2031
|
+
label: "Fit to Width",
|
|
2032
|
+
type: "button",
|
|
2033
|
+
group: "zoom",
|
|
2034
|
+
execute: () => instance.fitToWidth?.()
|
|
2035
|
+
},
|
|
1528
2036
|
{
|
|
1529
2037
|
id: "rotate-cw",
|
|
1530
2038
|
icon: "rotate-cw",
|
|
@@ -1533,6 +2041,14 @@ var PdfPlugin = class {
|
|
|
1533
2041
|
group: "view",
|
|
1534
2042
|
execute: () => instance.rotateCW?.()
|
|
1535
2043
|
},
|
|
2044
|
+
{
|
|
2045
|
+
id: "rotate-ccw",
|
|
2046
|
+
icon: "rotate-ccw",
|
|
2047
|
+
label: "Rotate Counter-Clockwise",
|
|
2048
|
+
type: "button",
|
|
2049
|
+
group: "view",
|
|
2050
|
+
execute: () => instance.rotateCCW?.()
|
|
2051
|
+
},
|
|
1536
2052
|
{
|
|
1537
2053
|
id: "download",
|
|
1538
2054
|
icon: "download",
|
|
@@ -1564,12 +2080,13 @@ var PdfPlugin = class {
|
|
|
1564
2080
|
container.className = "fp-pdf-container";
|
|
1565
2081
|
container.style.width = "100%";
|
|
1566
2082
|
container.style.height = "100%";
|
|
1567
|
-
container.style.
|
|
2083
|
+
container.style.overflowX = "hidden";
|
|
2084
|
+
container.style.overflowY = "auto";
|
|
1568
2085
|
container.style.display = "flex";
|
|
1569
2086
|
container.style.flexDirection = "column";
|
|
1570
2087
|
container.style.alignItems = "center";
|
|
1571
2088
|
container.style.justifyContent = "flex-start";
|
|
1572
|
-
container.style.padding = "
|
|
2089
|
+
container.style.padding = "16px 8px";
|
|
1573
2090
|
container.style.backgroundColor = "#0f172a";
|
|
1574
2091
|
container.style.boxSizing = "border-box";
|
|
1575
2092
|
container.style.position = "relative";
|
|
@@ -1580,30 +2097,12 @@ var PdfPlugin = class {
|
|
|
1580
2097
|
pageCard.style.borderRadius = "4px";
|
|
1581
2098
|
pageCard.style.overflow = "hidden";
|
|
1582
2099
|
pageCard.style.lineHeight = "0";
|
|
1583
|
-
pageCard.style.transition = "transform 0.15s ease";
|
|
1584
2100
|
pageCard.style.position = "relative";
|
|
1585
2101
|
pageCard.style.flexShrink = "0";
|
|
2102
|
+
pageCard.style.transition = "box-shadow 0.2s ease";
|
|
1586
2103
|
let canvas = document.createElement("canvas");
|
|
1587
2104
|
pageCard.appendChild(canvas);
|
|
1588
2105
|
container.appendChild(pageCard);
|
|
1589
|
-
const indicator = document.createElement("div");
|
|
1590
|
-
indicator.className = "fp-pdf-page-indicator";
|
|
1591
|
-
indicator.style.position = "sticky";
|
|
1592
|
-
indicator.style.bottom = "16px";
|
|
1593
|
-
indicator.style.marginTop = "16px";
|
|
1594
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1595
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
1596
|
-
indicator.style.color = "#f8fafc";
|
|
1597
|
-
indicator.style.fontSize = "12px";
|
|
1598
|
-
indicator.style.fontWeight = "600";
|
|
1599
|
-
indicator.style.padding = "5px 14px";
|
|
1600
|
-
indicator.style.borderRadius = "20px";
|
|
1601
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1602
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1603
|
-
indicator.style.zIndex = "10";
|
|
1604
|
-
indicator.style.userSelect = "none";
|
|
1605
|
-
indicator.style.pointerEvents = "none";
|
|
1606
|
-
container.appendChild(indicator);
|
|
1607
2106
|
ctx.container.appendChild(container);
|
|
1608
2107
|
const standardFontsUrl = typeof window !== "undefined" && window.__PDF_STANDARD_FONTS_URL__ || "./standard_fonts/";
|
|
1609
2108
|
const cmapsUrl = typeof window !== "undefined" && window.__PDF_CMAPS_URL__ || "./cmaps/";
|
|
@@ -1619,8 +2118,9 @@ var PdfPlugin = class {
|
|
|
1619
2118
|
let currentPage = 1;
|
|
1620
2119
|
let zoomScale = 1;
|
|
1621
2120
|
let rotation = 0;
|
|
1622
|
-
let fitMode = "
|
|
2121
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
1623
2122
|
let currentRenderTask = null;
|
|
2123
|
+
let textLayerDiv = null;
|
|
1624
2124
|
const renderPage = async (pageNum) => {
|
|
1625
2125
|
if (currentRenderTask) {
|
|
1626
2126
|
try {
|
|
@@ -1632,30 +2132,37 @@ var PdfPlugin = class {
|
|
|
1632
2132
|
const newCanvas = document.createElement("canvas");
|
|
1633
2133
|
pageCard.replaceChild(newCanvas, canvas);
|
|
1634
2134
|
canvas = newCanvas;
|
|
2135
|
+
if (textLayerDiv) {
|
|
2136
|
+
textLayerDiv.remove();
|
|
2137
|
+
textLayerDiv = null;
|
|
2138
|
+
}
|
|
1635
2139
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1636
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1637
2140
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1638
2141
|
const page = await pdfDoc.getPage(currentPage);
|
|
1639
2142
|
const containerWidth = container.clientWidth || 900;
|
|
1640
2143
|
const containerHeight = container.clientHeight || 700;
|
|
1641
2144
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1642
|
-
const availWidth = Math.max(
|
|
1643
|
-
const availHeight = Math.max(
|
|
2145
|
+
const availWidth = Math.max(280, containerWidth - 36);
|
|
2146
|
+
const availHeight = Math.max(280, containerHeight - 32);
|
|
1644
2147
|
const scaleW = availWidth / unscaledVp.width;
|
|
1645
2148
|
const scaleH = availHeight / unscaledVp.height;
|
|
1646
2149
|
let fitScale;
|
|
1647
2150
|
if (fitMode === "page") {
|
|
1648
|
-
fitScale = Math.max(0.4, Math.min(scaleW, scaleH));
|
|
2151
|
+
fitScale = Math.max(0.2, Math.min(4, Math.min(scaleW, scaleH)));
|
|
1649
2152
|
} else {
|
|
1650
|
-
fitScale = Math.max(0.
|
|
2153
|
+
fitScale = Math.max(0.2, Math.min(4, scaleW));
|
|
1651
2154
|
}
|
|
1652
2155
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1653
2156
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1654
2157
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
2158
|
+
const displayWidth = Math.floor(viewport.width);
|
|
2159
|
+
const displayHeight = Math.floor(viewport.height);
|
|
1655
2160
|
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1656
2161
|
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1657
|
-
canvas.style.width = `${
|
|
1658
|
-
canvas.style.height = `${
|
|
2162
|
+
canvas.style.width = `${displayWidth}px`;
|
|
2163
|
+
canvas.style.height = `${displayHeight}px`;
|
|
2164
|
+
pageCard.style.width = `${displayWidth}px`;
|
|
2165
|
+
pageCard.style.height = `${displayHeight}px`;
|
|
1659
2166
|
const canvasCtx = canvas.getContext("2d");
|
|
1660
2167
|
if (!canvasCtx) return;
|
|
1661
2168
|
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
@@ -1669,9 +2176,31 @@ var PdfPlugin = class {
|
|
|
1669
2176
|
if (err?.name !== "RenderingCancelledException") {
|
|
1670
2177
|
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1671
2178
|
}
|
|
2179
|
+
return;
|
|
1672
2180
|
} finally {
|
|
1673
2181
|
currentRenderTask = null;
|
|
1674
2182
|
}
|
|
2183
|
+
try {
|
|
2184
|
+
textLayerDiv = document.createElement("div");
|
|
2185
|
+
textLayerDiv.className = "textLayer";
|
|
2186
|
+
textLayerDiv.style.width = `${displayWidth}px`;
|
|
2187
|
+
textLayerDiv.style.height = `${displayHeight}px`;
|
|
2188
|
+
textLayerDiv.style.position = "absolute";
|
|
2189
|
+
textLayerDiv.style.top = "0";
|
|
2190
|
+
textLayerDiv.style.left = "0";
|
|
2191
|
+
textLayerDiv.style.lineHeight = "1";
|
|
2192
|
+
pageCard.appendChild(textLayerDiv);
|
|
2193
|
+
if (pdfjsLib__namespace.TextLayer) {
|
|
2194
|
+
const textLayer = new pdfjsLib__namespace.TextLayer({
|
|
2195
|
+
textContentSource: page.streamTextContent(),
|
|
2196
|
+
container: textLayerDiv,
|
|
2197
|
+
viewport
|
|
2198
|
+
});
|
|
2199
|
+
await textLayer.render();
|
|
2200
|
+
}
|
|
2201
|
+
} catch (err) {
|
|
2202
|
+
console.debug("[PdfPlugin] TextLayer notice:", err);
|
|
2203
|
+
}
|
|
1675
2204
|
};
|
|
1676
2205
|
renderPage(1);
|
|
1677
2206
|
let resizeTimer = null;
|
|
@@ -1681,11 +2210,48 @@ var PdfPlugin = class {
|
|
|
1681
2210
|
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1682
2211
|
renderPage(currentPage);
|
|
1683
2212
|
}
|
|
1684
|
-
},
|
|
2213
|
+
}, 120);
|
|
1685
2214
|
});
|
|
1686
2215
|
resizeObserver.observe(container);
|
|
2216
|
+
const onWheel = (e) => {
|
|
2217
|
+
if (e.ctrlKey || e.metaKey) {
|
|
2218
|
+
e.preventDefault();
|
|
2219
|
+
const delta = e.deltaY > 0 ? -0.15 : 0.15;
|
|
2220
|
+
zoomScale = Math.max(0.25, Math.min(4, Math.round((zoomScale + delta) * 100) / 100));
|
|
2221
|
+
renderPage(currentPage);
|
|
2222
|
+
}
|
|
2223
|
+
};
|
|
2224
|
+
container.addEventListener("wheel", onWheel, { passive: false });
|
|
2225
|
+
const onKeyDown = (e) => {
|
|
2226
|
+
const tag = e.target?.tagName?.toLowerCase();
|
|
2227
|
+
if (tag === "input" || tag === "textarea" || tag === "select") return;
|
|
2228
|
+
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
2229
|
+
if (currentPage < totalPages) {
|
|
2230
|
+
e.preventDefault();
|
|
2231
|
+
container.scrollTop = 0;
|
|
2232
|
+
renderPage(currentPage + 1);
|
|
2233
|
+
}
|
|
2234
|
+
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
2235
|
+
if (currentPage > 1) {
|
|
2236
|
+
e.preventDefault();
|
|
2237
|
+
container.scrollTop = 0;
|
|
2238
|
+
renderPage(currentPage - 1);
|
|
2239
|
+
}
|
|
2240
|
+
} else if (e.key === "Home") {
|
|
2241
|
+
e.preventDefault();
|
|
2242
|
+
container.scrollTop = 0;
|
|
2243
|
+
renderPage(1);
|
|
2244
|
+
} else if (e.key === "End") {
|
|
2245
|
+
e.preventDefault();
|
|
2246
|
+
container.scrollTop = 0;
|
|
2247
|
+
renderPage(totalPages);
|
|
2248
|
+
}
|
|
2249
|
+
};
|
|
2250
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1687
2251
|
const cleanup = () => {
|
|
1688
2252
|
resizeObserver.disconnect();
|
|
2253
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
2254
|
+
container.removeEventListener("wheel", onWheel);
|
|
1689
2255
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1690
2256
|
if (currentRenderTask) {
|
|
1691
2257
|
try {
|
|
@@ -1704,22 +2270,26 @@ var PdfPlugin = class {
|
|
|
1704
2270
|
const instance = {
|
|
1705
2271
|
destroy: cleanup,
|
|
1706
2272
|
zoomIn: () => {
|
|
1707
|
-
zoomScale = Math.min(
|
|
2273
|
+
zoomScale = Math.min(4, Math.round((zoomScale + 0.2) * 10) / 10);
|
|
1708
2274
|
renderPage(currentPage);
|
|
1709
2275
|
},
|
|
1710
2276
|
zoomOut: () => {
|
|
1711
|
-
zoomScale = Math.max(0.
|
|
2277
|
+
zoomScale = Math.max(0.25, Math.round((zoomScale - 0.2) * 10) / 10);
|
|
1712
2278
|
renderPage(currentPage);
|
|
1713
2279
|
},
|
|
1714
2280
|
getZoom: () => zoomScale,
|
|
1715
2281
|
setZoom: (level) => {
|
|
1716
|
-
zoomScale = Math.max(0.
|
|
2282
|
+
zoomScale = Math.max(0.25, Math.min(4, level));
|
|
1717
2283
|
renderPage(currentPage);
|
|
1718
2284
|
},
|
|
1719
2285
|
fitToPage: () => {
|
|
1720
|
-
fitMode =
|
|
2286
|
+
fitMode = "page";
|
|
2287
|
+
zoomScale = 1;
|
|
2288
|
+
renderPage(currentPage);
|
|
2289
|
+
},
|
|
2290
|
+
fitToWidth: () => {
|
|
2291
|
+
fitMode = "width";
|
|
1721
2292
|
zoomScale = 1;
|
|
1722
|
-
rotation = 0;
|
|
1723
2293
|
renderPage(currentPage);
|
|
1724
2294
|
},
|
|
1725
2295
|
rotateCW: () => {
|
|
@@ -1737,6 +2307,9 @@ var PdfPlugin = class {
|
|
|
1737
2307
|
container.scrollTop = 0;
|
|
1738
2308
|
renderPage(page);
|
|
1739
2309
|
},
|
|
2310
|
+
toggleThumbnails: () => {
|
|
2311
|
+
ctx?.toggleThumbnails?.();
|
|
2312
|
+
},
|
|
1740
2313
|
download: () => {
|
|
1741
2314
|
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1742
2315
|
const url = URL.createObjectURL(blob);
|
|
@@ -1770,7 +2343,7 @@ var PdfPlugin = class {
|
|
|
1770
2343
|
},
|
|
1771
2344
|
getThumbnails: async () => {
|
|
1772
2345
|
const thumbnails = [];
|
|
1773
|
-
const count =
|
|
2346
|
+
const count = totalPages;
|
|
1774
2347
|
for (let i = 1; i <= count; i++) {
|
|
1775
2348
|
thumbnails.push({
|
|
1776
2349
|
index: i,
|
|
@@ -1778,9 +2351,10 @@ var PdfPlugin = class {
|
|
|
1778
2351
|
render: async (thumbCanvas) => {
|
|
1779
2352
|
try {
|
|
1780
2353
|
const p = await pdfDoc.getPage(i);
|
|
1781
|
-
const baseVp = p.getViewport({ scale: 1 });
|
|
1782
|
-
const
|
|
1783
|
-
const
|
|
2354
|
+
const baseVp = p.getViewport({ scale: 1, rotation });
|
|
2355
|
+
const targetW = thumbCanvas.width || 130;
|
|
2356
|
+
const thumbScale = targetW / baseVp.width;
|
|
2357
|
+
const thumbVp = p.getViewport({ scale: thumbScale, rotation });
|
|
1784
2358
|
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1785
2359
|
const tCtx = thumbCanvas.getContext("2d");
|
|
1786
2360
|
if (tCtx) {
|
|
@@ -2124,28 +2698,26 @@ var DocxPlugin = class {
|
|
|
2124
2698
|
getToolbarActions(instance) {
|
|
2125
2699
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2126
2700
|
const actions = [];
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
if (
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
instance.goToPage?.(page);
|
|
2145
|
-
}
|
|
2701
|
+
actions.push({
|
|
2702
|
+
id: "page-nav",
|
|
2703
|
+
icon: "",
|
|
2704
|
+
label: "Page Navigation",
|
|
2705
|
+
type: "page-nav",
|
|
2706
|
+
group: "navigation",
|
|
2707
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2708
|
+
max: totalPages,
|
|
2709
|
+
execute: (action, page) => {
|
|
2710
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2711
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2712
|
+
if (action === "prev") {
|
|
2713
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2714
|
+
} else if (action === "next") {
|
|
2715
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2716
|
+
} else if (typeof page === "number") {
|
|
2717
|
+
instance.goToPage?.(page);
|
|
2146
2718
|
}
|
|
2147
|
-
}
|
|
2148
|
-
}
|
|
2719
|
+
}
|
|
2720
|
+
});
|
|
2149
2721
|
actions.push(
|
|
2150
2722
|
{
|
|
2151
2723
|
id: "zoom-out",
|
|
@@ -2211,11 +2783,17 @@ var DocxPlugin = class {
|
|
|
2211
2783
|
wrapper.className = "fp-docx-wrapper";
|
|
2212
2784
|
wrapper.style.transformOrigin = "top center";
|
|
2213
2785
|
wrapper.style.transition = "transform 0.2s ease";
|
|
2214
|
-
wrapper.style.padding = "
|
|
2215
|
-
wrapper.style.maxWidth = "
|
|
2786
|
+
wrapper.style.padding = "0";
|
|
2787
|
+
wrapper.style.maxWidth = "none";
|
|
2788
|
+
wrapper.style.width = "816px";
|
|
2216
2789
|
wrapper.style.margin = "0 auto";
|
|
2790
|
+
wrapper.style.display = "flex";
|
|
2791
|
+
wrapper.style.flexDirection = "column";
|
|
2792
|
+
wrapper.style.alignItems = "center";
|
|
2217
2793
|
wrapper.style.boxSizing = "border-box";
|
|
2218
|
-
ctx.container.style.
|
|
2794
|
+
ctx.container.style.overflowX = "hidden";
|
|
2795
|
+
ctx.container.style.overflowY = "auto";
|
|
2796
|
+
ctx.container.style.padding = "16px 8px";
|
|
2219
2797
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
2220
2798
|
ctx.container.appendChild(wrapper);
|
|
2221
2799
|
const styleOverride = document.createElement("style");
|
|
@@ -2389,39 +2967,13 @@ var DocxPlugin = class {
|
|
|
2389
2967
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2390
2968
|
const totalPages = Math.max(1, pageElements.length);
|
|
2391
2969
|
let currentPage = 1;
|
|
2392
|
-
let indicator = null;
|
|
2393
|
-
if (totalPages > 1) {
|
|
2394
|
-
indicator = document.createElement("div");
|
|
2395
|
-
indicator.className = "fp-docx-page-indicator";
|
|
2396
|
-
indicator.style.position = "sticky";
|
|
2397
|
-
indicator.style.bottom = "16px";
|
|
2398
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2399
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
2400
|
-
indicator.style.color = "#f8fafc";
|
|
2401
|
-
indicator.style.fontSize = "12px";
|
|
2402
|
-
indicator.style.fontWeight = "600";
|
|
2403
|
-
indicator.style.padding = "5px 14px";
|
|
2404
|
-
indicator.style.borderRadius = "20px";
|
|
2405
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2406
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2407
|
-
indicator.style.zIndex = "10";
|
|
2408
|
-
indicator.style.userSelect = "none";
|
|
2409
|
-
indicator.style.pointerEvents = "none";
|
|
2410
|
-
indicator.style.textAlign = "center";
|
|
2411
|
-
indicator.style.width = "fit-content";
|
|
2412
|
-
indicator.style.margin = "16px auto 0";
|
|
2413
|
-
ctx.container.appendChild(indicator);
|
|
2414
|
-
}
|
|
2415
2970
|
const showPage = (pageNum) => {
|
|
2416
2971
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2417
2972
|
if (pageElements.length > 1) {
|
|
2418
2973
|
pageElements.forEach((sec, idx) => {
|
|
2419
|
-
sec.style.display = idx + 1 === currentPage ? "
|
|
2974
|
+
sec.style.display = idx + 1 === currentPage ? "" : "none";
|
|
2420
2975
|
});
|
|
2421
2976
|
}
|
|
2422
|
-
if (indicator) {
|
|
2423
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2424
|
-
}
|
|
2425
2977
|
ctx.container.scrollTop = 0;
|
|
2426
2978
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2427
2979
|
};
|
|
@@ -2430,31 +2982,46 @@ var DocxPlugin = class {
|
|
|
2430
2982
|
}
|
|
2431
2983
|
scale = 1;
|
|
2432
2984
|
let rotation = 0;
|
|
2433
|
-
let fitMode = "
|
|
2434
|
-
|
|
2435
|
-
|
|
2985
|
+
let fitMode = "page";
|
|
2986
|
+
let isUserZoomed = false;
|
|
2987
|
+
const calculateFitScale = (_mode = fitMode) => {
|
|
2988
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
2436
2989
|
const elW = activeEl.offsetWidth || 816;
|
|
2437
|
-
const
|
|
2438
|
-
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
2439
|
-
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
2990
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
2440
2991
|
const sW = availW / elW;
|
|
2441
|
-
|
|
2442
|
-
if (mode === "page") {
|
|
2443
|
-
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
2444
|
-
}
|
|
2445
|
-
return Math.max(0.65, Math.min(1.05, sW));
|
|
2992
|
+
return Math.max(0.35, Math.min(3, sW));
|
|
2446
2993
|
};
|
|
2447
2994
|
const applyTransform = () => {
|
|
2448
2995
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2449
2996
|
wrapper.style.transformOrigin = "top center";
|
|
2997
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
2998
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
2999
|
+
if (scale > 1) {
|
|
3000
|
+
wrapper.style.marginBottom = `${Math.round(elH * scale - elH + 32)}px`;
|
|
3001
|
+
} else {
|
|
3002
|
+
wrapper.style.marginBottom = "32px";
|
|
3003
|
+
}
|
|
2450
3004
|
};
|
|
3005
|
+
let resizeObserver = null;
|
|
3006
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
3007
|
+
resizeObserver = new ResizeObserver(() => {
|
|
3008
|
+
if (!isUserZoomed) {
|
|
3009
|
+
const newFit = calculateFitScale("page");
|
|
3010
|
+
if (Math.abs(scale - newFit) > 0.015) {
|
|
3011
|
+
scale = newFit;
|
|
3012
|
+
applyTransform();
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
});
|
|
3016
|
+
resizeObserver.observe(ctx.container);
|
|
3017
|
+
}
|
|
2451
3018
|
setTimeout(() => {
|
|
2452
|
-
|
|
2453
|
-
scale = calculateFitScale("width");
|
|
3019
|
+
scale = calculateFitScale("page");
|
|
2454
3020
|
applyTransform();
|
|
2455
|
-
},
|
|
3021
|
+
}, 40);
|
|
2456
3022
|
const cleanup = () => {
|
|
2457
|
-
|
|
3023
|
+
resizeObserver?.disconnect();
|
|
3024
|
+
resizeObserver = null;
|
|
2458
3025
|
for (const url of createdBlobUrls) {
|
|
2459
3026
|
URL.revokeObjectURL(url);
|
|
2460
3027
|
}
|
|
@@ -2471,21 +3038,24 @@ var DocxPlugin = class {
|
|
|
2471
3038
|
showPage(page);
|
|
2472
3039
|
},
|
|
2473
3040
|
zoomIn: () => {
|
|
2474
|
-
|
|
3041
|
+
isUserZoomed = true;
|
|
3042
|
+
scale = Math.min(3.5, scale + 0.15);
|
|
2475
3043
|
applyTransform();
|
|
2476
3044
|
},
|
|
2477
3045
|
zoomOut: () => {
|
|
3046
|
+
isUserZoomed = true;
|
|
2478
3047
|
scale = Math.max(0.2, scale - 0.15);
|
|
2479
3048
|
applyTransform();
|
|
2480
3049
|
},
|
|
2481
3050
|
getZoom: () => scale,
|
|
2482
3051
|
setZoom: (level) => {
|
|
3052
|
+
isUserZoomed = true;
|
|
2483
3053
|
scale = level;
|
|
2484
3054
|
applyTransform();
|
|
2485
3055
|
},
|
|
2486
3056
|
fitToPage: () => {
|
|
2487
|
-
|
|
2488
|
-
scale = calculateFitScale(
|
|
3057
|
+
isUserZoomed = false;
|
|
3058
|
+
scale = calculateFitScale("page");
|
|
2489
3059
|
rotation = 0;
|
|
2490
3060
|
applyTransform();
|
|
2491
3061
|
},
|
|
@@ -2875,7 +3445,7 @@ var ExcelPlugin = class {
|
|
|
2875
3445
|
"application/vnd.ms-excel.template.macroEnabled.12",
|
|
2876
3446
|
"application/vnd.oasis.opendocument.spreadsheet"
|
|
2877
3447
|
];
|
|
2878
|
-
weight =
|
|
3448
|
+
weight = 85;
|
|
2879
3449
|
supports(file) {
|
|
2880
3450
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2881
3451
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
@@ -2887,6 +3457,14 @@ var ExcelPlugin = class {
|
|
|
2887
3457
|
getToolbarActions(instance) {
|
|
2888
3458
|
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2889
3459
|
const actions = [];
|
|
3460
|
+
actions.push({
|
|
3461
|
+
id: "thumbnails",
|
|
3462
|
+
icon: "thumbnails",
|
|
3463
|
+
label: "Sheet Thumbnails",
|
|
3464
|
+
type: "button",
|
|
3465
|
+
group: "navigation",
|
|
3466
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3467
|
+
});
|
|
2890
3468
|
if (totalSheets > 1) {
|
|
2891
3469
|
actions.push({
|
|
2892
3470
|
id: "page-nav",
|
|
@@ -2969,6 +3547,16 @@ var ExcelPlugin = class {
|
|
|
2969
3547
|
execute: () => {
|
|
2970
3548
|
instance.print?.();
|
|
2971
3549
|
}
|
|
3550
|
+
},
|
|
3551
|
+
{
|
|
3552
|
+
id: "open-window",
|
|
3553
|
+
icon: "open-window",
|
|
3554
|
+
label: "Open in Separate Full Window",
|
|
3555
|
+
type: "button",
|
|
3556
|
+
group: "actions",
|
|
3557
|
+
execute: () => {
|
|
3558
|
+
instance.openInSeparateWindow?.();
|
|
3559
|
+
}
|
|
2972
3560
|
}
|
|
2973
3561
|
);
|
|
2974
3562
|
return actions;
|
|
@@ -3134,6 +3722,63 @@ var ExcelPlugin = class {
|
|
|
3134
3722
|
},
|
|
3135
3723
|
getPageCount: () => sheetNames.length,
|
|
3136
3724
|
getCurrentPage: () => currentSheetIndex,
|
|
3725
|
+
getThumbnails: () => {
|
|
3726
|
+
return sheetNames.map((name, idx) => ({
|
|
3727
|
+
index: idx,
|
|
3728
|
+
label: name,
|
|
3729
|
+
render: async (canvas) => {
|
|
3730
|
+
canvas.width = 140;
|
|
3731
|
+
canvas.height = 100;
|
|
3732
|
+
const c = canvas.getContext("2d");
|
|
3733
|
+
if (!c) return;
|
|
3734
|
+
c.fillStyle = "#ffffff";
|
|
3735
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
3736
|
+
c.fillStyle = "#107c41";
|
|
3737
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
3738
|
+
c.fillStyle = "#ffffff";
|
|
3739
|
+
c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
3740
|
+
c.fillText(`\u{1F4CA} ${name.slice(0, 16)}`, 6, 11);
|
|
3741
|
+
const startY = 17;
|
|
3742
|
+
const rowH = 13;
|
|
3743
|
+
const colW = 30;
|
|
3744
|
+
const colHeaders = ["A", "B", "C", "D"];
|
|
3745
|
+
c.fillStyle = "#f1f5f9";
|
|
3746
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
3747
|
+
c.strokeStyle = "#cbd5e1";
|
|
3748
|
+
c.lineWidth = 0.8;
|
|
3749
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
3750
|
+
c.fillStyle = "#64748b";
|
|
3751
|
+
c.font = "bold 7px sans-serif";
|
|
3752
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3753
|
+
c.fillText(colHeaders[ci], 14 + ci * colW, startY + 9);
|
|
3754
|
+
}
|
|
3755
|
+
const ws = wb?.Sheets[name];
|
|
3756
|
+
for (let ri = 1; ri <= 5; ri++) {
|
|
3757
|
+
const y = startY + ri * rowH;
|
|
3758
|
+
if (y > canvas.height - 2) break;
|
|
3759
|
+
c.fillStyle = "#f8fafc";
|
|
3760
|
+
c.fillRect(0, y, 12, rowH);
|
|
3761
|
+
c.fillStyle = "#94a3b8";
|
|
3762
|
+
c.font = "6px sans-serif";
|
|
3763
|
+
c.fillText(String(ri), 3, y + 9);
|
|
3764
|
+
c.strokeStyle = "#e2e8f0";
|
|
3765
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
3766
|
+
c.fillStyle = "#334155";
|
|
3767
|
+
c.font = "6px sans-serif";
|
|
3768
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3769
|
+
const cellRef = `${colHeaders[ci]}${ri}`;
|
|
3770
|
+
const cellVal = ws?.[cellRef]?.w || ws?.[cellRef]?.v;
|
|
3771
|
+
if (cellVal !== void 0) {
|
|
3772
|
+
c.fillText(String(cellVal).slice(0, 6), 14 + ci * colW, y + 9);
|
|
3773
|
+
}
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3776
|
+
c.strokeStyle = "#cbd5e1";
|
|
3777
|
+
c.lineWidth = 1;
|
|
3778
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
3779
|
+
}
|
|
3780
|
+
}));
|
|
3781
|
+
},
|
|
3137
3782
|
download: () => {
|
|
3138
3783
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
3139
3784
|
const url = URL.createObjectURL(blob);
|
|
@@ -3166,7 +3811,39 @@ var CsvPlugin = class {
|
|
|
3166
3811
|
return ext === ".csv" || ext === ".tsv" || mime === "text/csv" || mime === "text/tab-separated-values";
|
|
3167
3812
|
}
|
|
3168
3813
|
getToolbarActions(instance) {
|
|
3169
|
-
|
|
3814
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3815
|
+
const actions = [];
|
|
3816
|
+
actions.push({
|
|
3817
|
+
id: "thumbnails",
|
|
3818
|
+
icon: "thumbnails",
|
|
3819
|
+
label: "Page Thumbnails",
|
|
3820
|
+
type: "button",
|
|
3821
|
+
group: "navigation",
|
|
3822
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3823
|
+
});
|
|
3824
|
+
if (totalPages > 1) {
|
|
3825
|
+
actions.push({
|
|
3826
|
+
id: "page-nav",
|
|
3827
|
+
icon: "",
|
|
3828
|
+
label: "Page Navigation",
|
|
3829
|
+
type: "page-nav",
|
|
3830
|
+
group: "navigation",
|
|
3831
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3832
|
+
max: totalPages,
|
|
3833
|
+
execute: (action, page) => {
|
|
3834
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3835
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
3836
|
+
if (action === "prev") {
|
|
3837
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3838
|
+
} else if (action === "next") {
|
|
3839
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
3840
|
+
} else if (typeof page === "number") {
|
|
3841
|
+
instance.goToPage?.(page);
|
|
3842
|
+
}
|
|
3843
|
+
}
|
|
3844
|
+
});
|
|
3845
|
+
}
|
|
3846
|
+
actions.push(
|
|
3170
3847
|
{
|
|
3171
3848
|
id: "zoom-out",
|
|
3172
3849
|
icon: "zoom-out",
|
|
@@ -3187,6 +3864,16 @@ var CsvPlugin = class {
|
|
|
3187
3864
|
instance.zoomIn?.();
|
|
3188
3865
|
}
|
|
3189
3866
|
},
|
|
3867
|
+
{
|
|
3868
|
+
id: "fit-page",
|
|
3869
|
+
icon: "fit-page",
|
|
3870
|
+
label: "Fit to View",
|
|
3871
|
+
type: "button",
|
|
3872
|
+
group: "zoom",
|
|
3873
|
+
execute: () => {
|
|
3874
|
+
instance.fitToPage?.();
|
|
3875
|
+
}
|
|
3876
|
+
},
|
|
3190
3877
|
{
|
|
3191
3878
|
id: "download",
|
|
3192
3879
|
icon: "download",
|
|
@@ -3204,10 +3891,21 @@ var CsvPlugin = class {
|
|
|
3204
3891
|
type: "button",
|
|
3205
3892
|
group: "actions",
|
|
3206
3893
|
execute: () => {
|
|
3207
|
-
instance.print?.();
|
|
3894
|
+
instance.print?.();
|
|
3895
|
+
}
|
|
3896
|
+
},
|
|
3897
|
+
{
|
|
3898
|
+
id: "open-window",
|
|
3899
|
+
icon: "open-window",
|
|
3900
|
+
label: "Open in Separate Full Window",
|
|
3901
|
+
type: "button",
|
|
3902
|
+
group: "actions",
|
|
3903
|
+
execute: () => {
|
|
3904
|
+
instance.openInSeparateWindow?.();
|
|
3208
3905
|
}
|
|
3209
3906
|
}
|
|
3210
|
-
|
|
3907
|
+
);
|
|
3908
|
+
return actions;
|
|
3211
3909
|
}
|
|
3212
3910
|
async render(ctx) {
|
|
3213
3911
|
const decoder = new TextDecoder("utf-8");
|
|
@@ -3219,33 +3917,62 @@ var CsvPlugin = class {
|
|
|
3219
3917
|
container.style.padding = "16px";
|
|
3220
3918
|
container.style.boxSizing = "border-box";
|
|
3221
3919
|
container.style.transformOrigin = "top left";
|
|
3920
|
+
const delimiter = ctx.metadata.extension === ".tsv" ? " " : ",";
|
|
3921
|
+
const allLines = text.split(/\r?\n/).filter((r) => r.trim().length > 0);
|
|
3922
|
+
const headerLine = allLines[0] || "";
|
|
3923
|
+
const headerCells = headerLine.split(delimiter);
|
|
3924
|
+
const dataLines = allLines.slice(1);
|
|
3925
|
+
const ROWS_PER_PAGE = 100;
|
|
3926
|
+
const totalPages = Math.max(1, Math.ceil(dataLines.length / ROWS_PER_PAGE));
|
|
3927
|
+
let currentPage = 1;
|
|
3222
3928
|
const table = document.createElement("table");
|
|
3223
3929
|
table.style.borderCollapse = "collapse";
|
|
3224
3930
|
table.style.width = "100%";
|
|
3225
|
-
table.style.fontFamily = "monospace
|
|
3931
|
+
table.style.fontFamily = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace';
|
|
3226
3932
|
table.style.fontSize = "13px";
|
|
3227
|
-
const
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
td.style.fontWeight = "bold";
|
|
3241
|
-
}
|
|
3242
|
-
tr.appendChild(td);
|
|
3933
|
+
const renderPage = (pageNum) => {
|
|
3934
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3935
|
+
table.innerHTML = "";
|
|
3936
|
+
const headerTr = document.createElement("tr");
|
|
3937
|
+
headerCells.forEach((cell) => {
|
|
3938
|
+
const th = document.createElement("th");
|
|
3939
|
+
th.textContent = cell.trim();
|
|
3940
|
+
th.style.border = "1px solid #d0d7de";
|
|
3941
|
+
th.style.padding = "8px 12px";
|
|
3942
|
+
th.style.backgroundColor = "#f6f8fa";
|
|
3943
|
+
th.style.fontWeight = "600";
|
|
3944
|
+
th.style.whiteSpace = "nowrap";
|
|
3945
|
+
headerTr.appendChild(th);
|
|
3243
3946
|
});
|
|
3244
|
-
table.appendChild(
|
|
3245
|
-
|
|
3947
|
+
table.appendChild(headerTr);
|
|
3948
|
+
const start = (currentPage - 1) * ROWS_PER_PAGE;
|
|
3949
|
+
const end = Math.min(dataLines.length, start + ROWS_PER_PAGE);
|
|
3950
|
+
const pageRows = dataLines.slice(start, end);
|
|
3951
|
+
pageRows.forEach((row, idx) => {
|
|
3952
|
+
const tr = document.createElement("tr");
|
|
3953
|
+
if (idx % 2 === 1) tr.style.backgroundColor = "#f8fafc";
|
|
3954
|
+
const cells = row.split(delimiter);
|
|
3955
|
+
cells.forEach((cell) => {
|
|
3956
|
+
const td = document.createElement("td");
|
|
3957
|
+
td.textContent = cell.trim();
|
|
3958
|
+
td.style.border = "1px solid #d0d7de";
|
|
3959
|
+
td.style.padding = "6px 12px";
|
|
3960
|
+
td.style.whiteSpace = "nowrap";
|
|
3961
|
+
tr.appendChild(td);
|
|
3962
|
+
});
|
|
3963
|
+
table.appendChild(tr);
|
|
3964
|
+
});
|
|
3965
|
+
container.scrollTop = 0;
|
|
3966
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3967
|
+
};
|
|
3968
|
+
renderPage(1);
|
|
3246
3969
|
container.appendChild(table);
|
|
3247
3970
|
ctx.container.appendChild(container);
|
|
3248
3971
|
let scale = 1;
|
|
3972
|
+
const applyScale = () => {
|
|
3973
|
+
container.style.transform = `scale(${scale})`;
|
|
3974
|
+
container.style.transformOrigin = "top left";
|
|
3975
|
+
};
|
|
3249
3976
|
const cleanup = () => {
|
|
3250
3977
|
container.remove();
|
|
3251
3978
|
ctx.container.innerHTML = "";
|
|
@@ -3253,22 +3980,86 @@ var CsvPlugin = class {
|
|
|
3253
3980
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3254
3981
|
return {
|
|
3255
3982
|
destroy: cleanup,
|
|
3983
|
+
getPageCount: () => totalPages,
|
|
3984
|
+
getCurrentPage: () => currentPage,
|
|
3985
|
+
goToPage: (page) => renderPage(page),
|
|
3986
|
+
getThumbnails: () => {
|
|
3987
|
+
const thumbnails = [];
|
|
3988
|
+
for (let i = 0; i < totalPages; i++) {
|
|
3989
|
+
const pageIdx = i;
|
|
3990
|
+
const startRow = pageIdx * ROWS_PER_PAGE + 1;
|
|
3991
|
+
const endRow = Math.min(dataLines.length, (pageIdx + 1) * ROWS_PER_PAGE);
|
|
3992
|
+
const label = totalPages === 1 ? "Table" : `Page ${pageIdx + 1} (${startRow}-${endRow})`;
|
|
3993
|
+
thumbnails.push({
|
|
3994
|
+
index: pageIdx,
|
|
3995
|
+
label,
|
|
3996
|
+
render: async (canvas) => {
|
|
3997
|
+
canvas.width = 140;
|
|
3998
|
+
canvas.height = 100;
|
|
3999
|
+
const c = canvas.getContext("2d");
|
|
4000
|
+
if (!c) return;
|
|
4001
|
+
c.fillStyle = "#ffffff";
|
|
4002
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4003
|
+
c.fillStyle = "#2563eb";
|
|
4004
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
4005
|
+
c.fillStyle = "#ffffff";
|
|
4006
|
+
c.font = "bold 8px sans-serif";
|
|
4007
|
+
c.fillText(`\u{1F4C8} ${label.slice(0, 18)}`, 6, 11);
|
|
4008
|
+
const startY = 17;
|
|
4009
|
+
const rowH = 13;
|
|
4010
|
+
const colW = 28;
|
|
4011
|
+
const cols = Math.min(4, headerCells.length || 4);
|
|
4012
|
+
c.fillStyle = "#f1f5f9";
|
|
4013
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
4014
|
+
c.strokeStyle = "#cbd5e1";
|
|
4015
|
+
c.lineWidth = 0.8;
|
|
4016
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
4017
|
+
c.fillStyle = "#64748b";
|
|
4018
|
+
c.font = "bold 7px sans-serif";
|
|
4019
|
+
for (let ci = 0; ci < cols; ci++) {
|
|
4020
|
+
const hName = headerCells[ci] || `Col ${ci + 1}`;
|
|
4021
|
+
c.fillText(hName.slice(0, 5), 8 + ci * colW, startY + 9);
|
|
4022
|
+
}
|
|
4023
|
+
const rowsToPreview = dataLines.slice(pageIdx * ROWS_PER_PAGE, pageIdx * ROWS_PER_PAGE + 5);
|
|
4024
|
+
for (let ri = 0; ri < rowsToPreview.length; ri++) {
|
|
4025
|
+
const y = startY + (ri + 1) * rowH;
|
|
4026
|
+
if (y > canvas.height - 2) break;
|
|
4027
|
+
c.strokeStyle = "#e2e8f0";
|
|
4028
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
4029
|
+
const cVals = rowsToPreview[ri].split(delimiter);
|
|
4030
|
+
c.fillStyle = "#334155";
|
|
4031
|
+
c.font = "6px sans-serif";
|
|
4032
|
+
for (let ci = 0; ci < cols; ci++) {
|
|
4033
|
+
const val = cVals[ci] || "";
|
|
4034
|
+
c.fillText(val.trim().slice(0, 6), 8 + ci * colW, y + 9);
|
|
4035
|
+
}
|
|
4036
|
+
}
|
|
4037
|
+
c.strokeStyle = "#cbd5e1";
|
|
4038
|
+
c.lineWidth = 1;
|
|
4039
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4040
|
+
}
|
|
4041
|
+
});
|
|
4042
|
+
}
|
|
4043
|
+
return thumbnails;
|
|
4044
|
+
},
|
|
3256
4045
|
zoomIn: () => {
|
|
3257
4046
|
scale += 0.1;
|
|
3258
|
-
|
|
4047
|
+
applyScale();
|
|
3259
4048
|
},
|
|
3260
4049
|
zoomOut: () => {
|
|
3261
4050
|
scale = Math.max(0.2, scale - 0.1);
|
|
3262
|
-
|
|
4051
|
+
applyScale();
|
|
3263
4052
|
},
|
|
3264
4053
|
getZoom: () => scale,
|
|
3265
4054
|
setZoom: (level) => {
|
|
3266
4055
|
scale = level;
|
|
3267
|
-
|
|
4056
|
+
applyScale();
|
|
3268
4057
|
},
|
|
3269
4058
|
fitToPage: () => {
|
|
3270
|
-
|
|
3271
|
-
|
|
4059
|
+
const availW = Math.max(280, (ctx.container.clientWidth || window.innerWidth) - 48);
|
|
4060
|
+
const tW = table.offsetWidth || 600;
|
|
4061
|
+
scale = Math.max(0.35, Math.min(1, availW / tW));
|
|
4062
|
+
applyScale();
|
|
3272
4063
|
},
|
|
3273
4064
|
download: () => {
|
|
3274
4065
|
const blob = new Blob([ctx.buffer], { type: "text/csv" });
|
|
@@ -3332,28 +4123,34 @@ var CodePlugin = class {
|
|
|
3332
4123
|
getToolbarActions(instance) {
|
|
3333
4124
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3334
4125
|
const actions = [];
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
4126
|
+
actions.push({
|
|
4127
|
+
id: "thumbnails",
|
|
4128
|
+
icon: "thumbnails",
|
|
4129
|
+
label: "Page Thumbnails",
|
|
4130
|
+
type: "button",
|
|
4131
|
+
group: "navigation",
|
|
4132
|
+
execute: () => instance.toggleThumbnails?.()
|
|
4133
|
+
});
|
|
4134
|
+
actions.push({
|
|
4135
|
+
id: "page-nav",
|
|
4136
|
+
icon: "",
|
|
4137
|
+
label: "Page Navigation",
|
|
4138
|
+
type: "page-nav",
|
|
4139
|
+
group: "navigation",
|
|
4140
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4141
|
+
max: totalPages,
|
|
4142
|
+
execute: (action, page) => {
|
|
4143
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4144
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4145
|
+
if (action === "prev") {
|
|
4146
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4147
|
+
} else if (action === "next") {
|
|
4148
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4149
|
+
} else if (typeof page === "number") {
|
|
4150
|
+
instance.goToPage?.(page);
|
|
3354
4151
|
}
|
|
3355
|
-
}
|
|
3356
|
-
}
|
|
4152
|
+
}
|
|
4153
|
+
});
|
|
3357
4154
|
actions.push(
|
|
3358
4155
|
{
|
|
3359
4156
|
id: "zoom-out",
|
|
@@ -3497,16 +4294,19 @@ var CodePlugin = class {
|
|
|
3497
4294
|
let fontSize = 13;
|
|
3498
4295
|
let rotation = 0;
|
|
3499
4296
|
let zoomLevel = 1;
|
|
4297
|
+
let isUserZoomed = false;
|
|
3500
4298
|
const pre = document.createElement("pre");
|
|
3501
4299
|
const code = document.createElement("code");
|
|
3502
4300
|
if (isTxt) {
|
|
4301
|
+
container.style.overflowX = "hidden";
|
|
4302
|
+
container.style.overflowY = "auto";
|
|
3503
4303
|
container.style.backgroundColor = "#f1f5f9";
|
|
3504
|
-
container.style.padding = "
|
|
4304
|
+
container.style.padding = "16px 8px";
|
|
3505
4305
|
container.style.boxSizing = "border-box";
|
|
3506
4306
|
container.style.display = "flex";
|
|
3507
4307
|
container.style.flexDirection = "column";
|
|
3508
4308
|
container.style.alignItems = "center";
|
|
3509
|
-
pre.style.margin = "0";
|
|
4309
|
+
pre.style.margin = "0 auto";
|
|
3510
4310
|
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3511
4311
|
pre.style.fontSize = "13px";
|
|
3512
4312
|
pre.style.color = "#1e293b";
|
|
@@ -3518,10 +4318,12 @@ var CodePlugin = class {
|
|
|
3518
4318
|
pre.style.minHeight = "1056px";
|
|
3519
4319
|
pre.style.padding = "72px 56px";
|
|
3520
4320
|
pre.style.boxSizing = "border-box";
|
|
3521
|
-
pre.style.boxShadow = "0 4px
|
|
4321
|
+
pre.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
3522
4322
|
pre.style.borderRadius = "4px";
|
|
3523
4323
|
pre.style.transformOrigin = "top center";
|
|
4324
|
+
pre.style.transition = "transform 0.15s ease";
|
|
3524
4325
|
} else {
|
|
4326
|
+
container.style.overflow = "auto";
|
|
3525
4327
|
container.style.backgroundColor = "#1e1e1e";
|
|
3526
4328
|
container.style.color = "#d4d4d4";
|
|
3527
4329
|
container.style.padding = "16px";
|
|
@@ -3553,42 +4355,9 @@ var CodePlugin = class {
|
|
|
3553
4355
|
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
3554
4356
|
pre.appendChild(code);
|
|
3555
4357
|
container.appendChild(pre);
|
|
3556
|
-
let indicator = null;
|
|
3557
|
-
if (totalPages > 1) {
|
|
3558
|
-
indicator = document.createElement("div");
|
|
3559
|
-
indicator.className = "fp-code-page-indicator";
|
|
3560
|
-
indicator.style.position = "sticky";
|
|
3561
|
-
indicator.style.bottom = "16px";
|
|
3562
|
-
if (isTxt) {
|
|
3563
|
-
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3564
|
-
indicator.style.color = "#334155";
|
|
3565
|
-
indicator.style.border = "1px solid #e2e8f0";
|
|
3566
|
-
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3567
|
-
} else {
|
|
3568
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3569
|
-
indicator.style.color = "#f8fafc";
|
|
3570
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3571
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3572
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
3573
|
-
}
|
|
3574
|
-
indicator.style.fontSize = "12px";
|
|
3575
|
-
indicator.style.fontWeight = "600";
|
|
3576
|
-
indicator.style.padding = "5px 14px";
|
|
3577
|
-
indicator.style.borderRadius = "20px";
|
|
3578
|
-
indicator.style.zIndex = "10";
|
|
3579
|
-
indicator.style.userSelect = "none";
|
|
3580
|
-
indicator.style.pointerEvents = "none";
|
|
3581
|
-
indicator.style.textAlign = "center";
|
|
3582
|
-
indicator.style.width = "fit-content";
|
|
3583
|
-
indicator.style.margin = "16px auto 0";
|
|
3584
|
-
container.appendChild(indicator);
|
|
3585
|
-
}
|
|
3586
4358
|
const showPage = (pageNum) => {
|
|
3587
4359
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3588
4360
|
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
3589
|
-
if (indicator) {
|
|
3590
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3591
|
-
}
|
|
3592
4361
|
container.scrollTop = 0;
|
|
3593
4362
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3594
4363
|
};
|
|
@@ -3596,36 +4365,90 @@ var CodePlugin = class {
|
|
|
3596
4365
|
showPage(1);
|
|
3597
4366
|
}
|
|
3598
4367
|
ctx.container.appendChild(container);
|
|
3599
|
-
const
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
ctx.container.innerHTML = "";
|
|
4368
|
+
const calculateTxtFit = () => {
|
|
4369
|
+
const availW = Math.max(280, container.clientWidth - 32);
|
|
4370
|
+
return Math.max(0.4, Math.min(3, availW / 816));
|
|
3603
4371
|
};
|
|
3604
|
-
ctx.signal.addEventListener("abort", cleanup);
|
|
3605
4372
|
const updateTransform = () => {
|
|
3606
4373
|
if (isTxt) {
|
|
3607
4374
|
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
4375
|
+
const scaledH = 1056 * zoomLevel;
|
|
4376
|
+
const extraH = Math.max(0, scaledH - 1056);
|
|
4377
|
+
pre.style.marginBottom = `${extraH + 32}px`;
|
|
3608
4378
|
} else {
|
|
3609
4379
|
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3610
4380
|
pre.style.fontSize = `${fontSize}px`;
|
|
3611
4381
|
}
|
|
3612
4382
|
};
|
|
4383
|
+
let resizeObserver = null;
|
|
4384
|
+
if (isTxt) {
|
|
4385
|
+
setTimeout(() => {
|
|
4386
|
+
zoomLevel = calculateTxtFit();
|
|
4387
|
+
updateTransform();
|
|
4388
|
+
}, 60);
|
|
4389
|
+
resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
4390
|
+
if (!isUserZoomed) {
|
|
4391
|
+
zoomLevel = calculateTxtFit();
|
|
4392
|
+
updateTransform();
|
|
4393
|
+
}
|
|
4394
|
+
}) : null;
|
|
4395
|
+
resizeObserver?.observe(container);
|
|
4396
|
+
}
|
|
4397
|
+
const cleanup = () => {
|
|
4398
|
+
resizeObserver?.disconnect();
|
|
4399
|
+
container.remove();
|
|
4400
|
+
ctx.container.innerHTML = "";
|
|
4401
|
+
};
|
|
4402
|
+
ctx.signal.addEventListener("abort", cleanup);
|
|
3613
4403
|
return {
|
|
3614
4404
|
destroy: cleanup,
|
|
3615
4405
|
getPageCount: () => totalPages,
|
|
3616
4406
|
getCurrentPage: () => currentPage,
|
|
3617
4407
|
goToPage: (page) => showPage(page),
|
|
4408
|
+
getThumbnails: () => {
|
|
4409
|
+
return rawPages.map((pageText, idx) => ({
|
|
4410
|
+
index: idx,
|
|
4411
|
+
label: `Page ${idx + 1}`,
|
|
4412
|
+
render: async (canvas) => {
|
|
4413
|
+
canvas.width = 140;
|
|
4414
|
+
canvas.height = 180;
|
|
4415
|
+
const c = canvas.getContext("2d");
|
|
4416
|
+
if (!c) return;
|
|
4417
|
+
c.fillStyle = "#ffffff";
|
|
4418
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4419
|
+
c.strokeStyle = "#cbd5e1";
|
|
4420
|
+
c.lineWidth = 1;
|
|
4421
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4422
|
+
c.fillStyle = "#64748b";
|
|
4423
|
+
const lines = (pageText || "").split("\n").slice(0, 24);
|
|
4424
|
+
const lineH = 6;
|
|
4425
|
+
const startY = 14;
|
|
4426
|
+
const startX = 12;
|
|
4427
|
+
const maxW = canvas.width - 24;
|
|
4428
|
+
c.font = "5px monospace";
|
|
4429
|
+
for (let li = 0; li < lines.length; li++) {
|
|
4430
|
+
const l = lines[li].trim();
|
|
4431
|
+
if (!l) continue;
|
|
4432
|
+
const y = startY + li * lineH;
|
|
4433
|
+
if (y > canvas.height - 12) break;
|
|
4434
|
+
c.fillText(l.slice(0, 30), startX, y, maxW);
|
|
4435
|
+
}
|
|
4436
|
+
}
|
|
4437
|
+
}));
|
|
4438
|
+
},
|
|
3618
4439
|
zoomIn: () => {
|
|
4440
|
+
isUserZoomed = true;
|
|
3619
4441
|
if (isTxt) {
|
|
3620
|
-
zoomLevel = Math.min(3, zoomLevel + 0.
|
|
4442
|
+
zoomLevel = Math.min(3.5, zoomLevel + 0.15);
|
|
3621
4443
|
} else {
|
|
3622
4444
|
fontSize = Math.min(32, fontSize + 2);
|
|
3623
4445
|
}
|
|
3624
4446
|
updateTransform();
|
|
3625
4447
|
},
|
|
3626
4448
|
zoomOut: () => {
|
|
4449
|
+
isUserZoomed = true;
|
|
3627
4450
|
if (isTxt) {
|
|
3628
|
-
zoomLevel = Math.max(0.1, zoomLevel - 0.
|
|
4451
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.15);
|
|
3629
4452
|
} else {
|
|
3630
4453
|
fontSize = Math.max(8, fontSize - 2);
|
|
3631
4454
|
}
|
|
@@ -3633,6 +4456,7 @@ var CodePlugin = class {
|
|
|
3633
4456
|
},
|
|
3634
4457
|
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
3635
4458
|
setZoom: (level) => {
|
|
4459
|
+
isUserZoomed = true;
|
|
3636
4460
|
if (isTxt) {
|
|
3637
4461
|
zoomLevel = level;
|
|
3638
4462
|
} else {
|
|
@@ -3641,9 +4465,10 @@ var CodePlugin = class {
|
|
|
3641
4465
|
updateTransform();
|
|
3642
4466
|
},
|
|
3643
4467
|
fitToPage: () => {
|
|
4468
|
+
isUserZoomed = false;
|
|
3644
4469
|
fontSize = 13;
|
|
3645
4470
|
rotation = 0;
|
|
3646
|
-
zoomLevel = isTxt ?
|
|
4471
|
+
zoomLevel = isTxt ? calculateTxtFit() : 1;
|
|
3647
4472
|
updateTransform();
|
|
3648
4473
|
},
|
|
3649
4474
|
rotateCW: () => {
|
|
@@ -4524,28 +5349,26 @@ var RtfPlugin = class {
|
|
|
4524
5349
|
getToolbarActions(instance) {
|
|
4525
5350
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4526
5351
|
const actions = [];
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
if (
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
instance.goToPage?.(page);
|
|
4545
|
-
}
|
|
5352
|
+
actions.push({
|
|
5353
|
+
id: "page-nav",
|
|
5354
|
+
icon: "",
|
|
5355
|
+
label: "Page Navigation",
|
|
5356
|
+
type: "page-nav",
|
|
5357
|
+
group: "navigation",
|
|
5358
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5359
|
+
max: totalPages,
|
|
5360
|
+
execute: (action, page) => {
|
|
5361
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5362
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5363
|
+
if (action === "prev") {
|
|
5364
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5365
|
+
} else if (action === "next") {
|
|
5366
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5367
|
+
} else if (typeof page === "number") {
|
|
5368
|
+
instance.goToPage?.(page);
|
|
4546
5369
|
}
|
|
4547
|
-
}
|
|
4548
|
-
}
|
|
5370
|
+
}
|
|
5371
|
+
});
|
|
4549
5372
|
actions.push(
|
|
4550
5373
|
{
|
|
4551
5374
|
id: "zoom-out",
|
|
@@ -4617,43 +5440,57 @@ var RtfPlugin = class {
|
|
|
4617
5440
|
async render(ctx) {
|
|
4618
5441
|
const wrapper = document.createElement("div");
|
|
4619
5442
|
wrapper.className = "fp-rtf-wrapper";
|
|
4620
|
-
wrapper.style.padding = "
|
|
4621
|
-
wrapper.style.
|
|
5443
|
+
wrapper.style.padding = "0";
|
|
5444
|
+
wrapper.style.width = "816px";
|
|
4622
5445
|
wrapper.style.margin = "0 auto";
|
|
4623
|
-
wrapper.style.
|
|
4624
|
-
wrapper.style.
|
|
4625
|
-
wrapper.style.
|
|
4626
|
-
wrapper.style.
|
|
5446
|
+
wrapper.style.boxSizing = "border-box";
|
|
5447
|
+
wrapper.style.display = "flex";
|
|
5448
|
+
wrapper.style.flexDirection = "column";
|
|
5449
|
+
wrapper.style.alignItems = "center";
|
|
5450
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4627
5451
|
wrapper.style.transformOrigin = "top center";
|
|
4628
|
-
wrapper.style.transition = "transform 0.
|
|
4629
|
-
ctx.container.style.
|
|
4630
|
-
ctx.container.style.
|
|
5452
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5453
|
+
ctx.container.style.overflowX = "hidden";
|
|
5454
|
+
ctx.container.style.overflowY = "auto";
|
|
5455
|
+
ctx.container.style.padding = "16px 8px";
|
|
4631
5456
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
4632
5457
|
ctx.container.appendChild(wrapper);
|
|
4633
5458
|
let scale = 1;
|
|
4634
5459
|
let rotation = 0;
|
|
4635
5460
|
let pageElements = [];
|
|
4636
|
-
let
|
|
5461
|
+
let isUserZoomed = false;
|
|
5462
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
4637
5463
|
const calculateFitScale = (mode = fitMode) => {
|
|
4638
5464
|
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4639
|
-
const elW =
|
|
4640
|
-
const singlePageH =
|
|
4641
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
4642
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
5465
|
+
const elW = 816;
|
|
5466
|
+
const singlePageH = activeEl?.offsetHeight || 1056;
|
|
5467
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
5468
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
4643
5469
|
const sW = availW / elW;
|
|
4644
5470
|
const sH = availH / singlePageH;
|
|
4645
5471
|
if (mode === "page") {
|
|
4646
|
-
return Math.max(0.
|
|
5472
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
4647
5473
|
}
|
|
4648
|
-
return Math.max(0.
|
|
5474
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
4649
5475
|
};
|
|
4650
5476
|
const applyTransform = () => {
|
|
4651
5477
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4652
5478
|
wrapper.style.transformOrigin = "top center";
|
|
5479
|
+
const activeEl = pageElements[currentPage - 1];
|
|
5480
|
+
const baseH = activeEl?.offsetHeight || 1056;
|
|
5481
|
+
const scaledH = baseH * scale;
|
|
5482
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
5483
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
4653
5484
|
};
|
|
5485
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
5486
|
+
if (!isUserZoomed) {
|
|
5487
|
+
scale = calculateFitScale(fitMode);
|
|
5488
|
+
applyTransform();
|
|
5489
|
+
}
|
|
5490
|
+
}) : null;
|
|
5491
|
+
resizeObserver?.observe(ctx.container);
|
|
4654
5492
|
setTimeout(() => {
|
|
4655
|
-
|
|
4656
|
-
scale = calculateFitScale("width");
|
|
5493
|
+
scale = calculateFitScale(fitMode);
|
|
4657
5494
|
applyTransform();
|
|
4658
5495
|
}, 60);
|
|
4659
5496
|
try {
|
|
@@ -4663,20 +5500,34 @@ var RtfPlugin = class {
|
|
|
4663
5500
|
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
4664
5501
|
const htmlElements = await doc.render();
|
|
4665
5502
|
const contentNodes = [];
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
5503
|
+
const extractBlocks = (nodes) => {
|
|
5504
|
+
for (const item of nodes) {
|
|
5505
|
+
if (!item || !(item instanceof HTMLElement)) continue;
|
|
5506
|
+
const tag = item.tagName.toLowerCase();
|
|
5507
|
+
const hasChildBlocks = Array.from(item.children).some((c) => {
|
|
5508
|
+
const ct = c.tagName.toLowerCase();
|
|
5509
|
+
return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
|
|
5510
|
+
});
|
|
5511
|
+
if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
|
|
5512
|
+
extractBlocks(Array.from(item.children));
|
|
5513
|
+
} else {
|
|
5514
|
+
if (tag === "p" || tag === "div") {
|
|
5515
|
+
item.style.display = "block";
|
|
5516
|
+
item.style.marginBottom = "12px";
|
|
5517
|
+
item.style.lineHeight = "1.6";
|
|
5518
|
+
}
|
|
5519
|
+
contentNodes.push(item);
|
|
5520
|
+
}
|
|
4671
5521
|
}
|
|
4672
|
-
}
|
|
5522
|
+
};
|
|
5523
|
+
extractBlocks(htmlElements);
|
|
4673
5524
|
wrapper.innerHTML = "";
|
|
4674
5525
|
contentNodes.forEach((node) => wrapper.appendChild(node));
|
|
4675
5526
|
const childHeights = contentNodes.map((c) => {
|
|
4676
5527
|
const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
|
|
4677
5528
|
const offH = c.offsetHeight || 0;
|
|
4678
5529
|
const textLen = c.textContent?.trim().length || 0;
|
|
4679
|
-
const estH = Math.max(
|
|
5530
|
+
const estH = Math.max(28, Math.ceil(textLen / 75) * 24 + 16);
|
|
4680
5531
|
return Math.max(rectH, offH, estH);
|
|
4681
5532
|
});
|
|
4682
5533
|
wrapper.innerHTML = "";
|
|
@@ -4693,6 +5544,7 @@ var RtfPlugin = class {
|
|
|
4693
5544
|
card.style.marginBottom = "24px";
|
|
4694
5545
|
card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4695
5546
|
card.style.lineHeight = "1.6";
|
|
5547
|
+
card.style.color = "#1e293b";
|
|
4696
5548
|
return card;
|
|
4697
5549
|
};
|
|
4698
5550
|
let curCard = createRtfCard();
|
|
@@ -4728,9 +5580,8 @@ var RtfPlugin = class {
|
|
|
4728
5580
|
pageCard.style.padding = "72px 56px";
|
|
4729
5581
|
pageCard.style.width = "816px";
|
|
4730
5582
|
pageCard.style.minHeight = "1056px";
|
|
4731
|
-
pageCard.style.maxWidth = "100%";
|
|
4732
5583
|
pageCard.style.boxSizing = "border-box";
|
|
4733
|
-
pageCard.style.fontFamily = "serif
|
|
5584
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4734
5585
|
pageCard.style.fontSize = "12pt";
|
|
4735
5586
|
pageCard.style.lineHeight = "1.6";
|
|
4736
5587
|
pageCard.style.color = "#1e293b";
|
|
@@ -4743,29 +5594,6 @@ var RtfPlugin = class {
|
|
|
4743
5594
|
}
|
|
4744
5595
|
const totalPages = Math.max(1, pageElements.length);
|
|
4745
5596
|
let currentPage = 1;
|
|
4746
|
-
let indicator = null;
|
|
4747
|
-
if (totalPages > 1) {
|
|
4748
|
-
indicator = document.createElement("div");
|
|
4749
|
-
indicator.className = "fp-rtf-page-indicator";
|
|
4750
|
-
indicator.style.position = "sticky";
|
|
4751
|
-
indicator.style.bottom = "16px";
|
|
4752
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4753
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
4754
|
-
indicator.style.color = "#f8fafc";
|
|
4755
|
-
indicator.style.fontSize = "12px";
|
|
4756
|
-
indicator.style.fontWeight = "600";
|
|
4757
|
-
indicator.style.padding = "5px 14px";
|
|
4758
|
-
indicator.style.borderRadius = "20px";
|
|
4759
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4760
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4761
|
-
indicator.style.zIndex = "10";
|
|
4762
|
-
indicator.style.userSelect = "none";
|
|
4763
|
-
indicator.style.pointerEvents = "none";
|
|
4764
|
-
indicator.style.textAlign = "center";
|
|
4765
|
-
indicator.style.width = "fit-content";
|
|
4766
|
-
indicator.style.margin = "16px auto 0";
|
|
4767
|
-
ctx.container.appendChild(indicator);
|
|
4768
|
-
}
|
|
4769
5597
|
const showPage = (pageNum) => {
|
|
4770
5598
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4771
5599
|
if (totalPages > 1) {
|
|
@@ -4773,9 +5601,6 @@ var RtfPlugin = class {
|
|
|
4773
5601
|
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4774
5602
|
});
|
|
4775
5603
|
}
|
|
4776
|
-
if (indicator) {
|
|
4777
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4778
|
-
}
|
|
4779
5604
|
ctx.container.scrollTop = 0;
|
|
4780
5605
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4781
5606
|
};
|
|
@@ -4783,7 +5608,7 @@ var RtfPlugin = class {
|
|
|
4783
5608
|
showPage(1);
|
|
4784
5609
|
}
|
|
4785
5610
|
const cleanup = () => {
|
|
4786
|
-
|
|
5611
|
+
resizeObserver?.disconnect();
|
|
4787
5612
|
wrapper.remove();
|
|
4788
5613
|
ctx.container.innerHTML = "";
|
|
4789
5614
|
};
|
|
@@ -4794,21 +5619,25 @@ var RtfPlugin = class {
|
|
|
4794
5619
|
getCurrentPage: () => currentPage,
|
|
4795
5620
|
goToPage: (page) => showPage(page),
|
|
4796
5621
|
zoomIn: () => {
|
|
5622
|
+
isUserZoomed = true;
|
|
4797
5623
|
scale += 0.15;
|
|
4798
5624
|
applyTransform();
|
|
4799
5625
|
},
|
|
4800
5626
|
zoomOut: () => {
|
|
5627
|
+
isUserZoomed = true;
|
|
4801
5628
|
scale = Math.max(0.2, scale - 0.15);
|
|
4802
5629
|
applyTransform();
|
|
4803
5630
|
},
|
|
4804
5631
|
getZoom: () => scale,
|
|
4805
5632
|
setZoom: (level) => {
|
|
5633
|
+
isUserZoomed = true;
|
|
4806
5634
|
scale = level;
|
|
4807
5635
|
applyTransform();
|
|
4808
5636
|
},
|
|
4809
5637
|
fitToPage: () => {
|
|
4810
|
-
|
|
4811
|
-
|
|
5638
|
+
isUserZoomed = false;
|
|
5639
|
+
fitMode = "width";
|
|
5640
|
+
scale = calculateFitScale("width");
|
|
4812
5641
|
rotation = 0;
|
|
4813
5642
|
applyTransform();
|
|
4814
5643
|
},
|
|
@@ -4996,40 +5825,36 @@ var OpenDocumentPlugin = class {
|
|
|
4996
5825
|
const isPresentation = instance.isPresentation;
|
|
4997
5826
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4998
5827
|
const actions = [];
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
max
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
if (
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
instance.goToPage?.(page);
|
|
5027
|
-
} else if (typeof action === "number") {
|
|
5028
|
-
instance.goToPage?.(action);
|
|
5029
|
-
}
|
|
5828
|
+
actions.push({
|
|
5829
|
+
id: "thumbnails",
|
|
5830
|
+
icon: "thumbnails",
|
|
5831
|
+
label: isPresentation ? "Slide Thumbnails" : "Page Thumbnails",
|
|
5832
|
+
type: "button",
|
|
5833
|
+
group: "navigation",
|
|
5834
|
+
execute: () => instance.toggleThumbnails?.()
|
|
5835
|
+
});
|
|
5836
|
+
actions.push({
|
|
5837
|
+
id: "page-nav",
|
|
5838
|
+
icon: "",
|
|
5839
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
5840
|
+
type: "page-nav",
|
|
5841
|
+
group: "navigation",
|
|
5842
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5843
|
+
max: totalPages,
|
|
5844
|
+
execute: (action, page) => {
|
|
5845
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5846
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5847
|
+
if (action === "prev") {
|
|
5848
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5849
|
+
} else if (action === "next") {
|
|
5850
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5851
|
+
} else if (typeof page === "number") {
|
|
5852
|
+
instance.goToPage?.(page);
|
|
5853
|
+
} else if (typeof action === "number") {
|
|
5854
|
+
instance.goToPage?.(action);
|
|
5030
5855
|
}
|
|
5031
|
-
}
|
|
5032
|
-
}
|
|
5856
|
+
}
|
|
5857
|
+
});
|
|
5033
5858
|
actions.push(
|
|
5034
5859
|
{
|
|
5035
5860
|
id: "zoom-out",
|
|
@@ -5120,49 +5945,65 @@ var OpenDocumentPlugin = class {
|
|
|
5120
5945
|
container.className = "fp-odf-container";
|
|
5121
5946
|
container.style.width = "100%";
|
|
5122
5947
|
container.style.height = "100%";
|
|
5123
|
-
container.style.
|
|
5124
|
-
container.style.
|
|
5948
|
+
container.style.overflowX = "hidden";
|
|
5949
|
+
container.style.overflowY = "auto";
|
|
5950
|
+
container.style.padding = "16px 8px";
|
|
5125
5951
|
container.style.backgroundColor = "#f1f5f9";
|
|
5126
5952
|
const wrapper = document.createElement("div");
|
|
5127
5953
|
wrapper.className = "fp-odf-wrapper";
|
|
5128
5954
|
wrapper.style.margin = "0 auto";
|
|
5955
|
+
wrapper.style.width = isPresentation ? "960px" : "816px";
|
|
5956
|
+
wrapper.style.boxSizing = "border-box";
|
|
5129
5957
|
wrapper.style.backgroundColor = "#ffffff";
|
|
5130
5958
|
wrapper.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
5131
5959
|
wrapper.style.borderRadius = "4px";
|
|
5132
5960
|
wrapper.style.transformOrigin = "top center";
|
|
5133
|
-
wrapper.style.transition = "transform 0.
|
|
5961
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5134
5962
|
container.appendChild(wrapper);
|
|
5135
5963
|
ctx.container.appendChild(container);
|
|
5136
5964
|
let scale = 1;
|
|
5137
5965
|
let rotation = 0;
|
|
5138
|
-
let
|
|
5966
|
+
let isUserZoomed = false;
|
|
5967
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
5968
|
+
let currentPage = 1;
|
|
5969
|
+
let totalPages = 1;
|
|
5970
|
+
let slides = [];
|
|
5139
5971
|
const calculateFitScale = (mode = fitMode) => {
|
|
5140
|
-
const
|
|
5141
|
-
const
|
|
5142
|
-
const
|
|
5143
|
-
const
|
|
5972
|
+
const activeSlide = slides[currentPage - 1];
|
|
5973
|
+
const elW = isPresentation ? 960 : 816;
|
|
5974
|
+
const singlePageH = Math.min(activeSlide?.offsetHeight || wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
5975
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
5976
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5144
5977
|
const sW = availW / elW;
|
|
5145
5978
|
const sH = availH / (isPresentation ? 540 : singlePageH);
|
|
5146
5979
|
if (isPresentation) {
|
|
5147
|
-
return Math.min(
|
|
5980
|
+
return Math.min(2.5, Math.min(sW, sH));
|
|
5148
5981
|
}
|
|
5149
5982
|
if (mode === "page") {
|
|
5150
|
-
return Math.max(0.
|
|
5983
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5151
5984
|
}
|
|
5152
|
-
return Math.max(0.
|
|
5985
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5153
5986
|
};
|
|
5154
5987
|
const applyTransform = () => {
|
|
5155
5988
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5156
5989
|
wrapper.style.transformOrigin = "top center";
|
|
5990
|
+
const activeSlide = slides[currentPage - 1];
|
|
5991
|
+
const baseH = activeSlide?.offsetHeight || wrapper.offsetHeight || 1056;
|
|
5992
|
+
const scaledH = baseH * scale;
|
|
5993
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
5994
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
5157
5995
|
};
|
|
5996
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
5997
|
+
if (!isUserZoomed) {
|
|
5998
|
+
scale = calculateFitScale(fitMode);
|
|
5999
|
+
applyTransform();
|
|
6000
|
+
}
|
|
6001
|
+
}) : null;
|
|
6002
|
+
resizeObserver?.observe(ctx.container);
|
|
5158
6003
|
setTimeout(() => {
|
|
5159
|
-
|
|
5160
|
-
scale = calculateFitScale("width");
|
|
6004
|
+
scale = calculateFitScale(fitMode);
|
|
5161
6005
|
applyTransform();
|
|
5162
6006
|
}, 60);
|
|
5163
|
-
let currentPage = 1;
|
|
5164
|
-
let totalPages = 1;
|
|
5165
|
-
let slides = [];
|
|
5166
6007
|
if (isPresentation) {
|
|
5167
6008
|
wrapper.style.maxWidth = "960px";
|
|
5168
6009
|
wrapper.style.aspectRatio = "16 / 9";
|
|
@@ -5263,24 +6104,9 @@ var OpenDocumentPlugin = class {
|
|
|
5263
6104
|
wrapper.appendChild(page);
|
|
5264
6105
|
slides.push(page);
|
|
5265
6106
|
});
|
|
5266
|
-
const pageIndicator = document.createElement("div");
|
|
5267
|
-
pageIndicator.className = "fp-odt-page-indicator";
|
|
5268
|
-
pageIndicator.style.position = "sticky";
|
|
5269
|
-
pageIndicator.style.bottom = "16px";
|
|
5270
|
-
pageIndicator.style.left = "50%";
|
|
5271
|
-
pageIndicator.style.transform = "translateX(-50%)";
|
|
5272
|
-
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
5273
|
-
pageIndicator.style.color = "#fff";
|
|
5274
|
-
pageIndicator.style.padding = "6px 12px";
|
|
5275
|
-
pageIndicator.style.borderRadius = "16px";
|
|
5276
|
-
pageIndicator.style.fontSize = "12px";
|
|
5277
|
-
pageIndicator.style.zIndex = "100";
|
|
5278
|
-
pageIndicator.style.display = "inline-block";
|
|
5279
|
-
pageIndicator.style.width = "fit-content";
|
|
5280
|
-
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
5281
|
-
container.appendChild(pageIndicator);
|
|
5282
6107
|
}
|
|
5283
6108
|
const cleanup = () => {
|
|
6109
|
+
resizeObserver?.disconnect();
|
|
5284
6110
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
5285
6111
|
container.remove();
|
|
5286
6112
|
ctx.container.innerHTML = "";
|
|
@@ -5292,10 +6118,6 @@ var OpenDocumentPlugin = class {
|
|
|
5292
6118
|
slides.forEach((s, idx) => {
|
|
5293
6119
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
5294
6120
|
});
|
|
5295
|
-
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
5296
|
-
if (indicator) {
|
|
5297
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5298
|
-
}
|
|
5299
6121
|
container.scrollTop = 0;
|
|
5300
6122
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5301
6123
|
};
|
|
@@ -5303,21 +6125,25 @@ var OpenDocumentPlugin = class {
|
|
|
5303
6125
|
destroy: cleanup,
|
|
5304
6126
|
isPresentation,
|
|
5305
6127
|
zoomIn: () => {
|
|
6128
|
+
isUserZoomed = true;
|
|
5306
6129
|
scale += 0.15;
|
|
5307
6130
|
applyTransform();
|
|
5308
6131
|
},
|
|
5309
6132
|
zoomOut: () => {
|
|
6133
|
+
isUserZoomed = true;
|
|
5310
6134
|
scale = Math.max(0.2, scale - 0.15);
|
|
5311
6135
|
applyTransform();
|
|
5312
6136
|
},
|
|
5313
6137
|
getZoom: () => scale,
|
|
5314
6138
|
setZoom: (level) => {
|
|
6139
|
+
isUserZoomed = true;
|
|
5315
6140
|
scale = level;
|
|
5316
6141
|
applyTransform();
|
|
5317
6142
|
},
|
|
5318
6143
|
fitToPage: () => {
|
|
5319
|
-
|
|
5320
|
-
|
|
6144
|
+
isUserZoomed = false;
|
|
6145
|
+
fitMode = "width";
|
|
6146
|
+
scale = calculateFitScale("width");
|
|
5321
6147
|
rotation = 0;
|
|
5322
6148
|
applyTransform();
|
|
5323
6149
|
},
|
|
@@ -5333,23 +6159,45 @@ var OpenDocumentPlugin = class {
|
|
|
5333
6159
|
getPageCount: () => totalPages,
|
|
5334
6160
|
getCurrentPage: () => currentPage,
|
|
5335
6161
|
getThumbnails: async () => {
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
canvas
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
6162
|
+
const count = totalPages || slides.length || 1;
|
|
6163
|
+
const items = [];
|
|
6164
|
+
for (let idx = 0; idx < count; idx++) {
|
|
6165
|
+
const itemIdx = idx;
|
|
6166
|
+
items.push({
|
|
6167
|
+
index: itemIdx,
|
|
6168
|
+
label: isPresentation ? `Slide ${itemIdx + 1}` : `Page ${itemIdx + 1}`,
|
|
6169
|
+
render: async (canvas) => {
|
|
6170
|
+
const ctx2d = canvas.getContext("2d");
|
|
6171
|
+
if (!ctx2d) return;
|
|
6172
|
+
if (isPresentation) {
|
|
6173
|
+
canvas.width = 160;
|
|
6174
|
+
canvas.height = 90;
|
|
6175
|
+
ctx2d.fillStyle = "#f8fafc";
|
|
6176
|
+
ctx2d.fillRect(0, 0, 160, 90);
|
|
6177
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6178
|
+
ctx2d.lineWidth = 1;
|
|
6179
|
+
ctx2d.strokeRect(0.5, 0.5, 159, 89);
|
|
6180
|
+
ctx2d.fillStyle = "#334155";
|
|
6181
|
+
ctx2d.font = "bold 11px sans-serif";
|
|
6182
|
+
ctx2d.textAlign = "center";
|
|
6183
|
+
ctx2d.fillText(`Slide ${itemIdx + 1}`, 80, 50);
|
|
6184
|
+
} else {
|
|
6185
|
+
canvas.width = 140;
|
|
6186
|
+
canvas.height = 180;
|
|
6187
|
+
ctx2d.fillStyle = "#ffffff";
|
|
6188
|
+
ctx2d.fillRect(0, 0, 140, 180);
|
|
6189
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6190
|
+
ctx2d.lineWidth = 1;
|
|
6191
|
+
ctx2d.strokeRect(0.5, 0.5, 139, 179);
|
|
6192
|
+
ctx2d.fillStyle = "#64748b";
|
|
6193
|
+
ctx2d.font = "bold 10px sans-serif";
|
|
6194
|
+
ctx2d.textAlign = "center";
|
|
6195
|
+
ctx2d.fillText(`Page ${itemIdx + 1}`, 70, 90);
|
|
6196
|
+
}
|
|
6197
|
+
}
|
|
6198
|
+
});
|
|
6199
|
+
}
|
|
6200
|
+
return items;
|
|
5353
6201
|
},
|
|
5354
6202
|
download: () => {
|
|
5355
6203
|
const mimeType = this.mimeTypes.find((m) => m.includes(ext.replace(".", ""))) || "application/octet-stream";
|
|
@@ -5454,23 +6302,24 @@ var OpenDocumentPlugin = class {
|
|
|
5454
6302
|
case "h": {
|
|
5455
6303
|
const level = Math.min(6, Math.max(1, Number(node.getAttribute("text:outline-level") || 1)));
|
|
5456
6304
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5457
|
-
html += `<h${level} style="${style}; font-family:
|
|
6305
|
+
html += `<h${level} style="${style}; margin: 18px 0 8px; color: #1e3a8a; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${node.textContent || ""}</h${level}>`;
|
|
5458
6306
|
break;
|
|
5459
6307
|
}
|
|
5460
6308
|
case "p": {
|
|
5461
6309
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5462
6310
|
const inner = this.renderSpans(node, styles, images);
|
|
5463
|
-
|
|
6311
|
+
const isInsideLi = node.parentElement?.localName === "list-item" || node.parentElement?.tagName?.toLowerCase() === "list-item";
|
|
6312
|
+
html += `<p style="${style}; line-height: 1.5; margin: ${isInsideLi ? "0" : "8px 0 12px"}; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${inner}</p>`;
|
|
5464
6313
|
break;
|
|
5465
6314
|
}
|
|
5466
6315
|
case "list": {
|
|
5467
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
6316
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
5468
6317
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5469
6318
|
html += "</ul>";
|
|
5470
6319
|
break;
|
|
5471
6320
|
}
|
|
5472
6321
|
case "list-item": {
|
|
5473
|
-
html +=
|
|
6322
|
+
html += '<li style="margin: 4px 0; font-size: 11pt; line-height: 1.5; color: #1e293b;">';
|
|
5474
6323
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5475
6324
|
html += "</li>";
|
|
5476
6325
|
break;
|
|
@@ -5596,28 +6445,26 @@ var DocPlugin = class {
|
|
|
5596
6445
|
getToolbarActions(instance) {
|
|
5597
6446
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5598
6447
|
const actions = [];
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
if (
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
instance.goToPage?.(page);
|
|
5617
|
-
}
|
|
6448
|
+
actions.push({
|
|
6449
|
+
id: "page-nav",
|
|
6450
|
+
icon: "",
|
|
6451
|
+
label: "Page Navigation",
|
|
6452
|
+
type: "page-nav",
|
|
6453
|
+
group: "navigation",
|
|
6454
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
6455
|
+
max: totalPages,
|
|
6456
|
+
execute: (action, page) => {
|
|
6457
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
6458
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
6459
|
+
if (action === "prev") {
|
|
6460
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
6461
|
+
} else if (action === "next") {
|
|
6462
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
6463
|
+
} else if (typeof page === "number") {
|
|
6464
|
+
instance.goToPage?.(page);
|
|
5618
6465
|
}
|
|
5619
|
-
}
|
|
5620
|
-
}
|
|
6466
|
+
}
|
|
6467
|
+
});
|
|
5621
6468
|
actions.push(
|
|
5622
6469
|
{
|
|
5623
6470
|
id: "zoom-out",
|
|
@@ -5691,8 +6538,9 @@ var DocPlugin = class {
|
|
|
5691
6538
|
container.className = "fp-doc-container";
|
|
5692
6539
|
container.style.width = "100%";
|
|
5693
6540
|
container.style.height = "100%";
|
|
5694
|
-
container.style.
|
|
5695
|
-
container.style.
|
|
6541
|
+
container.style.overflowX = "hidden";
|
|
6542
|
+
container.style.overflowY = "auto";
|
|
6543
|
+
container.style.padding = "16px 8px";
|
|
5696
6544
|
container.style.backgroundColor = "#f1f5f9";
|
|
5697
6545
|
container.style.display = "flex";
|
|
5698
6546
|
container.style.justifyContent = "center";
|
|
@@ -5701,8 +6549,17 @@ var DocPlugin = class {
|
|
|
5701
6549
|
let scale = 1;
|
|
5702
6550
|
let extractedRawText = "";
|
|
5703
6551
|
let isFallback = false;
|
|
6552
|
+
let chartSvg = "";
|
|
5704
6553
|
try {
|
|
5705
6554
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
6555
|
+
try {
|
|
6556
|
+
const pkg = cfbf.readStream("package_stream");
|
|
6557
|
+
if (pkg && pkg.length > 100) {
|
|
6558
|
+
chartSvg = this.parseOdfChartToSvg(pkg);
|
|
6559
|
+
}
|
|
6560
|
+
} catch (chartErr) {
|
|
6561
|
+
console.warn("[DocPlugin] Chart stream parsing info:", chartErr);
|
|
6562
|
+
}
|
|
5706
6563
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
5707
6564
|
if (!wordDocStream || wordDocStream.length < 512) {
|
|
5708
6565
|
throw new Error("WordDocument stream not found or invalid in CFBF archive");
|
|
@@ -5720,7 +6577,7 @@ var DocPlugin = class {
|
|
|
5720
6577
|
extractedRawText = fallback;
|
|
5721
6578
|
isFallback = true;
|
|
5722
6579
|
}
|
|
5723
|
-
const rawPages = this.splitIntoPages(extractedRawText);
|
|
6580
|
+
const rawPages = this.splitIntoPages(extractedRawText, chartSvg);
|
|
5724
6581
|
const totalPages = Math.max(1, rawPages.length);
|
|
5725
6582
|
let currentPage = 1;
|
|
5726
6583
|
const pageCards = [];
|
|
@@ -5728,16 +6585,15 @@ var DocPlugin = class {
|
|
|
5728
6585
|
const pageCard = document.createElement("div");
|
|
5729
6586
|
pageCard.className = "fp-doc-page-card";
|
|
5730
6587
|
pageCard.style.width = "816px";
|
|
5731
|
-
pageCard.style.
|
|
6588
|
+
pageCard.style.minHeight = "1056px";
|
|
5732
6589
|
pageCard.style.backgroundColor = "#ffffff";
|
|
5733
|
-
pageCard.style.boxShadow = "0
|
|
6590
|
+
pageCard.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
5734
6591
|
pageCard.style.borderRadius = "4px";
|
|
5735
|
-
pageCard.style.padding = "
|
|
6592
|
+
pageCard.style.padding = "72px 56px";
|
|
5736
6593
|
pageCard.style.boxSizing = "border-box";
|
|
5737
|
-
pageCard.style.overflow = "hidden";
|
|
5738
6594
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5739
6595
|
pageCard.style.transformOrigin = "top center";
|
|
5740
|
-
pageCard.style.transition = "transform 0.
|
|
6596
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
5741
6597
|
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5742
6598
|
pageCard.style.color = "#1e293b";
|
|
5743
6599
|
if (isFallback && i === 0) {
|
|
@@ -5754,34 +6610,15 @@ var DocPlugin = class {
|
|
|
5754
6610
|
container.appendChild(pageCard);
|
|
5755
6611
|
pageCards.push(pageCard);
|
|
5756
6612
|
}
|
|
5757
|
-
let indicator = null;
|
|
5758
|
-
if (totalPages > 1) {
|
|
5759
|
-
indicator = document.createElement("div");
|
|
5760
|
-
indicator.className = "fp-doc-page-indicator";
|
|
5761
|
-
indicator.style.position = "fixed";
|
|
5762
|
-
indicator.style.bottom = "16px";
|
|
5763
|
-
indicator.style.left = "50%";
|
|
5764
|
-
indicator.style.transform = "translateX(-50%)";
|
|
5765
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
5766
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
5767
|
-
indicator.style.color = "#f8fafc";
|
|
5768
|
-
indicator.style.fontSize = "12px";
|
|
5769
|
-
indicator.style.fontWeight = "600";
|
|
5770
|
-
indicator.style.padding = "5px 14px";
|
|
5771
|
-
indicator.style.borderRadius = "20px";
|
|
5772
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
5773
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
5774
|
-
indicator.style.zIndex = "10";
|
|
5775
|
-
indicator.style.userSelect = "none";
|
|
5776
|
-
indicator.style.pointerEvents = "none";
|
|
5777
|
-
indicator.style.textAlign = "center";
|
|
5778
|
-
container.appendChild(indicator);
|
|
5779
|
-
}
|
|
5780
6613
|
let rotation = 0;
|
|
5781
6614
|
const applyTransform = () => {
|
|
5782
6615
|
const activeCard = pageCards[currentPage - 1];
|
|
5783
6616
|
if (activeCard) {
|
|
5784
6617
|
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
6618
|
+
const baseH = activeCard.offsetHeight || 1056;
|
|
6619
|
+
const scaledH = baseH * scale;
|
|
6620
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6621
|
+
activeCard.style.marginBottom = `${extraH + 32}px`;
|
|
5785
6622
|
}
|
|
5786
6623
|
};
|
|
5787
6624
|
const showPage = (pageNum) => {
|
|
@@ -5794,35 +6631,39 @@ var DocPlugin = class {
|
|
|
5794
6631
|
card.style.display = "none";
|
|
5795
6632
|
}
|
|
5796
6633
|
});
|
|
5797
|
-
if (indicator) {
|
|
5798
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5799
|
-
}
|
|
5800
6634
|
container.scrollTop = 0;
|
|
5801
6635
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5802
6636
|
};
|
|
5803
6637
|
if (totalPages > 1) {
|
|
5804
6638
|
showPage(1);
|
|
5805
6639
|
}
|
|
5806
|
-
let fitMode = "width";
|
|
6640
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6641
|
+
let isUserZoomed = false;
|
|
5807
6642
|
const calculateFitScale = (mode = fitMode) => {
|
|
5808
6643
|
const elW = 816;
|
|
5809
6644
|
const elH = 1056;
|
|
5810
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
5811
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
6645
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6646
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5812
6647
|
const sW = availW / elW;
|
|
5813
6648
|
const sH = availH / elH;
|
|
5814
6649
|
if (mode === "page") {
|
|
5815
|
-
return Math.max(0.
|
|
6650
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5816
6651
|
}
|
|
5817
|
-
return Math.max(0.
|
|
6652
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5818
6653
|
};
|
|
6654
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6655
|
+
if (!isUserZoomed) {
|
|
6656
|
+
scale = calculateFitScale(fitMode);
|
|
6657
|
+
applyTransform();
|
|
6658
|
+
}
|
|
6659
|
+
}) : null;
|
|
6660
|
+
resizeObserver?.observe(ctx.container);
|
|
5819
6661
|
setTimeout(() => {
|
|
5820
|
-
|
|
5821
|
-
scale = calculateFitScale("width");
|
|
6662
|
+
scale = calculateFitScale(fitMode);
|
|
5822
6663
|
applyTransform();
|
|
5823
6664
|
}, 60);
|
|
5824
6665
|
const cleanup = () => {
|
|
5825
|
-
|
|
6666
|
+
resizeObserver?.disconnect();
|
|
5826
6667
|
container.remove();
|
|
5827
6668
|
ctx.container.innerHTML = "";
|
|
5828
6669
|
};
|
|
@@ -5833,21 +6674,25 @@ var DocPlugin = class {
|
|
|
5833
6674
|
getCurrentPage: () => currentPage,
|
|
5834
6675
|
goToPage: (page) => showPage(page),
|
|
5835
6676
|
zoomIn: () => {
|
|
6677
|
+
isUserZoomed = true;
|
|
5836
6678
|
scale += 0.15;
|
|
5837
6679
|
applyTransform();
|
|
5838
6680
|
},
|
|
5839
6681
|
zoomOut: () => {
|
|
6682
|
+
isUserZoomed = true;
|
|
5840
6683
|
scale = Math.max(0.2, scale - 0.15);
|
|
5841
6684
|
applyTransform();
|
|
5842
6685
|
},
|
|
5843
6686
|
getZoom: () => scale,
|
|
5844
6687
|
setZoom: (level) => {
|
|
6688
|
+
isUserZoomed = true;
|
|
5845
6689
|
scale = level;
|
|
5846
6690
|
applyTransform();
|
|
5847
6691
|
},
|
|
5848
6692
|
fitToPage: () => {
|
|
5849
|
-
|
|
5850
|
-
|
|
6693
|
+
isUserZoomed = false;
|
|
6694
|
+
fitMode = "width";
|
|
6695
|
+
scale = calculateFitScale("width");
|
|
5851
6696
|
rotation = 0;
|
|
5852
6697
|
applyTransform();
|
|
5853
6698
|
},
|
|
@@ -5962,7 +6807,7 @@ var DocPlugin = class {
|
|
|
5962
6807
|
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
5963
6808
|
const trimmed = run.trim();
|
|
5964
6809
|
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
5965
|
-
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)) {
|
|
6810
|
+
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)) {
|
|
5966
6811
|
seen.add(trimmed);
|
|
5967
6812
|
candidateLines.push(trimmed);
|
|
5968
6813
|
}
|
|
@@ -5973,9 +6818,114 @@ var DocPlugin = class {
|
|
|
5973
6818
|
heuristicTextExtraction(buffer) {
|
|
5974
6819
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
5975
6820
|
}
|
|
5976
|
-
|
|
6821
|
+
/**
|
|
6822
|
+
* Parses an embedded OpenDocument Chart package into a vector SVG bar/column chart
|
|
6823
|
+
*/
|
|
6824
|
+
parseOdfChartToSvg(zipBytes) {
|
|
6825
|
+
try {
|
|
6826
|
+
const unzipped = fflate__namespace.unzipSync(zipBytes);
|
|
6827
|
+
const contentXml = unzipped["content.xml"] ? new TextDecoder("utf-8").decode(unzipped["content.xml"]) : "";
|
|
6828
|
+
if (!contentXml) return "";
|
|
6829
|
+
const rowsMatch = contentXml.match(/<table:table-row[\s\S]*?<\/table:table-row>/g) || [];
|
|
6830
|
+
if (rowsMatch.length < 2) return "";
|
|
6831
|
+
const headers = [];
|
|
6832
|
+
const firstRow = rowsMatch[0];
|
|
6833
|
+
const headerCells = firstRow ? firstRow.match(/<text:p>([^<]+)<\/text:p>/g) || [] : [];
|
|
6834
|
+
for (const h2 of headerCells) {
|
|
6835
|
+
headers.push(h2.replace(/<\/?text:p>/g, "").trim());
|
|
6836
|
+
}
|
|
6837
|
+
const categories = [];
|
|
6838
|
+
const seriesValues = headers.map(() => []);
|
|
6839
|
+
for (let r = 1; r < rowsMatch.length; r++) {
|
|
6840
|
+
const rowStr = rowsMatch[r];
|
|
6841
|
+
if (!rowStr) continue;
|
|
6842
|
+
const cells = rowStr.match(/<table:table-cell[\s\S]*?<\/table:table-cell>/g) || [];
|
|
6843
|
+
if (cells.length > 0 && cells[0]) {
|
|
6844
|
+
const catMatch = cells[0].match(/<text:p>([^<]+)<\/text:p>/);
|
|
6845
|
+
categories.push(catMatch ? catMatch[1] : "Row " + r);
|
|
6846
|
+
for (let c = 1; c < cells.length && c - 1 < headers.length; c++) {
|
|
6847
|
+
const cellStr = cells[c];
|
|
6848
|
+
if (!cellStr) continue;
|
|
6849
|
+
const valMatch = cellStr.match(/office:value="([0-9.]+)"/) || cellStr.match(/<text:p>([0-9.]+)<\/text:p>/);
|
|
6850
|
+
const series = seriesValues[c - 1];
|
|
6851
|
+
if (series) {
|
|
6852
|
+
series.push(valMatch ? parseFloat(valMatch[1]) : 0);
|
|
6853
|
+
}
|
|
6854
|
+
}
|
|
6855
|
+
}
|
|
6856
|
+
}
|
|
6857
|
+
const colors = ["#004586", "#ff420e", "#ffd320", "#579d1c", "#7e0021"];
|
|
6858
|
+
const colorMatches = contentXml.matchAll(/draw:fill-color="(#[0-9a-fA-F]{6})"/g);
|
|
6859
|
+
let cIdx = 0;
|
|
6860
|
+
for (const cm of colorMatches) {
|
|
6861
|
+
if (cIdx < colors.length) colors[cIdx] = cm[1];
|
|
6862
|
+
cIdx++;
|
|
6863
|
+
}
|
|
6864
|
+
let maxVal = 10;
|
|
6865
|
+
for (const s of seriesValues) {
|
|
6866
|
+
for (const v of s) {
|
|
6867
|
+
if (v > maxVal) maxVal = v;
|
|
6868
|
+
}
|
|
6869
|
+
}
|
|
6870
|
+
maxVal = Math.ceil(maxVal * 1.15);
|
|
6871
|
+
const width = 560;
|
|
6872
|
+
const height = 280;
|
|
6873
|
+
const padLeft = 45;
|
|
6874
|
+
const padRight = 100;
|
|
6875
|
+
const padTop = 20;
|
|
6876
|
+
const padBottom = 40;
|
|
6877
|
+
const chartW = width - padLeft - padRight;
|
|
6878
|
+
const chartH = height - padTop - padBottom;
|
|
6879
|
+
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);">`;
|
|
6880
|
+
for (let step = 0; step <= 4; step++) {
|
|
6881
|
+
const yVal = (maxVal / 4 * step).toFixed(1);
|
|
6882
|
+
const yPos = padTop + chartH - step / 4 * chartH;
|
|
6883
|
+
svg += `<line x1="${padLeft}" y1="${yPos}" x2="${padLeft + chartW}" y2="${yPos}" stroke="#e2e8f0" stroke-dasharray="2,2" />`;
|
|
6884
|
+
svg += `<text x="${padLeft - 8}" y="${yPos + 4}" font-size="11" fill="#64748b" text-anchor="end">${yVal}</text>`;
|
|
6885
|
+
}
|
|
6886
|
+
const numCats = categories.length;
|
|
6887
|
+
const numSeries = headers.length;
|
|
6888
|
+
const groupW = chartW / numCats;
|
|
6889
|
+
const barW = Math.max(8, groupW * 0.7 / numSeries);
|
|
6890
|
+
const groupPad = (groupW - barW * numSeries) / 2;
|
|
6891
|
+
for (let catIdx = 0; catIdx < numCats; catIdx++) {
|
|
6892
|
+
const groupX = padLeft + catIdx * groupW + groupPad;
|
|
6893
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6894
|
+
const val = seriesValues[sIdx][catIdx] || 0;
|
|
6895
|
+
const barH = val / maxVal * chartH;
|
|
6896
|
+
const barX = groupX + sIdx * barW;
|
|
6897
|
+
const barY = padTop + chartH - barH;
|
|
6898
|
+
const col = colors[sIdx % colors.length];
|
|
6899
|
+
svg += `<rect x="${barX}" y="${barY}" width="${barW - 2}" height="${barH}" fill="${col}" rx="2"><title>${headers[sIdx]}: ${val}</title></rect>`;
|
|
6900
|
+
}
|
|
6901
|
+
const catX = padLeft + catIdx * groupW + groupW / 2;
|
|
6902
|
+
svg += `<text x="${catX}" y="${padTop + chartH + 18}" font-size="11" fill="#475569" text-anchor="middle">${categories[catIdx]}</text>`;
|
|
6903
|
+
}
|
|
6904
|
+
let legendY = padTop + 20;
|
|
6905
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6906
|
+
const col = colors[sIdx % colors.length];
|
|
6907
|
+
svg += `<rect x="${padLeft + chartW + 15}" y="${legendY}" width="12" height="12" fill="${col}" rx="2" />`;
|
|
6908
|
+
svg += `<text x="${padLeft + chartW + 32}" y="${legendY + 10}" font-size="11" fill="#334155">${headers[sIdx]}</text>`;
|
|
6909
|
+
legendY += 20;
|
|
6910
|
+
}
|
|
6911
|
+
svg += "</svg>";
|
|
6912
|
+
return svg;
|
|
6913
|
+
} catch (e) {
|
|
6914
|
+
console.warn("[DocPlugin] Error generating chart SVG:", e);
|
|
6915
|
+
return "";
|
|
6916
|
+
}
|
|
6917
|
+
}
|
|
6918
|
+
cleanWordDocFields(text, chartSvg = "") {
|
|
5977
6919
|
if (!text) return "";
|
|
5978
6920
|
let cleaned = text.replace(
|
|
6921
|
+
/\x13\s*EMBED\b[\s\S]*?\x15/gi,
|
|
6922
|
+
() => chartSvg ? `
|
|
6923
|
+
|
|
6924
|
+
${chartSvg}
|
|
6925
|
+
|
|
6926
|
+
` : ""
|
|
6927
|
+
);
|
|
6928
|
+
cleaned = cleaned.replace(
|
|
5979
6929
|
/\x13\s*HYPERLINK\s*"?([^"\x14]+)"?\s*\x14([\s\S]*?)\x15/gi,
|
|
5980
6930
|
(_match, url, label) => {
|
|
5981
6931
|
const cleanUrl = url.trim();
|
|
@@ -5983,18 +6933,23 @@ var DocPlugin = class {
|
|
|
5983
6933
|
return `<a href="${cleanUrl}" target="_blank" rel="noopener noreferrer" style="color: #2563eb; text-decoration: underline;">${cleanLabel}</a>`;
|
|
5984
6934
|
}
|
|
5985
6935
|
);
|
|
5986
|
-
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g,
|
|
6936
|
+
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g, (_m, res) => {
|
|
6937
|
+
if (/[\x00-\x1F]/.test(res)) return "";
|
|
6938
|
+
return res.trim();
|
|
6939
|
+
});
|
|
5987
6940
|
cleaned = cleaned.replace(/\x13[^\x15]*\x15/g, "");
|
|
5988
6941
|
cleaned = cleaned.replace(/[\x13\x14\x15]/g, "");
|
|
6942
|
+
cleaned = cleaned.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/g, "");
|
|
6943
|
+
cleaned = cleaned.replace(/EMBED\s+LibreOffice\.ChartDocument\.[0-9]+/gi, chartSvg || "");
|
|
5989
6944
|
return cleaned;
|
|
5990
6945
|
}
|
|
5991
|
-
splitIntoPages(text) {
|
|
6946
|
+
splitIntoPages(text, chartSvg = "") {
|
|
5992
6947
|
if (!text) return [""];
|
|
5993
|
-
const cleanedText = this.cleanWordDocFields(text);
|
|
6948
|
+
const cleanedText = this.cleanWordDocFields(text, chartSvg);
|
|
5994
6949
|
const normalized = cleanedText.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ");
|
|
5995
6950
|
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);
|
|
5996
6951
|
if (explicitParts.length === 0) explicitParts.push(normalized);
|
|
5997
|
-
const maxLinesPerPage =
|
|
6952
|
+
const maxLinesPerPage = 34;
|
|
5998
6953
|
const charsPerLine = 80;
|
|
5999
6954
|
const finalPages = [];
|
|
6000
6955
|
for (const part of explicitParts) {
|
|
@@ -6002,8 +6957,8 @@ var DocPlugin = class {
|
|
|
6002
6957
|
let currentLines = [];
|
|
6003
6958
|
let count = 0;
|
|
6004
6959
|
for (const line of lines) {
|
|
6005
|
-
const
|
|
6006
|
-
const vLines = Math.max(1, Math.ceil((
|
|
6960
|
+
const isSvg = line.includes("<svg");
|
|
6961
|
+
const vLines = isSvg ? 12 : Math.max(1, Math.ceil((line.replace(/<[^>]+>/g, "").length || 1) / charsPerLine));
|
|
6007
6962
|
if (count + vLines > maxLinesPerPage && currentLines.length > 0) {
|
|
6008
6963
|
finalPages.push(currentLines.join("\n"));
|
|
6009
6964
|
currentLines = [];
|
|
@@ -6043,9 +6998,44 @@ var DocPlugin = class {
|
|
|
6043
6998
|
tableLines = [];
|
|
6044
6999
|
}
|
|
6045
7000
|
};
|
|
7001
|
+
const sanitizeOptions = {
|
|
7002
|
+
ADD_TAGS: ["a", "svg", "g", "path", "line", "rect", "circle", "text", "title"],
|
|
7003
|
+
ADD_ATTR: [
|
|
7004
|
+
"href",
|
|
7005
|
+
"target",
|
|
7006
|
+
"rel",
|
|
7007
|
+
"style",
|
|
7008
|
+
"viewBox",
|
|
7009
|
+
"width",
|
|
7010
|
+
"height",
|
|
7011
|
+
"x",
|
|
7012
|
+
"y",
|
|
7013
|
+
"x1",
|
|
7014
|
+
"y1",
|
|
7015
|
+
"x2",
|
|
7016
|
+
"y2",
|
|
7017
|
+
"fill",
|
|
7018
|
+
"stroke",
|
|
7019
|
+
"stroke-width",
|
|
7020
|
+
"stroke-dasharray",
|
|
7021
|
+
"rx",
|
|
7022
|
+
"font-size",
|
|
7023
|
+
"text-anchor"
|
|
7024
|
+
]
|
|
7025
|
+
};
|
|
6046
7026
|
let i = 0;
|
|
6047
7027
|
while (i < lines.length) {
|
|
6048
7028
|
let line = lines[i];
|
|
7029
|
+
if (line.includes("<svg")) {
|
|
7030
|
+
if (inList) {
|
|
7031
|
+
html += "</ul>";
|
|
7032
|
+
inList = false;
|
|
7033
|
+
}
|
|
7034
|
+
flushTable();
|
|
7035
|
+
html += line;
|
|
7036
|
+
i++;
|
|
7037
|
+
continue;
|
|
7038
|
+
}
|
|
6049
7039
|
let tabCount = (line.match(/\t/g) || []).length;
|
|
6050
7040
|
if (tabCount > 0) {
|
|
6051
7041
|
let j = i;
|
|
@@ -6079,26 +7069,31 @@ var DocPlugin = class {
|
|
|
6079
7069
|
i++;
|
|
6080
7070
|
continue;
|
|
6081
7071
|
}
|
|
6082
|
-
|
|
6083
|
-
|
|
7072
|
+
if (/^\d{1,2}$/.test(line.trim())) {
|
|
7073
|
+
i++;
|
|
7074
|
+
continue;
|
|
7075
|
+
}
|
|
7076
|
+
const isShortLine = line.length < 60 && !line.endsWith(".") && !line.endsWith(",");
|
|
7077
|
+
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));
|
|
7078
|
+
if (isTitleLike) {
|
|
6084
7079
|
if (inList) {
|
|
6085
7080
|
html += "</ul>";
|
|
6086
7081
|
inList = false;
|
|
6087
7082
|
}
|
|
6088
|
-
html += `<h2 style="font-size:
|
|
7083
|
+
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>`;
|
|
6089
7084
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
6090
7085
|
if (!inList) {
|
|
6091
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
7086
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
6092
7087
|
inList = true;
|
|
6093
7088
|
}
|
|
6094
7089
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
6095
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
7090
|
+
html += `<li style="margin: 4px 0; line-height: 1.5; font-size: 11pt; color: #1e293b;">${DOMPurify6__default.default.sanitize(bulletText, sanitizeOptions)}</li>`;
|
|
6096
7091
|
} else {
|
|
6097
7092
|
if (inList) {
|
|
6098
7093
|
html += "</ul>";
|
|
6099
7094
|
inList = false;
|
|
6100
7095
|
}
|
|
6101
|
-
html += `<p style="line-height: 1.
|
|
7096
|
+
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>`;
|
|
6102
7097
|
}
|
|
6103
7098
|
i++;
|
|
6104
7099
|
}
|