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