@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/angular.js
CHANGED
|
@@ -3,6 +3,7 @@ import { CommonModule } from '@angular/common';
|
|
|
3
3
|
import DOMPurify6 from 'dompurify';
|
|
4
4
|
import * as pdfjsLib from 'pdfjs-dist';
|
|
5
5
|
import * as docx from 'docx-preview';
|
|
6
|
+
import * as fflate from 'fflate';
|
|
6
7
|
import { unzipSync, strFromU8, unzip } from 'fflate';
|
|
7
8
|
import * as XLSX from 'xlsx';
|
|
8
9
|
import hljs from 'highlight.js';
|
|
@@ -541,8 +542,7 @@ var ICON_FULLSCREEN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="non
|
|
|
541
542
|
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>`;
|
|
542
543
|
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>`;
|
|
543
544
|
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>`;
|
|
544
|
-
var
|
|
545
|
-
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>`;
|
|
545
|
+
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>`;
|
|
546
546
|
var ICON_MAP = {
|
|
547
547
|
"zoom-in": ICON_ZOOM_IN,
|
|
548
548
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -569,28 +569,177 @@ var ICON_MAP = {
|
|
|
569
569
|
"forward-10": ICON_FAST_FORWARD,
|
|
570
570
|
"rewind": ICON_REWIND,
|
|
571
571
|
"replay-10": ICON_REWIND,
|
|
572
|
-
"speed": ICON_SPEED,
|
|
573
572
|
"open-window": ICON_EXTERNAL_WINDOW,
|
|
574
|
-
"external-window": ICON_EXTERNAL_WINDOW
|
|
573
|
+
"external-window": ICON_EXTERNAL_WINDOW,
|
|
574
|
+
"openWindow": ICON_EXTERNAL_WINDOW,
|
|
575
|
+
"openSeparateWindow": ICON_EXTERNAL_WINDOW
|
|
575
576
|
};
|
|
576
577
|
var ToolbarController = class {
|
|
577
578
|
el;
|
|
578
579
|
toolbarEl;
|
|
579
580
|
actions = [];
|
|
581
|
+
config = {};
|
|
580
582
|
pageInputEl = null;
|
|
581
583
|
pageLabelEl = null;
|
|
582
|
-
|
|
584
|
+
prevPageBtn = null;
|
|
585
|
+
nextPageBtn = null;
|
|
586
|
+
constructor(container, config) {
|
|
583
587
|
this.el = container;
|
|
588
|
+
if (config) this.config = { ...config };
|
|
584
589
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
585
590
|
this.el.appendChild(this.toolbarEl);
|
|
586
591
|
}
|
|
592
|
+
setConfig(config) {
|
|
593
|
+
this.config = { ...config };
|
|
594
|
+
this.render();
|
|
595
|
+
}
|
|
596
|
+
getConfig() {
|
|
597
|
+
return { ...this.config };
|
|
598
|
+
}
|
|
599
|
+
hideAction(actionId) {
|
|
600
|
+
this.config[actionId] = false;
|
|
601
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = false;
|
|
602
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = false;
|
|
603
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
604
|
+
this.config.fitPage = false;
|
|
605
|
+
this.config.fitToPage = false;
|
|
606
|
+
this.config.fitWidth = false;
|
|
607
|
+
}
|
|
608
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = false;
|
|
609
|
+
if (actionId === "fullscreen") this.config.fullscreen = false;
|
|
610
|
+
if (actionId === "download") this.config.download = false;
|
|
611
|
+
if (actionId === "print") this.config.print = false;
|
|
612
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
613
|
+
this.config.openWindow = false;
|
|
614
|
+
this.config.openSeparateWindow = false;
|
|
615
|
+
}
|
|
616
|
+
if (actionId === "copy") this.config.copy = false;
|
|
617
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
618
|
+
this.config.pageNav = false;
|
|
619
|
+
this.config.pagination = false;
|
|
620
|
+
}
|
|
621
|
+
this.render();
|
|
622
|
+
}
|
|
623
|
+
showAction(actionId) {
|
|
624
|
+
this.config[actionId] = true;
|
|
625
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = true;
|
|
626
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = true;
|
|
627
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
628
|
+
this.config.fitPage = true;
|
|
629
|
+
this.config.fitToPage = true;
|
|
630
|
+
this.config.fitWidth = true;
|
|
631
|
+
}
|
|
632
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = true;
|
|
633
|
+
if (actionId === "fullscreen") this.config.fullscreen = true;
|
|
634
|
+
if (actionId === "download") this.config.download = true;
|
|
635
|
+
if (actionId === "print") this.config.print = true;
|
|
636
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
637
|
+
this.config.openWindow = true;
|
|
638
|
+
this.config.openSeparateWindow = true;
|
|
639
|
+
}
|
|
640
|
+
if (actionId === "copy") this.config.copy = true;
|
|
641
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
642
|
+
this.config.pageNav = true;
|
|
643
|
+
this.config.pagination = true;
|
|
644
|
+
}
|
|
645
|
+
this.render();
|
|
646
|
+
}
|
|
647
|
+
normalizeActionId(actionId) {
|
|
648
|
+
if (actionId === "zoomIn") return "zoom-in";
|
|
649
|
+
if (actionId === "zoomOut") return "zoom-out";
|
|
650
|
+
if (actionId === "fitPage" || actionId === "fitToPage" || actionId === "fitWidth") return "fit-page";
|
|
651
|
+
if (actionId === "rotateCW") return "rotate-cw";
|
|
652
|
+
if (actionId === "rotateCCW") return "rotate-ccw";
|
|
653
|
+
if (actionId === "openWindow" || actionId === "openSeparateWindow") return "open-window";
|
|
654
|
+
if (actionId === "pageNav") return "page-nav";
|
|
655
|
+
return actionId;
|
|
656
|
+
}
|
|
657
|
+
enableAction(actionId) {
|
|
658
|
+
const norm = this.normalizeActionId(actionId);
|
|
659
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
660
|
+
if (btn) {
|
|
661
|
+
btn.disabled = false;
|
|
662
|
+
btn.classList.remove("disabled");
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
disableAction(actionId) {
|
|
666
|
+
const norm = this.normalizeActionId(actionId);
|
|
667
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
668
|
+
if (btn) {
|
|
669
|
+
btn.disabled = true;
|
|
670
|
+
btn.classList.add("disabled");
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
setActionActive(actionId, active) {
|
|
674
|
+
const norm = this.normalizeActionId(actionId);
|
|
675
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
676
|
+
if (btn) {
|
|
677
|
+
if (active) {
|
|
678
|
+
btn.classList.add("active");
|
|
679
|
+
} else {
|
|
680
|
+
btn.classList.remove("active");
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
isActionEnabled(action) {
|
|
685
|
+
const c = this.config;
|
|
686
|
+
const id = action.id;
|
|
687
|
+
if (c[id] === false) return false;
|
|
688
|
+
if (id === "zoom-in" && (c.zoomIn === false || c["zoom-in"] === false)) return false;
|
|
689
|
+
if (id === "zoom-out" && (c.zoomOut === false || c["zoom-out"] === false)) return false;
|
|
690
|
+
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)) {
|
|
691
|
+
return false;
|
|
692
|
+
}
|
|
693
|
+
if ((id === "rotate-cw" || id === "rotate-ccw" || id === "rotate") && (c.rotate === false || c.rotateCW === false || c.rotateCCW === false || c["rotate-cw"] === false)) {
|
|
694
|
+
return false;
|
|
695
|
+
}
|
|
696
|
+
if (id === "fullscreen" && c.fullscreen === false) return false;
|
|
697
|
+
if (id === "download" && c.download === false) return false;
|
|
698
|
+
if (id === "print" && c.print === false) return false;
|
|
699
|
+
if ((id === "open-window" || id === "external-window") && (c.openWindow === false || c.openSeparateWindow === false || c["open-window"] === false)) {
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
702
|
+
if (id === "copy" && c.copy === false) return false;
|
|
703
|
+
if (id === "thumbnails" && c.thumbnails === false) return false;
|
|
704
|
+
if (id === "page-nav" && (c.pageNav === false || c.pagination === false || c["page-nav"] === false)) {
|
|
705
|
+
return false;
|
|
706
|
+
}
|
|
707
|
+
if ((id === "prev" || id === "page-prev") && (c.prevPage === false || c.prev === false || c["prev"] === false || c.pageNav === false || c.pagination === false)) {
|
|
708
|
+
return false;
|
|
709
|
+
}
|
|
710
|
+
if ((id === "next" || id === "page-next") && (c.nextPage === false || c.next === false || c["next"] === false || c.pageNav === false || c.pagination === false)) {
|
|
711
|
+
return false;
|
|
712
|
+
}
|
|
713
|
+
if (id === "play" && c.play === false) return false;
|
|
714
|
+
if (id === "pause" && c.pause === false) return false;
|
|
715
|
+
if ((id === "fast-forward" || id === "forward-10") && (c.fastForward === false || c["fast-forward"] === false)) {
|
|
716
|
+
return false;
|
|
717
|
+
}
|
|
718
|
+
if ((id === "rewind" || id === "replay-10") && (c.rewind === false || c["rewind"] === false)) {
|
|
719
|
+
return false;
|
|
720
|
+
}
|
|
721
|
+
if (id === "speed" && c.speed === false) return false;
|
|
722
|
+
return true;
|
|
723
|
+
}
|
|
587
724
|
setPage(page, max) {
|
|
588
725
|
if (this.pageInputEl) {
|
|
589
726
|
this.pageInputEl.value = page.toString();
|
|
727
|
+
if (max !== void 0) {
|
|
728
|
+
this.pageInputEl.max = max.toString();
|
|
729
|
+
}
|
|
590
730
|
}
|
|
591
731
|
if (max !== void 0 && this.pageLabelEl) {
|
|
592
732
|
this.pageLabelEl.textContent = ` / ${max}`;
|
|
593
733
|
}
|
|
734
|
+
const currentMax = max !== void 0 ? max : parseInt(this.pageInputEl?.max || "1", 10) || 1;
|
|
735
|
+
if (this.prevPageBtn) {
|
|
736
|
+
this.prevPageBtn.disabled = page <= 1;
|
|
737
|
+
this.prevPageBtn.style.opacity = page <= 1 ? "0.4" : "1";
|
|
738
|
+
}
|
|
739
|
+
if (this.nextPageBtn) {
|
|
740
|
+
this.nextPageBtn.disabled = page >= currentMax;
|
|
741
|
+
this.nextPageBtn.style.opacity = page >= currentMax ? "0.4" : "1";
|
|
742
|
+
}
|
|
594
743
|
}
|
|
595
744
|
update(actions) {
|
|
596
745
|
this.actions = actions;
|
|
@@ -613,8 +762,9 @@ var ToolbarController = class {
|
|
|
613
762
|
view: [],
|
|
614
763
|
actions: []
|
|
615
764
|
};
|
|
616
|
-
const
|
|
617
|
-
const
|
|
765
|
+
const enabledActions = this.actions.filter((a) => this.isActionEnabled(a));
|
|
766
|
+
const hasPageNav = enabledActions.some((a) => a.type === "page-nav");
|
|
767
|
+
const effectiveActions = hasPageNav ? enabledActions.filter((a) => a.id !== "page-prev" && a.id !== "page-next" && a.id !== "prev" && a.id !== "next") : enabledActions;
|
|
618
768
|
for (const action of effectiveActions) {
|
|
619
769
|
if (groups[action.group]) {
|
|
620
770
|
groups[action.group].push(action);
|
|
@@ -674,6 +824,13 @@ var ToolbarController = class {
|
|
|
674
824
|
action.execute("go", val);
|
|
675
825
|
});
|
|
676
826
|
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
827
|
+
const curVal = action.value ?? 1;
|
|
828
|
+
prevBtn.disabled = curVal <= 1;
|
|
829
|
+
prevBtn.style.opacity = curVal <= 1 ? "0.4" : "1";
|
|
830
|
+
nextBtn.disabled = curVal >= max;
|
|
831
|
+
nextBtn.style.opacity = curVal >= max ? "0.4" : "1";
|
|
832
|
+
this.prevPageBtn = prevBtn;
|
|
833
|
+
this.nextPageBtn = nextBtn;
|
|
677
834
|
this.pageInputEl = input;
|
|
678
835
|
this.pageLabelEl = label;
|
|
679
836
|
groupEl.appendChild(prevBtn);
|
|
@@ -714,9 +871,11 @@ var ToolbarController = class {
|
|
|
714
871
|
type: "button",
|
|
715
872
|
"data-action-id": id
|
|
716
873
|
});
|
|
717
|
-
const
|
|
718
|
-
if (
|
|
719
|
-
btn.innerHTML =
|
|
874
|
+
const internalSvg = ICON_MAP[iconHtml] || ICON_MAP[id];
|
|
875
|
+
if (internalSvg) {
|
|
876
|
+
btn.innerHTML = internalSvg;
|
|
877
|
+
} else if (iconHtml && iconHtml.startsWith("<svg")) {
|
|
878
|
+
btn.innerHTML = sanitizeSVG(iconHtml);
|
|
720
879
|
} else {
|
|
721
880
|
btn.textContent = title || id;
|
|
722
881
|
}
|
|
@@ -727,25 +886,63 @@ var ToolbarController = class {
|
|
|
727
886
|
var ThumbnailPanel = class {
|
|
728
887
|
el;
|
|
729
888
|
panelEl;
|
|
889
|
+
listEl;
|
|
890
|
+
headerEl;
|
|
730
891
|
thumbnails = [];
|
|
731
892
|
onSelect;
|
|
893
|
+
onToggleCallback;
|
|
732
894
|
activeIndex = 0;
|
|
733
|
-
|
|
895
|
+
observer;
|
|
896
|
+
renderedIndices = /* @__PURE__ */ new Set();
|
|
897
|
+
constructor(container, onToggle) {
|
|
734
898
|
this.el = container;
|
|
899
|
+
this.onToggleCallback = onToggle;
|
|
735
900
|
this.panelEl = createElement("div", { className: "fp-thumbnail-panel hidden" });
|
|
901
|
+
this.panelEl.style.width = "0px";
|
|
902
|
+
this.panelEl.style.minWidth = "0px";
|
|
903
|
+
this.panelEl.style.opacity = "0";
|
|
904
|
+
this.headerEl = createElement("div", { className: "fp-thumbnail-header" });
|
|
905
|
+
const title = createElement("span", { className: "fp-thumbnail-title" }, "Pages");
|
|
906
|
+
const closeBtn = createElement("button", {
|
|
907
|
+
className: "fp-thumbnail-close-btn",
|
|
908
|
+
title: "Close Thumbnails",
|
|
909
|
+
type: "button"
|
|
910
|
+
});
|
|
911
|
+
closeBtn.innerHTML = ICON_CLOSE;
|
|
912
|
+
closeBtn.addEventListener("click", (e) => {
|
|
913
|
+
e.stopPropagation();
|
|
914
|
+
this.hide();
|
|
915
|
+
});
|
|
916
|
+
this.headerEl.appendChild(title);
|
|
917
|
+
this.headerEl.appendChild(closeBtn);
|
|
918
|
+
this.listEl = createElement("div", { className: "fp-thumbnail-list" });
|
|
919
|
+
this.panelEl.appendChild(this.headerEl);
|
|
920
|
+
this.panelEl.appendChild(this.listEl);
|
|
736
921
|
this.el.appendChild(this.panelEl);
|
|
737
922
|
}
|
|
923
|
+
isOpen() {
|
|
924
|
+
return !this.panelEl.classList.contains("hidden") && this.panelEl.style.width !== "0px";
|
|
925
|
+
}
|
|
738
926
|
update(thumbnails, onSelect) {
|
|
739
927
|
this.thumbnails = thumbnails;
|
|
740
928
|
this.onSelect = onSelect;
|
|
929
|
+
this.renderedIndices.clear();
|
|
930
|
+
const titleEl = this.headerEl.querySelector(".fp-thumbnail-title");
|
|
931
|
+
if (titleEl) {
|
|
932
|
+
titleEl.textContent = `Pages (${thumbnails.length})`;
|
|
933
|
+
}
|
|
741
934
|
this.render();
|
|
935
|
+
if (this.isOpen()) {
|
|
936
|
+
this.renderAllVisible();
|
|
937
|
+
}
|
|
742
938
|
}
|
|
743
939
|
setActive(index) {
|
|
744
940
|
this.activeIndex = index;
|
|
745
|
-
const items = this.
|
|
941
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
746
942
|
items.forEach((item, i) => {
|
|
747
943
|
if (i === index) {
|
|
748
944
|
item.classList.add("active");
|
|
945
|
+
item.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
749
946
|
} else {
|
|
750
947
|
item.classList.remove("active");
|
|
751
948
|
}
|
|
@@ -753,37 +950,102 @@ var ThumbnailPanel = class {
|
|
|
753
950
|
}
|
|
754
951
|
show() {
|
|
755
952
|
this.panelEl.classList.remove("hidden");
|
|
953
|
+
this.panelEl.style.width = "200px";
|
|
954
|
+
this.panelEl.style.minWidth = "200px";
|
|
955
|
+
this.panelEl.style.opacity = "1";
|
|
956
|
+
this.panelEl.style.display = "flex";
|
|
957
|
+
this.onToggleCallback?.(true);
|
|
958
|
+
this.renderAllVisible();
|
|
756
959
|
}
|
|
757
960
|
hide() {
|
|
758
961
|
this.panelEl.classList.add("hidden");
|
|
962
|
+
this.panelEl.style.width = "0px";
|
|
963
|
+
this.panelEl.style.minWidth = "0px";
|
|
964
|
+
this.panelEl.style.opacity = "0";
|
|
965
|
+
this.onToggleCallback?.(false);
|
|
759
966
|
}
|
|
760
967
|
toggle() {
|
|
761
|
-
this.
|
|
968
|
+
if (this.isOpen()) {
|
|
969
|
+
this.hide();
|
|
970
|
+
} else {
|
|
971
|
+
this.show();
|
|
972
|
+
}
|
|
762
973
|
}
|
|
763
974
|
destroy() {
|
|
975
|
+
if (this.observer) {
|
|
976
|
+
this.observer.disconnect();
|
|
977
|
+
this.observer = void 0;
|
|
978
|
+
}
|
|
979
|
+
this.renderedIndices.clear();
|
|
764
980
|
this.el.innerHTML = "";
|
|
765
981
|
}
|
|
766
|
-
|
|
767
|
-
this.
|
|
982
|
+
renderAllVisible() {
|
|
983
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
984
|
+
items.forEach((item) => {
|
|
985
|
+
const idx = parseInt(item.dataset.thumbIndex || "-1", 10);
|
|
986
|
+
if (idx >= 0 && !this.renderedIndices.has(idx)) {
|
|
987
|
+
this.renderThumbnailItem(idx, item);
|
|
988
|
+
}
|
|
989
|
+
});
|
|
990
|
+
}
|
|
991
|
+
renderThumbnailItem(idx, itemEl) {
|
|
992
|
+
if (this.renderedIndices.has(idx)) return;
|
|
993
|
+
this.renderedIndices.add(idx);
|
|
994
|
+
const canvas = itemEl.querySelector("canvas");
|
|
995
|
+
const thumb = this.thumbnails[idx];
|
|
996
|
+
if (canvas && thumb) {
|
|
997
|
+
Promise.resolve(thumb.render(canvas)).catch((err) => {
|
|
998
|
+
console.warn(`[FilePreview] Error rendering thumbnail ${idx}:`, err);
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
render() {
|
|
1003
|
+
if (this.observer) {
|
|
1004
|
+
this.observer.disconnect();
|
|
1005
|
+
}
|
|
1006
|
+
this.listEl.innerHTML = "";
|
|
1007
|
+
const useObserver = typeof IntersectionObserver !== "undefined";
|
|
1008
|
+
if (useObserver) {
|
|
1009
|
+
this.observer = new IntersectionObserver(
|
|
1010
|
+
(entries) => {
|
|
1011
|
+
for (const entry of entries) {
|
|
1012
|
+
if (entry.isIntersecting) {
|
|
1013
|
+
const target = entry.target;
|
|
1014
|
+
const idx = parseInt(target.dataset.thumbIndex || "-1", 10);
|
|
1015
|
+
if (idx >= 0) {
|
|
1016
|
+
this.renderThumbnailItem(idx, target);
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
},
|
|
1021
|
+
{
|
|
1022
|
+
root: this.listEl,
|
|
1023
|
+
rootMargin: "120px 0px 120px 0px"
|
|
1024
|
+
}
|
|
1025
|
+
);
|
|
1026
|
+
}
|
|
768
1027
|
for (let i = 0; i < this.thumbnails.length; i++) {
|
|
769
1028
|
const thumb = this.thumbnails[i];
|
|
770
|
-
const itemEl = createElement("div", {
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
1029
|
+
const itemEl = createElement("div", {
|
|
1030
|
+
className: "fp-thumbnail-item" + (i === this.activeIndex ? " active" : "")
|
|
1031
|
+
});
|
|
1032
|
+
itemEl.dataset.thumbIndex = i.toString();
|
|
774
1033
|
itemEl.addEventListener("click", () => {
|
|
775
1034
|
this.setActive(i);
|
|
776
1035
|
this.onSelect?.(i);
|
|
777
1036
|
});
|
|
778
|
-
const
|
|
779
|
-
const
|
|
780
|
-
|
|
1037
|
+
const canvasWrapper = createElement("div", { className: "fp-thumbnail-canvas-wrapper" });
|
|
1038
|
+
const canvas = createElement("canvas", { width: "130", height: "170" });
|
|
1039
|
+
canvasWrapper.appendChild(canvas);
|
|
1040
|
+
const label = createElement("span", { className: "fp-thumbnail-label" }, thumb.label || `Page ${i + 1}`);
|
|
1041
|
+
itemEl.appendChild(canvasWrapper);
|
|
781
1042
|
itemEl.appendChild(label);
|
|
782
|
-
this.
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
}
|
|
786
|
-
|
|
1043
|
+
this.listEl.appendChild(itemEl);
|
|
1044
|
+
if (this.observer) {
|
|
1045
|
+
this.observer.observe(itemEl);
|
|
1046
|
+
}
|
|
1047
|
+
if (i < 4) {
|
|
1048
|
+
this.renderThumbnailItem(i, itemEl);
|
|
787
1049
|
}
|
|
788
1050
|
}
|
|
789
1051
|
}
|
|
@@ -804,6 +1066,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
804
1066
|
currentOptions = {};
|
|
805
1067
|
resizeObserver = null;
|
|
806
1068
|
fullscreenHandler = null;
|
|
1069
|
+
titleBarEl = null;
|
|
807
1070
|
/**
|
|
808
1071
|
* Register a preview plugin.
|
|
809
1072
|
*/
|
|
@@ -840,6 +1103,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
840
1103
|
}
|
|
841
1104
|
this.currentBuffer = buffer.slice(0);
|
|
842
1105
|
this.currentMetadata = metadata;
|
|
1106
|
+
this.updateTitleBar(options, metadata);
|
|
843
1107
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
844
1108
|
const fileInfo = { metadata, buffer };
|
|
845
1109
|
const matchedPlugin = await this.findPlugin(fileInfo);
|
|
@@ -863,15 +1127,21 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
863
1127
|
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
864
1128
|
const total = payload.total ?? payload.totalPages;
|
|
865
1129
|
this.toolbar?.setPage(payload.page, total);
|
|
1130
|
+
this.thumbnailPanel?.setActive(payload.page - 1);
|
|
866
1131
|
}
|
|
867
1132
|
this.eventEmitter.emit(event, payload);
|
|
868
|
-
}
|
|
1133
|
+
},
|
|
1134
|
+
toggleThumbnails: () => this.toggleThumbnails()
|
|
869
1135
|
});
|
|
870
1136
|
this.activeInstance = instance;
|
|
871
1137
|
instance.openInSeparateWindow = () => this.openInSeparateWindow();
|
|
1138
|
+
instance.toggleThumbnails = () => this.toggleThumbnails();
|
|
872
1139
|
this.hideLoading();
|
|
873
1140
|
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
874
|
-
|
|
1141
|
+
const isToolbarVisible = options.showToolbar !== false && options.toolbar !== false;
|
|
1142
|
+
if (isToolbarVisible && this.toolbar) {
|
|
1143
|
+
const toolbarConfig = this.extractToolbarConfig(options);
|
|
1144
|
+
this.toolbar.setConfig(toolbarConfig);
|
|
875
1145
|
const actions = matchedPlugin.getToolbarActions(instance);
|
|
876
1146
|
const hasFullscreen = actions.some((a) => a.id === "fullscreen");
|
|
877
1147
|
if (!hasFullscreen && this.wrapperEl) {
|
|
@@ -921,6 +1191,12 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
921
1191
|
}
|
|
922
1192
|
});
|
|
923
1193
|
}
|
|
1194
|
+
const thumbAction = actions.find((a) => a.id === "thumbnails");
|
|
1195
|
+
if (thumbAction) {
|
|
1196
|
+
thumbAction.execute = () => {
|
|
1197
|
+
this.toggleThumbnails();
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
924
1200
|
this.toolbar.update(actions);
|
|
925
1201
|
this.toolbar.show();
|
|
926
1202
|
}
|
|
@@ -1005,7 +1281,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1005
1281
|
if (targetUrl) {
|
|
1006
1282
|
const newWin2 = window.open(targetUrl, "_blank");
|
|
1007
1283
|
if (!newWin2) {
|
|
1008
|
-
|
|
1284
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
1009
1285
|
return null;
|
|
1010
1286
|
}
|
|
1011
1287
|
return newWin2;
|
|
@@ -1013,7 +1289,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1013
1289
|
const title = (this.currentMetadata?.name || "Document Preview") + " - Full Preview";
|
|
1014
1290
|
const newWin = window.open("", "_blank");
|
|
1015
1291
|
if (!newWin) {
|
|
1016
|
-
|
|
1292
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
1017
1293
|
return null;
|
|
1018
1294
|
}
|
|
1019
1295
|
newWin.document.title = title;
|
|
@@ -1090,6 +1366,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1090
1366
|
this.currentBuffer = null;
|
|
1091
1367
|
this.currentMetadata = null;
|
|
1092
1368
|
this.currentContainer = null;
|
|
1369
|
+
this.titleBarEl = null;
|
|
1093
1370
|
}
|
|
1094
1371
|
/**
|
|
1095
1372
|
* Get the currently active preview instance.
|
|
@@ -1097,7 +1374,218 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1097
1374
|
getInstance() {
|
|
1098
1375
|
return this.activeInstance;
|
|
1099
1376
|
}
|
|
1377
|
+
// --- Toolbar Configuration & Feature Toggles ---
|
|
1378
|
+
/**
|
|
1379
|
+
* Configure toolbar features dynamically through options or methods.
|
|
1380
|
+
* e.g. viewer.setToolbarConfig({ zoomIn: false, print: false })
|
|
1381
|
+
*/
|
|
1382
|
+
setToolbarConfig(config) {
|
|
1383
|
+
this.toolbar?.setConfig(config);
|
|
1384
|
+
}
|
|
1385
|
+
/**
|
|
1386
|
+
* Get current toolbar configuration.
|
|
1387
|
+
*/
|
|
1388
|
+
getToolbarConfig() {
|
|
1389
|
+
return this.toolbar?.getConfig() ?? {};
|
|
1390
|
+
}
|
|
1391
|
+
/**
|
|
1392
|
+
* Hide a specific toolbar action by ID or alias (e.g. 'zoom-in', 'print', 'download').
|
|
1393
|
+
*/
|
|
1394
|
+
hideToolbarAction(actionId) {
|
|
1395
|
+
this.toolbar?.hideAction(actionId);
|
|
1396
|
+
}
|
|
1397
|
+
/**
|
|
1398
|
+
* Show a specific toolbar action by ID or alias.
|
|
1399
|
+
*/
|
|
1400
|
+
showToolbarAction(actionId) {
|
|
1401
|
+
this.toolbar?.showAction(actionId);
|
|
1402
|
+
}
|
|
1403
|
+
/**
|
|
1404
|
+
* Enable a specific toolbar action button.
|
|
1405
|
+
*/
|
|
1406
|
+
enableToolbarAction(actionId) {
|
|
1407
|
+
this.toolbar?.enableAction(actionId);
|
|
1408
|
+
}
|
|
1409
|
+
/**
|
|
1410
|
+
* Disable a specific toolbar action button.
|
|
1411
|
+
*/
|
|
1412
|
+
disableToolbarAction(actionId) {
|
|
1413
|
+
this.toolbar?.disableAction(actionId);
|
|
1414
|
+
}
|
|
1415
|
+
// --- Programmatic Toolbar Action Methods ---
|
|
1416
|
+
/**
|
|
1417
|
+
* Fit document to page so it fills the frame width with minimal margins.
|
|
1418
|
+
*/
|
|
1419
|
+
fitToPage() {
|
|
1420
|
+
this.activeInstance?.fitToPage?.();
|
|
1421
|
+
}
|
|
1422
|
+
/**
|
|
1423
|
+
* Zoom in.
|
|
1424
|
+
*/
|
|
1425
|
+
zoomIn() {
|
|
1426
|
+
this.activeInstance?.zoomIn?.();
|
|
1427
|
+
}
|
|
1428
|
+
/**
|
|
1429
|
+
* Zoom out.
|
|
1430
|
+
*/
|
|
1431
|
+
zoomOut() {
|
|
1432
|
+
this.activeInstance?.zoomOut?.();
|
|
1433
|
+
}
|
|
1434
|
+
/**
|
|
1435
|
+
* Set specific zoom level.
|
|
1436
|
+
*/
|
|
1437
|
+
setZoom(level) {
|
|
1438
|
+
this.activeInstance?.setZoom?.(level);
|
|
1439
|
+
}
|
|
1440
|
+
/**
|
|
1441
|
+
* Get current zoom level.
|
|
1442
|
+
*/
|
|
1443
|
+
getZoom() {
|
|
1444
|
+
return this.activeInstance?.getZoom?.() ?? 1;
|
|
1445
|
+
}
|
|
1446
|
+
/**
|
|
1447
|
+
* Rotate 90 degrees clockwise.
|
|
1448
|
+
*/
|
|
1449
|
+
rotateCW() {
|
|
1450
|
+
this.activeInstance?.rotateCW?.();
|
|
1451
|
+
}
|
|
1452
|
+
/**
|
|
1453
|
+
* Rotate 90 degrees counter-clockwise.
|
|
1454
|
+
*/
|
|
1455
|
+
rotateCCW() {
|
|
1456
|
+
this.activeInstance?.rotateCCW?.();
|
|
1457
|
+
}
|
|
1458
|
+
/**
|
|
1459
|
+
* Navigate to a specific page number.
|
|
1460
|
+
*/
|
|
1461
|
+
goToPage(page) {
|
|
1462
|
+
this.activeInstance?.goToPage?.(page);
|
|
1463
|
+
this.toolbar?.setPage(page);
|
|
1464
|
+
}
|
|
1465
|
+
/**
|
|
1466
|
+
* Navigate to next page.
|
|
1467
|
+
*/
|
|
1468
|
+
nextPage() {
|
|
1469
|
+
const cur = this.getCurrentPage();
|
|
1470
|
+
const max = this.getPageCount();
|
|
1471
|
+
if (cur < max) {
|
|
1472
|
+
this.goToPage(cur + 1);
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
/**
|
|
1476
|
+
* Navigate to previous page.
|
|
1477
|
+
*/
|
|
1478
|
+
prevPage() {
|
|
1479
|
+
const cur = this.getCurrentPage();
|
|
1480
|
+
if (cur > 1) {
|
|
1481
|
+
this.goToPage(cur - 1);
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
/**
|
|
1485
|
+
* Get total page count.
|
|
1486
|
+
*/
|
|
1487
|
+
getPageCount() {
|
|
1488
|
+
return this.activeInstance?.getPageCount?.() ?? 1;
|
|
1489
|
+
}
|
|
1490
|
+
/**
|
|
1491
|
+
* Get current page number.
|
|
1492
|
+
*/
|
|
1493
|
+
getCurrentPage() {
|
|
1494
|
+
return this.activeInstance?.getCurrentPage?.() ?? 1;
|
|
1495
|
+
}
|
|
1496
|
+
/**
|
|
1497
|
+
* Download the current document.
|
|
1498
|
+
*/
|
|
1499
|
+
download() {
|
|
1500
|
+
this.activeInstance?.download?.();
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1503
|
+
* Print the current document.
|
|
1504
|
+
*/
|
|
1505
|
+
print() {
|
|
1506
|
+
this.activeInstance?.print?.();
|
|
1507
|
+
}
|
|
1508
|
+
/**
|
|
1509
|
+
* Toggle fullscreen mode.
|
|
1510
|
+
*/
|
|
1511
|
+
toggleFullscreen() {
|
|
1512
|
+
try {
|
|
1513
|
+
if (!document.fullscreenElement) {
|
|
1514
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
1515
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
1516
|
+
} else {
|
|
1517
|
+
document.exitFullscreen?.();
|
|
1518
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
1519
|
+
}
|
|
1520
|
+
} catch {
|
|
1521
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
1522
|
+
}
|
|
1523
|
+
setTimeout(() => {
|
|
1524
|
+
this.activeInstance?.fitToPage?.();
|
|
1525
|
+
}, 120);
|
|
1526
|
+
}
|
|
1527
|
+
/**
|
|
1528
|
+
* Toggle thumbnails sidebar panel.
|
|
1529
|
+
*/
|
|
1530
|
+
toggleThumbnails() {
|
|
1531
|
+
if (!this.thumbnailPanel) return;
|
|
1532
|
+
this.thumbnailPanel.toggle();
|
|
1533
|
+
const isOpen = this.thumbnailPanel.isOpen();
|
|
1534
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1535
|
+
setTimeout(() => {
|
|
1536
|
+
this.activeInstance?.fitToPage?.();
|
|
1537
|
+
}, 260);
|
|
1538
|
+
}
|
|
1539
|
+
/**
|
|
1540
|
+
* Set whether to display the file name / title bar above the toolbar.
|
|
1541
|
+
*/
|
|
1542
|
+
setShowFileName(show) {
|
|
1543
|
+
if (this.currentOptions) {
|
|
1544
|
+
this.currentOptions.showFileName = show;
|
|
1545
|
+
}
|
|
1546
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1547
|
+
}
|
|
1548
|
+
/**
|
|
1549
|
+
* Set or override the displayed file name in the preview panel.
|
|
1550
|
+
*/
|
|
1551
|
+
setFileName(name) {
|
|
1552
|
+
if (this.currentOptions) {
|
|
1553
|
+
this.currentOptions.fileName = name;
|
|
1554
|
+
}
|
|
1555
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1556
|
+
}
|
|
1100
1557
|
// --- Private methods ---
|
|
1558
|
+
updateTitleBar(options, metadata) {
|
|
1559
|
+
if (!this.titleBarEl) return;
|
|
1560
|
+
const show = options?.showFileName !== false;
|
|
1561
|
+
if (!show) {
|
|
1562
|
+
this.titleBarEl.style.display = "none";
|
|
1563
|
+
return;
|
|
1564
|
+
}
|
|
1565
|
+
const name = options?.fileName || metadata?.name || this.currentMetadata?.name || "";
|
|
1566
|
+
if (!name) {
|
|
1567
|
+
this.titleBarEl.style.display = "none";
|
|
1568
|
+
return;
|
|
1569
|
+
}
|
|
1570
|
+
this.titleBarEl.style.display = "flex";
|
|
1571
|
+
const ext = metadata?.extension || (name.includes(".") ? "." + name.split(".").pop() : "");
|
|
1572
|
+
const badge = ext ? ext.replace(".", "").toUpperCase() : "";
|
|
1573
|
+
this.titleBarEl.innerHTML = `
|
|
1574
|
+
<div class="fp-titlebar-info">
|
|
1575
|
+
<span class="fp-titlebar-icon">\u{1F4C4}</span>
|
|
1576
|
+
<span class="fp-titlebar-name" title="${name}">${name}</span>
|
|
1577
|
+
${badge ? `<span class="fp-titlebar-badge">${badge}</span>` : ""}
|
|
1578
|
+
</div>
|
|
1579
|
+
`;
|
|
1580
|
+
}
|
|
1581
|
+
extractToolbarConfig(options) {
|
|
1582
|
+
if (!options) return {};
|
|
1583
|
+
const nested = typeof options.toolbar === "object" ? options.toolbar : {};
|
|
1584
|
+
return {
|
|
1585
|
+
...options,
|
|
1586
|
+
...nested
|
|
1587
|
+
};
|
|
1588
|
+
}
|
|
1101
1589
|
abort() {
|
|
1102
1590
|
if (this.abortController) {
|
|
1103
1591
|
this.abortController.abort();
|
|
@@ -1140,17 +1628,29 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1140
1628
|
bodyEl.className = "fp-body";
|
|
1141
1629
|
bodyEl.appendChild(thumbnailEl);
|
|
1142
1630
|
bodyEl.appendChild(this.contentEl);
|
|
1631
|
+
const titleBarEl = document.createElement("div");
|
|
1632
|
+
titleBarEl.className = "fp-titlebar";
|
|
1633
|
+
this.titleBarEl = titleBarEl;
|
|
1634
|
+
this.updateTitleBar(options, this.currentMetadata);
|
|
1143
1635
|
if (toolbarPos === "top") {
|
|
1636
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1144
1637
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1145
1638
|
this.wrapperEl.appendChild(bodyEl);
|
|
1146
1639
|
} else {
|
|
1640
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1147
1641
|
this.wrapperEl.appendChild(bodyEl);
|
|
1148
1642
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1149
1643
|
}
|
|
1150
1644
|
container.innerHTML = "";
|
|
1151
1645
|
container.appendChild(this.wrapperEl);
|
|
1152
|
-
|
|
1153
|
-
this.
|
|
1646
|
+
const initialToolbarConfig = this.extractToolbarConfig(options);
|
|
1647
|
+
this.toolbar = new ToolbarController(toolbarEl, initialToolbarConfig);
|
|
1648
|
+
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl, (isOpen) => {
|
|
1649
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1650
|
+
setTimeout(() => {
|
|
1651
|
+
this.activeInstance?.fitToPage?.();
|
|
1652
|
+
}, 260);
|
|
1653
|
+
});
|
|
1154
1654
|
this.setupKeyboardShortcuts();
|
|
1155
1655
|
this.setupDragAndDrop(container, options);
|
|
1156
1656
|
this.setupResizeAndFullscreenListeners();
|
|
@@ -1540,6 +2040,14 @@ var PdfPlugin = class {
|
|
|
1540
2040
|
group: "zoom",
|
|
1541
2041
|
execute: () => instance.fitToPage?.()
|
|
1542
2042
|
},
|
|
2043
|
+
{
|
|
2044
|
+
id: "fit-width",
|
|
2045
|
+
icon: "fit-width",
|
|
2046
|
+
label: "Fit to Width",
|
|
2047
|
+
type: "button",
|
|
2048
|
+
group: "zoom",
|
|
2049
|
+
execute: () => instance.fitToWidth?.()
|
|
2050
|
+
},
|
|
1543
2051
|
{
|
|
1544
2052
|
id: "rotate-cw",
|
|
1545
2053
|
icon: "rotate-cw",
|
|
@@ -1548,6 +2056,14 @@ var PdfPlugin = class {
|
|
|
1548
2056
|
group: "view",
|
|
1549
2057
|
execute: () => instance.rotateCW?.()
|
|
1550
2058
|
},
|
|
2059
|
+
{
|
|
2060
|
+
id: "rotate-ccw",
|
|
2061
|
+
icon: "rotate-ccw",
|
|
2062
|
+
label: "Rotate Counter-Clockwise",
|
|
2063
|
+
type: "button",
|
|
2064
|
+
group: "view",
|
|
2065
|
+
execute: () => instance.rotateCCW?.()
|
|
2066
|
+
},
|
|
1551
2067
|
{
|
|
1552
2068
|
id: "download",
|
|
1553
2069
|
icon: "download",
|
|
@@ -1579,12 +2095,13 @@ var PdfPlugin = class {
|
|
|
1579
2095
|
container.className = "fp-pdf-container";
|
|
1580
2096
|
container.style.width = "100%";
|
|
1581
2097
|
container.style.height = "100%";
|
|
1582
|
-
container.style.
|
|
2098
|
+
container.style.overflowX = "hidden";
|
|
2099
|
+
container.style.overflowY = "auto";
|
|
1583
2100
|
container.style.display = "flex";
|
|
1584
2101
|
container.style.flexDirection = "column";
|
|
1585
2102
|
container.style.alignItems = "center";
|
|
1586
2103
|
container.style.justifyContent = "flex-start";
|
|
1587
|
-
container.style.padding = "
|
|
2104
|
+
container.style.padding = "16px 8px";
|
|
1588
2105
|
container.style.backgroundColor = "#0f172a";
|
|
1589
2106
|
container.style.boxSizing = "border-box";
|
|
1590
2107
|
container.style.position = "relative";
|
|
@@ -1595,30 +2112,12 @@ var PdfPlugin = class {
|
|
|
1595
2112
|
pageCard.style.borderRadius = "4px";
|
|
1596
2113
|
pageCard.style.overflow = "hidden";
|
|
1597
2114
|
pageCard.style.lineHeight = "0";
|
|
1598
|
-
pageCard.style.transition = "transform 0.15s ease";
|
|
1599
2115
|
pageCard.style.position = "relative";
|
|
1600
2116
|
pageCard.style.flexShrink = "0";
|
|
2117
|
+
pageCard.style.transition = "box-shadow 0.2s ease";
|
|
1601
2118
|
let canvas = document.createElement("canvas");
|
|
1602
2119
|
pageCard.appendChild(canvas);
|
|
1603
2120
|
container.appendChild(pageCard);
|
|
1604
|
-
const indicator = document.createElement("div");
|
|
1605
|
-
indicator.className = "fp-pdf-page-indicator";
|
|
1606
|
-
indicator.style.position = "sticky";
|
|
1607
|
-
indicator.style.bottom = "16px";
|
|
1608
|
-
indicator.style.marginTop = "16px";
|
|
1609
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1610
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
1611
|
-
indicator.style.color = "#f8fafc";
|
|
1612
|
-
indicator.style.fontSize = "12px";
|
|
1613
|
-
indicator.style.fontWeight = "600";
|
|
1614
|
-
indicator.style.padding = "5px 14px";
|
|
1615
|
-
indicator.style.borderRadius = "20px";
|
|
1616
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1617
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1618
|
-
indicator.style.zIndex = "10";
|
|
1619
|
-
indicator.style.userSelect = "none";
|
|
1620
|
-
indicator.style.pointerEvents = "none";
|
|
1621
|
-
container.appendChild(indicator);
|
|
1622
2121
|
ctx.container.appendChild(container);
|
|
1623
2122
|
const standardFontsUrl = typeof window !== "undefined" && window.__PDF_STANDARD_FONTS_URL__ || "./standard_fonts/";
|
|
1624
2123
|
const cmapsUrl = typeof window !== "undefined" && window.__PDF_CMAPS_URL__ || "./cmaps/";
|
|
@@ -1634,8 +2133,9 @@ var PdfPlugin = class {
|
|
|
1634
2133
|
let currentPage = 1;
|
|
1635
2134
|
let zoomScale = 1;
|
|
1636
2135
|
let rotation = 0;
|
|
1637
|
-
let fitMode = "
|
|
2136
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
1638
2137
|
let currentRenderTask = null;
|
|
2138
|
+
let textLayerDiv = null;
|
|
1639
2139
|
const renderPage = async (pageNum) => {
|
|
1640
2140
|
if (currentRenderTask) {
|
|
1641
2141
|
try {
|
|
@@ -1647,30 +2147,37 @@ var PdfPlugin = class {
|
|
|
1647
2147
|
const newCanvas = document.createElement("canvas");
|
|
1648
2148
|
pageCard.replaceChild(newCanvas, canvas);
|
|
1649
2149
|
canvas = newCanvas;
|
|
2150
|
+
if (textLayerDiv) {
|
|
2151
|
+
textLayerDiv.remove();
|
|
2152
|
+
textLayerDiv = null;
|
|
2153
|
+
}
|
|
1650
2154
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1651
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1652
2155
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1653
2156
|
const page = await pdfDoc.getPage(currentPage);
|
|
1654
2157
|
const containerWidth = container.clientWidth || 900;
|
|
1655
2158
|
const containerHeight = container.clientHeight || 700;
|
|
1656
2159
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1657
|
-
const availWidth = Math.max(
|
|
1658
|
-
const availHeight = Math.max(
|
|
2160
|
+
const availWidth = Math.max(280, containerWidth - 36);
|
|
2161
|
+
const availHeight = Math.max(280, containerHeight - 32);
|
|
1659
2162
|
const scaleW = availWidth / unscaledVp.width;
|
|
1660
2163
|
const scaleH = availHeight / unscaledVp.height;
|
|
1661
2164
|
let fitScale;
|
|
1662
2165
|
if (fitMode === "page") {
|
|
1663
|
-
fitScale = Math.max(0.4, Math.min(scaleW, scaleH));
|
|
2166
|
+
fitScale = Math.max(0.2, Math.min(4, Math.min(scaleW, scaleH)));
|
|
1664
2167
|
} else {
|
|
1665
|
-
fitScale = Math.max(0.
|
|
2168
|
+
fitScale = Math.max(0.2, Math.min(4, scaleW));
|
|
1666
2169
|
}
|
|
1667
2170
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1668
2171
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1669
2172
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
2173
|
+
const displayWidth = Math.floor(viewport.width);
|
|
2174
|
+
const displayHeight = Math.floor(viewport.height);
|
|
1670
2175
|
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1671
2176
|
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1672
|
-
canvas.style.width = `${
|
|
1673
|
-
canvas.style.height = `${
|
|
2177
|
+
canvas.style.width = `${displayWidth}px`;
|
|
2178
|
+
canvas.style.height = `${displayHeight}px`;
|
|
2179
|
+
pageCard.style.width = `${displayWidth}px`;
|
|
2180
|
+
pageCard.style.height = `${displayHeight}px`;
|
|
1674
2181
|
const canvasCtx = canvas.getContext("2d");
|
|
1675
2182
|
if (!canvasCtx) return;
|
|
1676
2183
|
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
@@ -1684,9 +2191,31 @@ var PdfPlugin = class {
|
|
|
1684
2191
|
if (err?.name !== "RenderingCancelledException") {
|
|
1685
2192
|
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1686
2193
|
}
|
|
2194
|
+
return;
|
|
1687
2195
|
} finally {
|
|
1688
2196
|
currentRenderTask = null;
|
|
1689
2197
|
}
|
|
2198
|
+
try {
|
|
2199
|
+
textLayerDiv = document.createElement("div");
|
|
2200
|
+
textLayerDiv.className = "textLayer";
|
|
2201
|
+
textLayerDiv.style.width = `${displayWidth}px`;
|
|
2202
|
+
textLayerDiv.style.height = `${displayHeight}px`;
|
|
2203
|
+
textLayerDiv.style.position = "absolute";
|
|
2204
|
+
textLayerDiv.style.top = "0";
|
|
2205
|
+
textLayerDiv.style.left = "0";
|
|
2206
|
+
textLayerDiv.style.lineHeight = "1";
|
|
2207
|
+
pageCard.appendChild(textLayerDiv);
|
|
2208
|
+
if (pdfjsLib.TextLayer) {
|
|
2209
|
+
const textLayer = new pdfjsLib.TextLayer({
|
|
2210
|
+
textContentSource: page.streamTextContent(),
|
|
2211
|
+
container: textLayerDiv,
|
|
2212
|
+
viewport
|
|
2213
|
+
});
|
|
2214
|
+
await textLayer.render();
|
|
2215
|
+
}
|
|
2216
|
+
} catch (err) {
|
|
2217
|
+
console.debug("[PdfPlugin] TextLayer notice:", err);
|
|
2218
|
+
}
|
|
1690
2219
|
};
|
|
1691
2220
|
renderPage(1);
|
|
1692
2221
|
let resizeTimer = null;
|
|
@@ -1696,11 +2225,48 @@ var PdfPlugin = class {
|
|
|
1696
2225
|
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1697
2226
|
renderPage(currentPage);
|
|
1698
2227
|
}
|
|
1699
|
-
},
|
|
2228
|
+
}, 120);
|
|
1700
2229
|
});
|
|
1701
2230
|
resizeObserver.observe(container);
|
|
2231
|
+
const onWheel = (e) => {
|
|
2232
|
+
if (e.ctrlKey || e.metaKey) {
|
|
2233
|
+
e.preventDefault();
|
|
2234
|
+
const delta = e.deltaY > 0 ? -0.15 : 0.15;
|
|
2235
|
+
zoomScale = Math.max(0.25, Math.min(4, Math.round((zoomScale + delta) * 100) / 100));
|
|
2236
|
+
renderPage(currentPage);
|
|
2237
|
+
}
|
|
2238
|
+
};
|
|
2239
|
+
container.addEventListener("wheel", onWheel, { passive: false });
|
|
2240
|
+
const onKeyDown = (e) => {
|
|
2241
|
+
const tag = e.target?.tagName?.toLowerCase();
|
|
2242
|
+
if (tag === "input" || tag === "textarea" || tag === "select") return;
|
|
2243
|
+
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
2244
|
+
if (currentPage < totalPages) {
|
|
2245
|
+
e.preventDefault();
|
|
2246
|
+
container.scrollTop = 0;
|
|
2247
|
+
renderPage(currentPage + 1);
|
|
2248
|
+
}
|
|
2249
|
+
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
2250
|
+
if (currentPage > 1) {
|
|
2251
|
+
e.preventDefault();
|
|
2252
|
+
container.scrollTop = 0;
|
|
2253
|
+
renderPage(currentPage - 1);
|
|
2254
|
+
}
|
|
2255
|
+
} else if (e.key === "Home") {
|
|
2256
|
+
e.preventDefault();
|
|
2257
|
+
container.scrollTop = 0;
|
|
2258
|
+
renderPage(1);
|
|
2259
|
+
} else if (e.key === "End") {
|
|
2260
|
+
e.preventDefault();
|
|
2261
|
+
container.scrollTop = 0;
|
|
2262
|
+
renderPage(totalPages);
|
|
2263
|
+
}
|
|
2264
|
+
};
|
|
2265
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1702
2266
|
const cleanup = () => {
|
|
1703
2267
|
resizeObserver.disconnect();
|
|
2268
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
2269
|
+
container.removeEventListener("wheel", onWheel);
|
|
1704
2270
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1705
2271
|
if (currentRenderTask) {
|
|
1706
2272
|
try {
|
|
@@ -1719,22 +2285,26 @@ var PdfPlugin = class {
|
|
|
1719
2285
|
const instance = {
|
|
1720
2286
|
destroy: cleanup,
|
|
1721
2287
|
zoomIn: () => {
|
|
1722
|
-
zoomScale = Math.min(
|
|
2288
|
+
zoomScale = Math.min(4, Math.round((zoomScale + 0.2) * 10) / 10);
|
|
1723
2289
|
renderPage(currentPage);
|
|
1724
2290
|
},
|
|
1725
2291
|
zoomOut: () => {
|
|
1726
|
-
zoomScale = Math.max(0.
|
|
2292
|
+
zoomScale = Math.max(0.25, Math.round((zoomScale - 0.2) * 10) / 10);
|
|
1727
2293
|
renderPage(currentPage);
|
|
1728
2294
|
},
|
|
1729
2295
|
getZoom: () => zoomScale,
|
|
1730
2296
|
setZoom: (level) => {
|
|
1731
|
-
zoomScale = Math.max(0.
|
|
2297
|
+
zoomScale = Math.max(0.25, Math.min(4, level));
|
|
1732
2298
|
renderPage(currentPage);
|
|
1733
2299
|
},
|
|
1734
2300
|
fitToPage: () => {
|
|
1735
|
-
fitMode =
|
|
2301
|
+
fitMode = "page";
|
|
2302
|
+
zoomScale = 1;
|
|
2303
|
+
renderPage(currentPage);
|
|
2304
|
+
},
|
|
2305
|
+
fitToWidth: () => {
|
|
2306
|
+
fitMode = "width";
|
|
1736
2307
|
zoomScale = 1;
|
|
1737
|
-
rotation = 0;
|
|
1738
2308
|
renderPage(currentPage);
|
|
1739
2309
|
},
|
|
1740
2310
|
rotateCW: () => {
|
|
@@ -1752,6 +2322,9 @@ var PdfPlugin = class {
|
|
|
1752
2322
|
container.scrollTop = 0;
|
|
1753
2323
|
renderPage(page);
|
|
1754
2324
|
},
|
|
2325
|
+
toggleThumbnails: () => {
|
|
2326
|
+
ctx?.toggleThumbnails?.();
|
|
2327
|
+
},
|
|
1755
2328
|
download: () => {
|
|
1756
2329
|
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1757
2330
|
const url = URL.createObjectURL(blob);
|
|
@@ -1785,7 +2358,7 @@ var PdfPlugin = class {
|
|
|
1785
2358
|
},
|
|
1786
2359
|
getThumbnails: async () => {
|
|
1787
2360
|
const thumbnails = [];
|
|
1788
|
-
const count =
|
|
2361
|
+
const count = totalPages;
|
|
1789
2362
|
for (let i = 1; i <= count; i++) {
|
|
1790
2363
|
thumbnails.push({
|
|
1791
2364
|
index: i,
|
|
@@ -1793,9 +2366,10 @@ var PdfPlugin = class {
|
|
|
1793
2366
|
render: async (thumbCanvas) => {
|
|
1794
2367
|
try {
|
|
1795
2368
|
const p = await pdfDoc.getPage(i);
|
|
1796
|
-
const baseVp = p.getViewport({ scale: 1 });
|
|
1797
|
-
const
|
|
1798
|
-
const
|
|
2369
|
+
const baseVp = p.getViewport({ scale: 1, rotation });
|
|
2370
|
+
const targetW = thumbCanvas.width || 130;
|
|
2371
|
+
const thumbScale = targetW / baseVp.width;
|
|
2372
|
+
const thumbVp = p.getViewport({ scale: thumbScale, rotation });
|
|
1799
2373
|
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1800
2374
|
const tCtx = thumbCanvas.getContext("2d");
|
|
1801
2375
|
if (tCtx) {
|
|
@@ -2139,28 +2713,26 @@ var DocxPlugin = class {
|
|
|
2139
2713
|
getToolbarActions(instance) {
|
|
2140
2714
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2141
2715
|
const actions = [];
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
if (
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
instance.goToPage?.(page);
|
|
2160
|
-
}
|
|
2716
|
+
actions.push({
|
|
2717
|
+
id: "page-nav",
|
|
2718
|
+
icon: "",
|
|
2719
|
+
label: "Page Navigation",
|
|
2720
|
+
type: "page-nav",
|
|
2721
|
+
group: "navigation",
|
|
2722
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2723
|
+
max: totalPages,
|
|
2724
|
+
execute: (action, page) => {
|
|
2725
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2726
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2727
|
+
if (action === "prev") {
|
|
2728
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2729
|
+
} else if (action === "next") {
|
|
2730
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2731
|
+
} else if (typeof page === "number") {
|
|
2732
|
+
instance.goToPage?.(page);
|
|
2161
2733
|
}
|
|
2162
|
-
}
|
|
2163
|
-
}
|
|
2734
|
+
}
|
|
2735
|
+
});
|
|
2164
2736
|
actions.push(
|
|
2165
2737
|
{
|
|
2166
2738
|
id: "zoom-out",
|
|
@@ -2226,11 +2798,17 @@ var DocxPlugin = class {
|
|
|
2226
2798
|
wrapper.className = "fp-docx-wrapper";
|
|
2227
2799
|
wrapper.style.transformOrigin = "top center";
|
|
2228
2800
|
wrapper.style.transition = "transform 0.2s ease";
|
|
2229
|
-
wrapper.style.padding = "
|
|
2230
|
-
wrapper.style.maxWidth = "
|
|
2801
|
+
wrapper.style.padding = "0";
|
|
2802
|
+
wrapper.style.maxWidth = "none";
|
|
2803
|
+
wrapper.style.width = "816px";
|
|
2231
2804
|
wrapper.style.margin = "0 auto";
|
|
2805
|
+
wrapper.style.display = "flex";
|
|
2806
|
+
wrapper.style.flexDirection = "column";
|
|
2807
|
+
wrapper.style.alignItems = "center";
|
|
2232
2808
|
wrapper.style.boxSizing = "border-box";
|
|
2233
|
-
ctx.container.style.
|
|
2809
|
+
ctx.container.style.overflowX = "hidden";
|
|
2810
|
+
ctx.container.style.overflowY = "auto";
|
|
2811
|
+
ctx.container.style.padding = "16px 8px";
|
|
2234
2812
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
2235
2813
|
ctx.container.appendChild(wrapper);
|
|
2236
2814
|
const styleOverride = document.createElement("style");
|
|
@@ -2404,39 +2982,13 @@ var DocxPlugin = class {
|
|
|
2404
2982
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2405
2983
|
const totalPages = Math.max(1, pageElements.length);
|
|
2406
2984
|
let currentPage = 1;
|
|
2407
|
-
let indicator = null;
|
|
2408
|
-
if (totalPages > 1) {
|
|
2409
|
-
indicator = document.createElement("div");
|
|
2410
|
-
indicator.className = "fp-docx-page-indicator";
|
|
2411
|
-
indicator.style.position = "sticky";
|
|
2412
|
-
indicator.style.bottom = "16px";
|
|
2413
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2414
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
2415
|
-
indicator.style.color = "#f8fafc";
|
|
2416
|
-
indicator.style.fontSize = "12px";
|
|
2417
|
-
indicator.style.fontWeight = "600";
|
|
2418
|
-
indicator.style.padding = "5px 14px";
|
|
2419
|
-
indicator.style.borderRadius = "20px";
|
|
2420
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2421
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2422
|
-
indicator.style.zIndex = "10";
|
|
2423
|
-
indicator.style.userSelect = "none";
|
|
2424
|
-
indicator.style.pointerEvents = "none";
|
|
2425
|
-
indicator.style.textAlign = "center";
|
|
2426
|
-
indicator.style.width = "fit-content";
|
|
2427
|
-
indicator.style.margin = "16px auto 0";
|
|
2428
|
-
ctx.container.appendChild(indicator);
|
|
2429
|
-
}
|
|
2430
2985
|
const showPage = (pageNum) => {
|
|
2431
2986
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2432
2987
|
if (pageElements.length > 1) {
|
|
2433
2988
|
pageElements.forEach((sec, idx) => {
|
|
2434
|
-
sec.style.display = idx + 1 === currentPage ? "
|
|
2989
|
+
sec.style.display = idx + 1 === currentPage ? "" : "none";
|
|
2435
2990
|
});
|
|
2436
2991
|
}
|
|
2437
|
-
if (indicator) {
|
|
2438
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2439
|
-
}
|
|
2440
2992
|
ctx.container.scrollTop = 0;
|
|
2441
2993
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2442
2994
|
};
|
|
@@ -2445,31 +2997,46 @@ var DocxPlugin = class {
|
|
|
2445
2997
|
}
|
|
2446
2998
|
scale = 1;
|
|
2447
2999
|
let rotation = 0;
|
|
2448
|
-
let fitMode = "
|
|
2449
|
-
|
|
2450
|
-
|
|
3000
|
+
let fitMode = "page";
|
|
3001
|
+
let isUserZoomed = false;
|
|
3002
|
+
const calculateFitScale = (_mode = fitMode) => {
|
|
3003
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
2451
3004
|
const elW = activeEl.offsetWidth || 816;
|
|
2452
|
-
const
|
|
2453
|
-
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
2454
|
-
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
3005
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
2455
3006
|
const sW = availW / elW;
|
|
2456
|
-
|
|
2457
|
-
if (mode === "page") {
|
|
2458
|
-
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
2459
|
-
}
|
|
2460
|
-
return Math.max(0.65, Math.min(1.05, sW));
|
|
3007
|
+
return Math.max(0.35, Math.min(3, sW));
|
|
2461
3008
|
};
|
|
2462
3009
|
const applyTransform = () => {
|
|
2463
3010
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2464
3011
|
wrapper.style.transformOrigin = "top center";
|
|
3012
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
3013
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
3014
|
+
if (scale > 1) {
|
|
3015
|
+
wrapper.style.marginBottom = `${Math.round(elH * scale - elH + 32)}px`;
|
|
3016
|
+
} else {
|
|
3017
|
+
wrapper.style.marginBottom = "32px";
|
|
3018
|
+
}
|
|
2465
3019
|
};
|
|
3020
|
+
let resizeObserver = null;
|
|
3021
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
3022
|
+
resizeObserver = new ResizeObserver(() => {
|
|
3023
|
+
if (!isUserZoomed) {
|
|
3024
|
+
const newFit = calculateFitScale("page");
|
|
3025
|
+
if (Math.abs(scale - newFit) > 0.015) {
|
|
3026
|
+
scale = newFit;
|
|
3027
|
+
applyTransform();
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
});
|
|
3031
|
+
resizeObserver.observe(ctx.container);
|
|
3032
|
+
}
|
|
2466
3033
|
setTimeout(() => {
|
|
2467
|
-
|
|
2468
|
-
scale = calculateFitScale("width");
|
|
3034
|
+
scale = calculateFitScale("page");
|
|
2469
3035
|
applyTransform();
|
|
2470
|
-
},
|
|
3036
|
+
}, 40);
|
|
2471
3037
|
const cleanup = () => {
|
|
2472
|
-
|
|
3038
|
+
resizeObserver?.disconnect();
|
|
3039
|
+
resizeObserver = null;
|
|
2473
3040
|
for (const url of createdBlobUrls) {
|
|
2474
3041
|
URL.revokeObjectURL(url);
|
|
2475
3042
|
}
|
|
@@ -2486,21 +3053,24 @@ var DocxPlugin = class {
|
|
|
2486
3053
|
showPage(page);
|
|
2487
3054
|
},
|
|
2488
3055
|
zoomIn: () => {
|
|
2489
|
-
|
|
3056
|
+
isUserZoomed = true;
|
|
3057
|
+
scale = Math.min(3.5, scale + 0.15);
|
|
2490
3058
|
applyTransform();
|
|
2491
3059
|
},
|
|
2492
3060
|
zoomOut: () => {
|
|
3061
|
+
isUserZoomed = true;
|
|
2493
3062
|
scale = Math.max(0.2, scale - 0.15);
|
|
2494
3063
|
applyTransform();
|
|
2495
3064
|
},
|
|
2496
3065
|
getZoom: () => scale,
|
|
2497
3066
|
setZoom: (level) => {
|
|
3067
|
+
isUserZoomed = true;
|
|
2498
3068
|
scale = level;
|
|
2499
3069
|
applyTransform();
|
|
2500
3070
|
},
|
|
2501
3071
|
fitToPage: () => {
|
|
2502
|
-
|
|
2503
|
-
scale = calculateFitScale(
|
|
3072
|
+
isUserZoomed = false;
|
|
3073
|
+
scale = calculateFitScale("page");
|
|
2504
3074
|
rotation = 0;
|
|
2505
3075
|
applyTransform();
|
|
2506
3076
|
},
|
|
@@ -2890,7 +3460,7 @@ var ExcelPlugin = class {
|
|
|
2890
3460
|
"application/vnd.ms-excel.template.macroEnabled.12",
|
|
2891
3461
|
"application/vnd.oasis.opendocument.spreadsheet"
|
|
2892
3462
|
];
|
|
2893
|
-
weight =
|
|
3463
|
+
weight = 85;
|
|
2894
3464
|
supports(file) {
|
|
2895
3465
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2896
3466
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
@@ -2902,6 +3472,14 @@ var ExcelPlugin = class {
|
|
|
2902
3472
|
getToolbarActions(instance) {
|
|
2903
3473
|
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2904
3474
|
const actions = [];
|
|
3475
|
+
actions.push({
|
|
3476
|
+
id: "thumbnails",
|
|
3477
|
+
icon: "thumbnails",
|
|
3478
|
+
label: "Sheet Thumbnails",
|
|
3479
|
+
type: "button",
|
|
3480
|
+
group: "navigation",
|
|
3481
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3482
|
+
});
|
|
2905
3483
|
if (totalSheets > 1) {
|
|
2906
3484
|
actions.push({
|
|
2907
3485
|
id: "page-nav",
|
|
@@ -2984,6 +3562,16 @@ var ExcelPlugin = class {
|
|
|
2984
3562
|
execute: () => {
|
|
2985
3563
|
instance.print?.();
|
|
2986
3564
|
}
|
|
3565
|
+
},
|
|
3566
|
+
{
|
|
3567
|
+
id: "open-window",
|
|
3568
|
+
icon: "open-window",
|
|
3569
|
+
label: "Open in Separate Full Window",
|
|
3570
|
+
type: "button",
|
|
3571
|
+
group: "actions",
|
|
3572
|
+
execute: () => {
|
|
3573
|
+
instance.openInSeparateWindow?.();
|
|
3574
|
+
}
|
|
2987
3575
|
}
|
|
2988
3576
|
);
|
|
2989
3577
|
return actions;
|
|
@@ -3149,6 +3737,63 @@ var ExcelPlugin = class {
|
|
|
3149
3737
|
},
|
|
3150
3738
|
getPageCount: () => sheetNames.length,
|
|
3151
3739
|
getCurrentPage: () => currentSheetIndex,
|
|
3740
|
+
getThumbnails: () => {
|
|
3741
|
+
return sheetNames.map((name, idx) => ({
|
|
3742
|
+
index: idx,
|
|
3743
|
+
label: name,
|
|
3744
|
+
render: async (canvas) => {
|
|
3745
|
+
canvas.width = 140;
|
|
3746
|
+
canvas.height = 100;
|
|
3747
|
+
const c = canvas.getContext("2d");
|
|
3748
|
+
if (!c) return;
|
|
3749
|
+
c.fillStyle = "#ffffff";
|
|
3750
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
3751
|
+
c.fillStyle = "#107c41";
|
|
3752
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
3753
|
+
c.fillStyle = "#ffffff";
|
|
3754
|
+
c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
3755
|
+
c.fillText(`\u{1F4CA} ${name.slice(0, 16)}`, 6, 11);
|
|
3756
|
+
const startY = 17;
|
|
3757
|
+
const rowH = 13;
|
|
3758
|
+
const colW = 30;
|
|
3759
|
+
const colHeaders = ["A", "B", "C", "D"];
|
|
3760
|
+
c.fillStyle = "#f1f5f9";
|
|
3761
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
3762
|
+
c.strokeStyle = "#cbd5e1";
|
|
3763
|
+
c.lineWidth = 0.8;
|
|
3764
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
3765
|
+
c.fillStyle = "#64748b";
|
|
3766
|
+
c.font = "bold 7px sans-serif";
|
|
3767
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3768
|
+
c.fillText(colHeaders[ci], 14 + ci * colW, startY + 9);
|
|
3769
|
+
}
|
|
3770
|
+
const ws = wb?.Sheets[name];
|
|
3771
|
+
for (let ri = 1; ri <= 5; ri++) {
|
|
3772
|
+
const y = startY + ri * rowH;
|
|
3773
|
+
if (y > canvas.height - 2) break;
|
|
3774
|
+
c.fillStyle = "#f8fafc";
|
|
3775
|
+
c.fillRect(0, y, 12, rowH);
|
|
3776
|
+
c.fillStyle = "#94a3b8";
|
|
3777
|
+
c.font = "6px sans-serif";
|
|
3778
|
+
c.fillText(String(ri), 3, y + 9);
|
|
3779
|
+
c.strokeStyle = "#e2e8f0";
|
|
3780
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
3781
|
+
c.fillStyle = "#334155";
|
|
3782
|
+
c.font = "6px sans-serif";
|
|
3783
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3784
|
+
const cellRef = `${colHeaders[ci]}${ri}`;
|
|
3785
|
+
const cellVal = ws?.[cellRef]?.w || ws?.[cellRef]?.v;
|
|
3786
|
+
if (cellVal !== void 0) {
|
|
3787
|
+
c.fillText(String(cellVal).slice(0, 6), 14 + ci * colW, y + 9);
|
|
3788
|
+
}
|
|
3789
|
+
}
|
|
3790
|
+
}
|
|
3791
|
+
c.strokeStyle = "#cbd5e1";
|
|
3792
|
+
c.lineWidth = 1;
|
|
3793
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
3794
|
+
}
|
|
3795
|
+
}));
|
|
3796
|
+
},
|
|
3152
3797
|
download: () => {
|
|
3153
3798
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
3154
3799
|
const url = URL.createObjectURL(blob);
|
|
@@ -3181,7 +3826,39 @@ var CsvPlugin = class {
|
|
|
3181
3826
|
return ext === ".csv" || ext === ".tsv" || mime === "text/csv" || mime === "text/tab-separated-values";
|
|
3182
3827
|
}
|
|
3183
3828
|
getToolbarActions(instance) {
|
|
3184
|
-
|
|
3829
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3830
|
+
const actions = [];
|
|
3831
|
+
actions.push({
|
|
3832
|
+
id: "thumbnails",
|
|
3833
|
+
icon: "thumbnails",
|
|
3834
|
+
label: "Page Thumbnails",
|
|
3835
|
+
type: "button",
|
|
3836
|
+
group: "navigation",
|
|
3837
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3838
|
+
});
|
|
3839
|
+
if (totalPages > 1) {
|
|
3840
|
+
actions.push({
|
|
3841
|
+
id: "page-nav",
|
|
3842
|
+
icon: "",
|
|
3843
|
+
label: "Page Navigation",
|
|
3844
|
+
type: "page-nav",
|
|
3845
|
+
group: "navigation",
|
|
3846
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3847
|
+
max: totalPages,
|
|
3848
|
+
execute: (action, page) => {
|
|
3849
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3850
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
3851
|
+
if (action === "prev") {
|
|
3852
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3853
|
+
} else if (action === "next") {
|
|
3854
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
3855
|
+
} else if (typeof page === "number") {
|
|
3856
|
+
instance.goToPage?.(page);
|
|
3857
|
+
}
|
|
3858
|
+
}
|
|
3859
|
+
});
|
|
3860
|
+
}
|
|
3861
|
+
actions.push(
|
|
3185
3862
|
{
|
|
3186
3863
|
id: "zoom-out",
|
|
3187
3864
|
icon: "zoom-out",
|
|
@@ -3202,6 +3879,16 @@ var CsvPlugin = class {
|
|
|
3202
3879
|
instance.zoomIn?.();
|
|
3203
3880
|
}
|
|
3204
3881
|
},
|
|
3882
|
+
{
|
|
3883
|
+
id: "fit-page",
|
|
3884
|
+
icon: "fit-page",
|
|
3885
|
+
label: "Fit to View",
|
|
3886
|
+
type: "button",
|
|
3887
|
+
group: "zoom",
|
|
3888
|
+
execute: () => {
|
|
3889
|
+
instance.fitToPage?.();
|
|
3890
|
+
}
|
|
3891
|
+
},
|
|
3205
3892
|
{
|
|
3206
3893
|
id: "download",
|
|
3207
3894
|
icon: "download",
|
|
@@ -3219,10 +3906,21 @@ var CsvPlugin = class {
|
|
|
3219
3906
|
type: "button",
|
|
3220
3907
|
group: "actions",
|
|
3221
3908
|
execute: () => {
|
|
3222
|
-
instance.print?.();
|
|
3909
|
+
instance.print?.();
|
|
3910
|
+
}
|
|
3911
|
+
},
|
|
3912
|
+
{
|
|
3913
|
+
id: "open-window",
|
|
3914
|
+
icon: "open-window",
|
|
3915
|
+
label: "Open in Separate Full Window",
|
|
3916
|
+
type: "button",
|
|
3917
|
+
group: "actions",
|
|
3918
|
+
execute: () => {
|
|
3919
|
+
instance.openInSeparateWindow?.();
|
|
3223
3920
|
}
|
|
3224
3921
|
}
|
|
3225
|
-
|
|
3922
|
+
);
|
|
3923
|
+
return actions;
|
|
3226
3924
|
}
|
|
3227
3925
|
async render(ctx) {
|
|
3228
3926
|
const decoder = new TextDecoder("utf-8");
|
|
@@ -3234,33 +3932,62 @@ var CsvPlugin = class {
|
|
|
3234
3932
|
container.style.padding = "16px";
|
|
3235
3933
|
container.style.boxSizing = "border-box";
|
|
3236
3934
|
container.style.transformOrigin = "top left";
|
|
3935
|
+
const delimiter = ctx.metadata.extension === ".tsv" ? " " : ",";
|
|
3936
|
+
const allLines = text.split(/\r?\n/).filter((r) => r.trim().length > 0);
|
|
3937
|
+
const headerLine = allLines[0] || "";
|
|
3938
|
+
const headerCells = headerLine.split(delimiter);
|
|
3939
|
+
const dataLines = allLines.slice(1);
|
|
3940
|
+
const ROWS_PER_PAGE = 100;
|
|
3941
|
+
const totalPages = Math.max(1, Math.ceil(dataLines.length / ROWS_PER_PAGE));
|
|
3942
|
+
let currentPage = 1;
|
|
3237
3943
|
const table = document.createElement("table");
|
|
3238
3944
|
table.style.borderCollapse = "collapse";
|
|
3239
3945
|
table.style.width = "100%";
|
|
3240
|
-
table.style.fontFamily = "monospace
|
|
3946
|
+
table.style.fontFamily = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace';
|
|
3241
3947
|
table.style.fontSize = "13px";
|
|
3242
|
-
const
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
td.style.fontWeight = "bold";
|
|
3256
|
-
}
|
|
3257
|
-
tr.appendChild(td);
|
|
3948
|
+
const renderPage = (pageNum) => {
|
|
3949
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3950
|
+
table.innerHTML = "";
|
|
3951
|
+
const headerTr = document.createElement("tr");
|
|
3952
|
+
headerCells.forEach((cell) => {
|
|
3953
|
+
const th = document.createElement("th");
|
|
3954
|
+
th.textContent = cell.trim();
|
|
3955
|
+
th.style.border = "1px solid #d0d7de";
|
|
3956
|
+
th.style.padding = "8px 12px";
|
|
3957
|
+
th.style.backgroundColor = "#f6f8fa";
|
|
3958
|
+
th.style.fontWeight = "600";
|
|
3959
|
+
th.style.whiteSpace = "nowrap";
|
|
3960
|
+
headerTr.appendChild(th);
|
|
3258
3961
|
});
|
|
3259
|
-
table.appendChild(
|
|
3260
|
-
|
|
3962
|
+
table.appendChild(headerTr);
|
|
3963
|
+
const start = (currentPage - 1) * ROWS_PER_PAGE;
|
|
3964
|
+
const end = Math.min(dataLines.length, start + ROWS_PER_PAGE);
|
|
3965
|
+
const pageRows = dataLines.slice(start, end);
|
|
3966
|
+
pageRows.forEach((row, idx) => {
|
|
3967
|
+
const tr = document.createElement("tr");
|
|
3968
|
+
if (idx % 2 === 1) tr.style.backgroundColor = "#f8fafc";
|
|
3969
|
+
const cells = row.split(delimiter);
|
|
3970
|
+
cells.forEach((cell) => {
|
|
3971
|
+
const td = document.createElement("td");
|
|
3972
|
+
td.textContent = cell.trim();
|
|
3973
|
+
td.style.border = "1px solid #d0d7de";
|
|
3974
|
+
td.style.padding = "6px 12px";
|
|
3975
|
+
td.style.whiteSpace = "nowrap";
|
|
3976
|
+
tr.appendChild(td);
|
|
3977
|
+
});
|
|
3978
|
+
table.appendChild(tr);
|
|
3979
|
+
});
|
|
3980
|
+
container.scrollTop = 0;
|
|
3981
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3982
|
+
};
|
|
3983
|
+
renderPage(1);
|
|
3261
3984
|
container.appendChild(table);
|
|
3262
3985
|
ctx.container.appendChild(container);
|
|
3263
3986
|
let scale = 1;
|
|
3987
|
+
const applyScale = () => {
|
|
3988
|
+
container.style.transform = `scale(${scale})`;
|
|
3989
|
+
container.style.transformOrigin = "top left";
|
|
3990
|
+
};
|
|
3264
3991
|
const cleanup = () => {
|
|
3265
3992
|
container.remove();
|
|
3266
3993
|
ctx.container.innerHTML = "";
|
|
@@ -3268,22 +3995,86 @@ var CsvPlugin = class {
|
|
|
3268
3995
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3269
3996
|
return {
|
|
3270
3997
|
destroy: cleanup,
|
|
3998
|
+
getPageCount: () => totalPages,
|
|
3999
|
+
getCurrentPage: () => currentPage,
|
|
4000
|
+
goToPage: (page) => renderPage(page),
|
|
4001
|
+
getThumbnails: () => {
|
|
4002
|
+
const thumbnails = [];
|
|
4003
|
+
for (let i = 0; i < totalPages; i++) {
|
|
4004
|
+
const pageIdx = i;
|
|
4005
|
+
const startRow = pageIdx * ROWS_PER_PAGE + 1;
|
|
4006
|
+
const endRow = Math.min(dataLines.length, (pageIdx + 1) * ROWS_PER_PAGE);
|
|
4007
|
+
const label = totalPages === 1 ? "Table" : `Page ${pageIdx + 1} (${startRow}-${endRow})`;
|
|
4008
|
+
thumbnails.push({
|
|
4009
|
+
index: pageIdx,
|
|
4010
|
+
label,
|
|
4011
|
+
render: async (canvas) => {
|
|
4012
|
+
canvas.width = 140;
|
|
4013
|
+
canvas.height = 100;
|
|
4014
|
+
const c = canvas.getContext("2d");
|
|
4015
|
+
if (!c) return;
|
|
4016
|
+
c.fillStyle = "#ffffff";
|
|
4017
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4018
|
+
c.fillStyle = "#2563eb";
|
|
4019
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
4020
|
+
c.fillStyle = "#ffffff";
|
|
4021
|
+
c.font = "bold 8px sans-serif";
|
|
4022
|
+
c.fillText(`\u{1F4C8} ${label.slice(0, 18)}`, 6, 11);
|
|
4023
|
+
const startY = 17;
|
|
4024
|
+
const rowH = 13;
|
|
4025
|
+
const colW = 28;
|
|
4026
|
+
const cols = Math.min(4, headerCells.length || 4);
|
|
4027
|
+
c.fillStyle = "#f1f5f9";
|
|
4028
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
4029
|
+
c.strokeStyle = "#cbd5e1";
|
|
4030
|
+
c.lineWidth = 0.8;
|
|
4031
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
4032
|
+
c.fillStyle = "#64748b";
|
|
4033
|
+
c.font = "bold 7px sans-serif";
|
|
4034
|
+
for (let ci = 0; ci < cols; ci++) {
|
|
4035
|
+
const hName = headerCells[ci] || `Col ${ci + 1}`;
|
|
4036
|
+
c.fillText(hName.slice(0, 5), 8 + ci * colW, startY + 9);
|
|
4037
|
+
}
|
|
4038
|
+
const rowsToPreview = dataLines.slice(pageIdx * ROWS_PER_PAGE, pageIdx * ROWS_PER_PAGE + 5);
|
|
4039
|
+
for (let ri = 0; ri < rowsToPreview.length; ri++) {
|
|
4040
|
+
const y = startY + (ri + 1) * rowH;
|
|
4041
|
+
if (y > canvas.height - 2) break;
|
|
4042
|
+
c.strokeStyle = "#e2e8f0";
|
|
4043
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
4044
|
+
const cVals = rowsToPreview[ri].split(delimiter);
|
|
4045
|
+
c.fillStyle = "#334155";
|
|
4046
|
+
c.font = "6px sans-serif";
|
|
4047
|
+
for (let ci = 0; ci < cols; ci++) {
|
|
4048
|
+
const val = cVals[ci] || "";
|
|
4049
|
+
c.fillText(val.trim().slice(0, 6), 8 + ci * colW, y + 9);
|
|
4050
|
+
}
|
|
4051
|
+
}
|
|
4052
|
+
c.strokeStyle = "#cbd5e1";
|
|
4053
|
+
c.lineWidth = 1;
|
|
4054
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4055
|
+
}
|
|
4056
|
+
});
|
|
4057
|
+
}
|
|
4058
|
+
return thumbnails;
|
|
4059
|
+
},
|
|
3271
4060
|
zoomIn: () => {
|
|
3272
4061
|
scale += 0.1;
|
|
3273
|
-
|
|
4062
|
+
applyScale();
|
|
3274
4063
|
},
|
|
3275
4064
|
zoomOut: () => {
|
|
3276
4065
|
scale = Math.max(0.2, scale - 0.1);
|
|
3277
|
-
|
|
4066
|
+
applyScale();
|
|
3278
4067
|
},
|
|
3279
4068
|
getZoom: () => scale,
|
|
3280
4069
|
setZoom: (level) => {
|
|
3281
4070
|
scale = level;
|
|
3282
|
-
|
|
4071
|
+
applyScale();
|
|
3283
4072
|
},
|
|
3284
4073
|
fitToPage: () => {
|
|
3285
|
-
|
|
3286
|
-
|
|
4074
|
+
const availW = Math.max(280, (ctx.container.clientWidth || window.innerWidth) - 48);
|
|
4075
|
+
const tW = table.offsetWidth || 600;
|
|
4076
|
+
scale = Math.max(0.35, Math.min(1, availW / tW));
|
|
4077
|
+
applyScale();
|
|
3287
4078
|
},
|
|
3288
4079
|
download: () => {
|
|
3289
4080
|
const blob = new Blob([ctx.buffer], { type: "text/csv" });
|
|
@@ -3347,28 +4138,34 @@ var CodePlugin = class {
|
|
|
3347
4138
|
getToolbarActions(instance) {
|
|
3348
4139
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3349
4140
|
const actions = [];
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
4141
|
+
actions.push({
|
|
4142
|
+
id: "thumbnails",
|
|
4143
|
+
icon: "thumbnails",
|
|
4144
|
+
label: "Page Thumbnails",
|
|
4145
|
+
type: "button",
|
|
4146
|
+
group: "navigation",
|
|
4147
|
+
execute: () => instance.toggleThumbnails?.()
|
|
4148
|
+
});
|
|
4149
|
+
actions.push({
|
|
4150
|
+
id: "page-nav",
|
|
4151
|
+
icon: "",
|
|
4152
|
+
label: "Page Navigation",
|
|
4153
|
+
type: "page-nav",
|
|
4154
|
+
group: "navigation",
|
|
4155
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4156
|
+
max: totalPages,
|
|
4157
|
+
execute: (action, page) => {
|
|
4158
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4159
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4160
|
+
if (action === "prev") {
|
|
4161
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4162
|
+
} else if (action === "next") {
|
|
4163
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4164
|
+
} else if (typeof page === "number") {
|
|
4165
|
+
instance.goToPage?.(page);
|
|
3369
4166
|
}
|
|
3370
|
-
}
|
|
3371
|
-
}
|
|
4167
|
+
}
|
|
4168
|
+
});
|
|
3372
4169
|
actions.push(
|
|
3373
4170
|
{
|
|
3374
4171
|
id: "zoom-out",
|
|
@@ -3512,16 +4309,19 @@ var CodePlugin = class {
|
|
|
3512
4309
|
let fontSize = 13;
|
|
3513
4310
|
let rotation = 0;
|
|
3514
4311
|
let zoomLevel = 1;
|
|
4312
|
+
let isUserZoomed = false;
|
|
3515
4313
|
const pre = document.createElement("pre");
|
|
3516
4314
|
const code = document.createElement("code");
|
|
3517
4315
|
if (isTxt) {
|
|
4316
|
+
container.style.overflowX = "hidden";
|
|
4317
|
+
container.style.overflowY = "auto";
|
|
3518
4318
|
container.style.backgroundColor = "#f1f5f9";
|
|
3519
|
-
container.style.padding = "
|
|
4319
|
+
container.style.padding = "16px 8px";
|
|
3520
4320
|
container.style.boxSizing = "border-box";
|
|
3521
4321
|
container.style.display = "flex";
|
|
3522
4322
|
container.style.flexDirection = "column";
|
|
3523
4323
|
container.style.alignItems = "center";
|
|
3524
|
-
pre.style.margin = "0";
|
|
4324
|
+
pre.style.margin = "0 auto";
|
|
3525
4325
|
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3526
4326
|
pre.style.fontSize = "13px";
|
|
3527
4327
|
pre.style.color = "#1e293b";
|
|
@@ -3533,10 +4333,12 @@ var CodePlugin = class {
|
|
|
3533
4333
|
pre.style.minHeight = "1056px";
|
|
3534
4334
|
pre.style.padding = "72px 56px";
|
|
3535
4335
|
pre.style.boxSizing = "border-box";
|
|
3536
|
-
pre.style.boxShadow = "0 4px
|
|
4336
|
+
pre.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
3537
4337
|
pre.style.borderRadius = "4px";
|
|
3538
4338
|
pre.style.transformOrigin = "top center";
|
|
4339
|
+
pre.style.transition = "transform 0.15s ease";
|
|
3539
4340
|
} else {
|
|
4341
|
+
container.style.overflow = "auto";
|
|
3540
4342
|
container.style.backgroundColor = "#1e1e1e";
|
|
3541
4343
|
container.style.color = "#d4d4d4";
|
|
3542
4344
|
container.style.padding = "16px";
|
|
@@ -3568,42 +4370,9 @@ var CodePlugin = class {
|
|
|
3568
4370
|
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
3569
4371
|
pre.appendChild(code);
|
|
3570
4372
|
container.appendChild(pre);
|
|
3571
|
-
let indicator = null;
|
|
3572
|
-
if (totalPages > 1) {
|
|
3573
|
-
indicator = document.createElement("div");
|
|
3574
|
-
indicator.className = "fp-code-page-indicator";
|
|
3575
|
-
indicator.style.position = "sticky";
|
|
3576
|
-
indicator.style.bottom = "16px";
|
|
3577
|
-
if (isTxt) {
|
|
3578
|
-
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3579
|
-
indicator.style.color = "#334155";
|
|
3580
|
-
indicator.style.border = "1px solid #e2e8f0";
|
|
3581
|
-
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3582
|
-
} else {
|
|
3583
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3584
|
-
indicator.style.color = "#f8fafc";
|
|
3585
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3586
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3587
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
3588
|
-
}
|
|
3589
|
-
indicator.style.fontSize = "12px";
|
|
3590
|
-
indicator.style.fontWeight = "600";
|
|
3591
|
-
indicator.style.padding = "5px 14px";
|
|
3592
|
-
indicator.style.borderRadius = "20px";
|
|
3593
|
-
indicator.style.zIndex = "10";
|
|
3594
|
-
indicator.style.userSelect = "none";
|
|
3595
|
-
indicator.style.pointerEvents = "none";
|
|
3596
|
-
indicator.style.textAlign = "center";
|
|
3597
|
-
indicator.style.width = "fit-content";
|
|
3598
|
-
indicator.style.margin = "16px auto 0";
|
|
3599
|
-
container.appendChild(indicator);
|
|
3600
|
-
}
|
|
3601
4373
|
const showPage = (pageNum) => {
|
|
3602
4374
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3603
4375
|
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
3604
|
-
if (indicator) {
|
|
3605
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3606
|
-
}
|
|
3607
4376
|
container.scrollTop = 0;
|
|
3608
4377
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3609
4378
|
};
|
|
@@ -3611,36 +4380,90 @@ var CodePlugin = class {
|
|
|
3611
4380
|
showPage(1);
|
|
3612
4381
|
}
|
|
3613
4382
|
ctx.container.appendChild(container);
|
|
3614
|
-
const
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
ctx.container.innerHTML = "";
|
|
4383
|
+
const calculateTxtFit = () => {
|
|
4384
|
+
const availW = Math.max(280, container.clientWidth - 32);
|
|
4385
|
+
return Math.max(0.4, Math.min(3, availW / 816));
|
|
3618
4386
|
};
|
|
3619
|
-
ctx.signal.addEventListener("abort", cleanup);
|
|
3620
4387
|
const updateTransform = () => {
|
|
3621
4388
|
if (isTxt) {
|
|
3622
4389
|
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
4390
|
+
const scaledH = 1056 * zoomLevel;
|
|
4391
|
+
const extraH = Math.max(0, scaledH - 1056);
|
|
4392
|
+
pre.style.marginBottom = `${extraH + 32}px`;
|
|
3623
4393
|
} else {
|
|
3624
4394
|
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3625
4395
|
pre.style.fontSize = `${fontSize}px`;
|
|
3626
4396
|
}
|
|
3627
4397
|
};
|
|
4398
|
+
let resizeObserver = null;
|
|
4399
|
+
if (isTxt) {
|
|
4400
|
+
setTimeout(() => {
|
|
4401
|
+
zoomLevel = calculateTxtFit();
|
|
4402
|
+
updateTransform();
|
|
4403
|
+
}, 60);
|
|
4404
|
+
resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
4405
|
+
if (!isUserZoomed) {
|
|
4406
|
+
zoomLevel = calculateTxtFit();
|
|
4407
|
+
updateTransform();
|
|
4408
|
+
}
|
|
4409
|
+
}) : null;
|
|
4410
|
+
resizeObserver?.observe(container);
|
|
4411
|
+
}
|
|
4412
|
+
const cleanup = () => {
|
|
4413
|
+
resizeObserver?.disconnect();
|
|
4414
|
+
container.remove();
|
|
4415
|
+
ctx.container.innerHTML = "";
|
|
4416
|
+
};
|
|
4417
|
+
ctx.signal.addEventListener("abort", cleanup);
|
|
3628
4418
|
return {
|
|
3629
4419
|
destroy: cleanup,
|
|
3630
4420
|
getPageCount: () => totalPages,
|
|
3631
4421
|
getCurrentPage: () => currentPage,
|
|
3632
4422
|
goToPage: (page) => showPage(page),
|
|
4423
|
+
getThumbnails: () => {
|
|
4424
|
+
return rawPages.map((pageText, idx) => ({
|
|
4425
|
+
index: idx,
|
|
4426
|
+
label: `Page ${idx + 1}`,
|
|
4427
|
+
render: async (canvas) => {
|
|
4428
|
+
canvas.width = 140;
|
|
4429
|
+
canvas.height = 180;
|
|
4430
|
+
const c = canvas.getContext("2d");
|
|
4431
|
+
if (!c) return;
|
|
4432
|
+
c.fillStyle = "#ffffff";
|
|
4433
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4434
|
+
c.strokeStyle = "#cbd5e1";
|
|
4435
|
+
c.lineWidth = 1;
|
|
4436
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4437
|
+
c.fillStyle = "#64748b";
|
|
4438
|
+
const lines = (pageText || "").split("\n").slice(0, 24);
|
|
4439
|
+
const lineH = 6;
|
|
4440
|
+
const startY = 14;
|
|
4441
|
+
const startX = 12;
|
|
4442
|
+
const maxW = canvas.width - 24;
|
|
4443
|
+
c.font = "5px monospace";
|
|
4444
|
+
for (let li = 0; li < lines.length; li++) {
|
|
4445
|
+
const l = lines[li].trim();
|
|
4446
|
+
if (!l) continue;
|
|
4447
|
+
const y = startY + li * lineH;
|
|
4448
|
+
if (y > canvas.height - 12) break;
|
|
4449
|
+
c.fillText(l.slice(0, 30), startX, y, maxW);
|
|
4450
|
+
}
|
|
4451
|
+
}
|
|
4452
|
+
}));
|
|
4453
|
+
},
|
|
3633
4454
|
zoomIn: () => {
|
|
4455
|
+
isUserZoomed = true;
|
|
3634
4456
|
if (isTxt) {
|
|
3635
|
-
zoomLevel = Math.min(3, zoomLevel + 0.
|
|
4457
|
+
zoomLevel = Math.min(3.5, zoomLevel + 0.15);
|
|
3636
4458
|
} else {
|
|
3637
4459
|
fontSize = Math.min(32, fontSize + 2);
|
|
3638
4460
|
}
|
|
3639
4461
|
updateTransform();
|
|
3640
4462
|
},
|
|
3641
4463
|
zoomOut: () => {
|
|
4464
|
+
isUserZoomed = true;
|
|
3642
4465
|
if (isTxt) {
|
|
3643
|
-
zoomLevel = Math.max(0.1, zoomLevel - 0.
|
|
4466
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.15);
|
|
3644
4467
|
} else {
|
|
3645
4468
|
fontSize = Math.max(8, fontSize - 2);
|
|
3646
4469
|
}
|
|
@@ -3648,6 +4471,7 @@ var CodePlugin = class {
|
|
|
3648
4471
|
},
|
|
3649
4472
|
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
3650
4473
|
setZoom: (level) => {
|
|
4474
|
+
isUserZoomed = true;
|
|
3651
4475
|
if (isTxt) {
|
|
3652
4476
|
zoomLevel = level;
|
|
3653
4477
|
} else {
|
|
@@ -3656,9 +4480,10 @@ var CodePlugin = class {
|
|
|
3656
4480
|
updateTransform();
|
|
3657
4481
|
},
|
|
3658
4482
|
fitToPage: () => {
|
|
4483
|
+
isUserZoomed = false;
|
|
3659
4484
|
fontSize = 13;
|
|
3660
4485
|
rotation = 0;
|
|
3661
|
-
zoomLevel = isTxt ?
|
|
4486
|
+
zoomLevel = isTxt ? calculateTxtFit() : 1;
|
|
3662
4487
|
updateTransform();
|
|
3663
4488
|
},
|
|
3664
4489
|
rotateCW: () => {
|
|
@@ -4539,28 +5364,26 @@ var RtfPlugin = class {
|
|
|
4539
5364
|
getToolbarActions(instance) {
|
|
4540
5365
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4541
5366
|
const actions = [];
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
if (
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
instance.goToPage?.(page);
|
|
4560
|
-
}
|
|
5367
|
+
actions.push({
|
|
5368
|
+
id: "page-nav",
|
|
5369
|
+
icon: "",
|
|
5370
|
+
label: "Page Navigation",
|
|
5371
|
+
type: "page-nav",
|
|
5372
|
+
group: "navigation",
|
|
5373
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5374
|
+
max: totalPages,
|
|
5375
|
+
execute: (action, page) => {
|
|
5376
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5377
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5378
|
+
if (action === "prev") {
|
|
5379
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5380
|
+
} else if (action === "next") {
|
|
5381
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5382
|
+
} else if (typeof page === "number") {
|
|
5383
|
+
instance.goToPage?.(page);
|
|
4561
5384
|
}
|
|
4562
|
-
}
|
|
4563
|
-
}
|
|
5385
|
+
}
|
|
5386
|
+
});
|
|
4564
5387
|
actions.push(
|
|
4565
5388
|
{
|
|
4566
5389
|
id: "zoom-out",
|
|
@@ -4632,43 +5455,57 @@ var RtfPlugin = class {
|
|
|
4632
5455
|
async render(ctx) {
|
|
4633
5456
|
const wrapper = document.createElement("div");
|
|
4634
5457
|
wrapper.className = "fp-rtf-wrapper";
|
|
4635
|
-
wrapper.style.padding = "
|
|
4636
|
-
wrapper.style.
|
|
5458
|
+
wrapper.style.padding = "0";
|
|
5459
|
+
wrapper.style.width = "816px";
|
|
4637
5460
|
wrapper.style.margin = "0 auto";
|
|
4638
|
-
wrapper.style.
|
|
4639
|
-
wrapper.style.
|
|
4640
|
-
wrapper.style.
|
|
4641
|
-
wrapper.style.
|
|
5461
|
+
wrapper.style.boxSizing = "border-box";
|
|
5462
|
+
wrapper.style.display = "flex";
|
|
5463
|
+
wrapper.style.flexDirection = "column";
|
|
5464
|
+
wrapper.style.alignItems = "center";
|
|
5465
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4642
5466
|
wrapper.style.transformOrigin = "top center";
|
|
4643
|
-
wrapper.style.transition = "transform 0.
|
|
4644
|
-
ctx.container.style.
|
|
4645
|
-
ctx.container.style.
|
|
5467
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5468
|
+
ctx.container.style.overflowX = "hidden";
|
|
5469
|
+
ctx.container.style.overflowY = "auto";
|
|
5470
|
+
ctx.container.style.padding = "16px 8px";
|
|
4646
5471
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
4647
5472
|
ctx.container.appendChild(wrapper);
|
|
4648
5473
|
let scale = 1;
|
|
4649
5474
|
let rotation = 0;
|
|
4650
5475
|
let pageElements = [];
|
|
4651
|
-
let
|
|
5476
|
+
let isUserZoomed = false;
|
|
5477
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
4652
5478
|
const calculateFitScale = (mode = fitMode) => {
|
|
4653
5479
|
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4654
|
-
const elW =
|
|
4655
|
-
const singlePageH =
|
|
4656
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
4657
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
5480
|
+
const elW = 816;
|
|
5481
|
+
const singlePageH = activeEl?.offsetHeight || 1056;
|
|
5482
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
5483
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
4658
5484
|
const sW = availW / elW;
|
|
4659
5485
|
const sH = availH / singlePageH;
|
|
4660
5486
|
if (mode === "page") {
|
|
4661
|
-
return Math.max(0.
|
|
5487
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
4662
5488
|
}
|
|
4663
|
-
return Math.max(0.
|
|
5489
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
4664
5490
|
};
|
|
4665
5491
|
const applyTransform = () => {
|
|
4666
5492
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4667
5493
|
wrapper.style.transformOrigin = "top center";
|
|
5494
|
+
const activeEl = pageElements[currentPage - 1];
|
|
5495
|
+
const baseH = activeEl?.offsetHeight || 1056;
|
|
5496
|
+
const scaledH = baseH * scale;
|
|
5497
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
5498
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
4668
5499
|
};
|
|
5500
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
5501
|
+
if (!isUserZoomed) {
|
|
5502
|
+
scale = calculateFitScale(fitMode);
|
|
5503
|
+
applyTransform();
|
|
5504
|
+
}
|
|
5505
|
+
}) : null;
|
|
5506
|
+
resizeObserver?.observe(ctx.container);
|
|
4669
5507
|
setTimeout(() => {
|
|
4670
|
-
|
|
4671
|
-
scale = calculateFitScale("width");
|
|
5508
|
+
scale = calculateFitScale(fitMode);
|
|
4672
5509
|
applyTransform();
|
|
4673
5510
|
}, 60);
|
|
4674
5511
|
try {
|
|
@@ -4678,20 +5515,34 @@ var RtfPlugin = class {
|
|
|
4678
5515
|
const doc = new RTFJS.Document(ctx.buffer, {});
|
|
4679
5516
|
const htmlElements = await doc.render();
|
|
4680
5517
|
const contentNodes = [];
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
5518
|
+
const extractBlocks = (nodes) => {
|
|
5519
|
+
for (const item of nodes) {
|
|
5520
|
+
if (!item || !(item instanceof HTMLElement)) continue;
|
|
5521
|
+
const tag = item.tagName.toLowerCase();
|
|
5522
|
+
const hasChildBlocks = Array.from(item.children).some((c) => {
|
|
5523
|
+
const ct = c.tagName.toLowerCase();
|
|
5524
|
+
return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
|
|
5525
|
+
});
|
|
5526
|
+
if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
|
|
5527
|
+
extractBlocks(Array.from(item.children));
|
|
5528
|
+
} else {
|
|
5529
|
+
if (tag === "p" || tag === "div") {
|
|
5530
|
+
item.style.display = "block";
|
|
5531
|
+
item.style.marginBottom = "12px";
|
|
5532
|
+
item.style.lineHeight = "1.6";
|
|
5533
|
+
}
|
|
5534
|
+
contentNodes.push(item);
|
|
5535
|
+
}
|
|
4686
5536
|
}
|
|
4687
|
-
}
|
|
5537
|
+
};
|
|
5538
|
+
extractBlocks(htmlElements);
|
|
4688
5539
|
wrapper.innerHTML = "";
|
|
4689
5540
|
contentNodes.forEach((node) => wrapper.appendChild(node));
|
|
4690
5541
|
const childHeights = contentNodes.map((c) => {
|
|
4691
5542
|
const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
|
|
4692
5543
|
const offH = c.offsetHeight || 0;
|
|
4693
5544
|
const textLen = c.textContent?.trim().length || 0;
|
|
4694
|
-
const estH = Math.max(
|
|
5545
|
+
const estH = Math.max(28, Math.ceil(textLen / 75) * 24 + 16);
|
|
4695
5546
|
return Math.max(rectH, offH, estH);
|
|
4696
5547
|
});
|
|
4697
5548
|
wrapper.innerHTML = "";
|
|
@@ -4708,6 +5559,7 @@ var RtfPlugin = class {
|
|
|
4708
5559
|
card.style.marginBottom = "24px";
|
|
4709
5560
|
card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4710
5561
|
card.style.lineHeight = "1.6";
|
|
5562
|
+
card.style.color = "#1e293b";
|
|
4711
5563
|
return card;
|
|
4712
5564
|
};
|
|
4713
5565
|
let curCard = createRtfCard();
|
|
@@ -4743,9 +5595,8 @@ var RtfPlugin = class {
|
|
|
4743
5595
|
pageCard.style.padding = "72px 56px";
|
|
4744
5596
|
pageCard.style.width = "816px";
|
|
4745
5597
|
pageCard.style.minHeight = "1056px";
|
|
4746
|
-
pageCard.style.maxWidth = "100%";
|
|
4747
5598
|
pageCard.style.boxSizing = "border-box";
|
|
4748
|
-
pageCard.style.fontFamily = "serif
|
|
5599
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4749
5600
|
pageCard.style.fontSize = "12pt";
|
|
4750
5601
|
pageCard.style.lineHeight = "1.6";
|
|
4751
5602
|
pageCard.style.color = "#1e293b";
|
|
@@ -4758,29 +5609,6 @@ var RtfPlugin = class {
|
|
|
4758
5609
|
}
|
|
4759
5610
|
const totalPages = Math.max(1, pageElements.length);
|
|
4760
5611
|
let currentPage = 1;
|
|
4761
|
-
let indicator = null;
|
|
4762
|
-
if (totalPages > 1) {
|
|
4763
|
-
indicator = document.createElement("div");
|
|
4764
|
-
indicator.className = "fp-rtf-page-indicator";
|
|
4765
|
-
indicator.style.position = "sticky";
|
|
4766
|
-
indicator.style.bottom = "16px";
|
|
4767
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4768
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
4769
|
-
indicator.style.color = "#f8fafc";
|
|
4770
|
-
indicator.style.fontSize = "12px";
|
|
4771
|
-
indicator.style.fontWeight = "600";
|
|
4772
|
-
indicator.style.padding = "5px 14px";
|
|
4773
|
-
indicator.style.borderRadius = "20px";
|
|
4774
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4775
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4776
|
-
indicator.style.zIndex = "10";
|
|
4777
|
-
indicator.style.userSelect = "none";
|
|
4778
|
-
indicator.style.pointerEvents = "none";
|
|
4779
|
-
indicator.style.textAlign = "center";
|
|
4780
|
-
indicator.style.width = "fit-content";
|
|
4781
|
-
indicator.style.margin = "16px auto 0";
|
|
4782
|
-
ctx.container.appendChild(indicator);
|
|
4783
|
-
}
|
|
4784
5612
|
const showPage = (pageNum) => {
|
|
4785
5613
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4786
5614
|
if (totalPages > 1) {
|
|
@@ -4788,9 +5616,6 @@ var RtfPlugin = class {
|
|
|
4788
5616
|
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4789
5617
|
});
|
|
4790
5618
|
}
|
|
4791
|
-
if (indicator) {
|
|
4792
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4793
|
-
}
|
|
4794
5619
|
ctx.container.scrollTop = 0;
|
|
4795
5620
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4796
5621
|
};
|
|
@@ -4798,7 +5623,7 @@ var RtfPlugin = class {
|
|
|
4798
5623
|
showPage(1);
|
|
4799
5624
|
}
|
|
4800
5625
|
const cleanup = () => {
|
|
4801
|
-
|
|
5626
|
+
resizeObserver?.disconnect();
|
|
4802
5627
|
wrapper.remove();
|
|
4803
5628
|
ctx.container.innerHTML = "";
|
|
4804
5629
|
};
|
|
@@ -4809,21 +5634,25 @@ var RtfPlugin = class {
|
|
|
4809
5634
|
getCurrentPage: () => currentPage,
|
|
4810
5635
|
goToPage: (page) => showPage(page),
|
|
4811
5636
|
zoomIn: () => {
|
|
5637
|
+
isUserZoomed = true;
|
|
4812
5638
|
scale += 0.15;
|
|
4813
5639
|
applyTransform();
|
|
4814
5640
|
},
|
|
4815
5641
|
zoomOut: () => {
|
|
5642
|
+
isUserZoomed = true;
|
|
4816
5643
|
scale = Math.max(0.2, scale - 0.15);
|
|
4817
5644
|
applyTransform();
|
|
4818
5645
|
},
|
|
4819
5646
|
getZoom: () => scale,
|
|
4820
5647
|
setZoom: (level) => {
|
|
5648
|
+
isUserZoomed = true;
|
|
4821
5649
|
scale = level;
|
|
4822
5650
|
applyTransform();
|
|
4823
5651
|
},
|
|
4824
5652
|
fitToPage: () => {
|
|
4825
|
-
|
|
4826
|
-
|
|
5653
|
+
isUserZoomed = false;
|
|
5654
|
+
fitMode = "width";
|
|
5655
|
+
scale = calculateFitScale("width");
|
|
4827
5656
|
rotation = 0;
|
|
4828
5657
|
applyTransform();
|
|
4829
5658
|
},
|
|
@@ -5011,40 +5840,36 @@ var OpenDocumentPlugin = class {
|
|
|
5011
5840
|
const isPresentation = instance.isPresentation;
|
|
5012
5841
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5013
5842
|
const actions = [];
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
max
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
if (
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
instance.goToPage?.(page);
|
|
5042
|
-
} else if (typeof action === "number") {
|
|
5043
|
-
instance.goToPage?.(action);
|
|
5044
|
-
}
|
|
5843
|
+
actions.push({
|
|
5844
|
+
id: "thumbnails",
|
|
5845
|
+
icon: "thumbnails",
|
|
5846
|
+
label: isPresentation ? "Slide Thumbnails" : "Page Thumbnails",
|
|
5847
|
+
type: "button",
|
|
5848
|
+
group: "navigation",
|
|
5849
|
+
execute: () => instance.toggleThumbnails?.()
|
|
5850
|
+
});
|
|
5851
|
+
actions.push({
|
|
5852
|
+
id: "page-nav",
|
|
5853
|
+
icon: "",
|
|
5854
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
5855
|
+
type: "page-nav",
|
|
5856
|
+
group: "navigation",
|
|
5857
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5858
|
+
max: totalPages,
|
|
5859
|
+
execute: (action, page) => {
|
|
5860
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5861
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5862
|
+
if (action === "prev") {
|
|
5863
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5864
|
+
} else if (action === "next") {
|
|
5865
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5866
|
+
} else if (typeof page === "number") {
|
|
5867
|
+
instance.goToPage?.(page);
|
|
5868
|
+
} else if (typeof action === "number") {
|
|
5869
|
+
instance.goToPage?.(action);
|
|
5045
5870
|
}
|
|
5046
|
-
}
|
|
5047
|
-
}
|
|
5871
|
+
}
|
|
5872
|
+
});
|
|
5048
5873
|
actions.push(
|
|
5049
5874
|
{
|
|
5050
5875
|
id: "zoom-out",
|
|
@@ -5135,49 +5960,65 @@ var OpenDocumentPlugin = class {
|
|
|
5135
5960
|
container.className = "fp-odf-container";
|
|
5136
5961
|
container.style.width = "100%";
|
|
5137
5962
|
container.style.height = "100%";
|
|
5138
|
-
container.style.
|
|
5139
|
-
container.style.
|
|
5963
|
+
container.style.overflowX = "hidden";
|
|
5964
|
+
container.style.overflowY = "auto";
|
|
5965
|
+
container.style.padding = "16px 8px";
|
|
5140
5966
|
container.style.backgroundColor = "#f1f5f9";
|
|
5141
5967
|
const wrapper = document.createElement("div");
|
|
5142
5968
|
wrapper.className = "fp-odf-wrapper";
|
|
5143
5969
|
wrapper.style.margin = "0 auto";
|
|
5970
|
+
wrapper.style.width = isPresentation ? "960px" : "816px";
|
|
5971
|
+
wrapper.style.boxSizing = "border-box";
|
|
5144
5972
|
wrapper.style.backgroundColor = "#ffffff";
|
|
5145
5973
|
wrapper.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
5146
5974
|
wrapper.style.borderRadius = "4px";
|
|
5147
5975
|
wrapper.style.transformOrigin = "top center";
|
|
5148
|
-
wrapper.style.transition = "transform 0.
|
|
5976
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5149
5977
|
container.appendChild(wrapper);
|
|
5150
5978
|
ctx.container.appendChild(container);
|
|
5151
5979
|
let scale = 1;
|
|
5152
5980
|
let rotation = 0;
|
|
5153
|
-
let
|
|
5981
|
+
let isUserZoomed = false;
|
|
5982
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
5983
|
+
let currentPage = 1;
|
|
5984
|
+
let totalPages = 1;
|
|
5985
|
+
let slides = [];
|
|
5154
5986
|
const calculateFitScale = (mode = fitMode) => {
|
|
5155
|
-
const
|
|
5156
|
-
const
|
|
5157
|
-
const
|
|
5158
|
-
const
|
|
5987
|
+
const activeSlide = slides[currentPage - 1];
|
|
5988
|
+
const elW = isPresentation ? 960 : 816;
|
|
5989
|
+
const singlePageH = Math.min(activeSlide?.offsetHeight || wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
5990
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
5991
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5159
5992
|
const sW = availW / elW;
|
|
5160
5993
|
const sH = availH / (isPresentation ? 540 : singlePageH);
|
|
5161
5994
|
if (isPresentation) {
|
|
5162
|
-
return Math.min(
|
|
5995
|
+
return Math.min(2.5, Math.min(sW, sH));
|
|
5163
5996
|
}
|
|
5164
5997
|
if (mode === "page") {
|
|
5165
|
-
return Math.max(0.
|
|
5998
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5166
5999
|
}
|
|
5167
|
-
return Math.max(0.
|
|
6000
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5168
6001
|
};
|
|
5169
6002
|
const applyTransform = () => {
|
|
5170
6003
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5171
6004
|
wrapper.style.transformOrigin = "top center";
|
|
6005
|
+
const activeSlide = slides[currentPage - 1];
|
|
6006
|
+
const baseH = activeSlide?.offsetHeight || wrapper.offsetHeight || 1056;
|
|
6007
|
+
const scaledH = baseH * scale;
|
|
6008
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6009
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
5172
6010
|
};
|
|
6011
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6012
|
+
if (!isUserZoomed) {
|
|
6013
|
+
scale = calculateFitScale(fitMode);
|
|
6014
|
+
applyTransform();
|
|
6015
|
+
}
|
|
6016
|
+
}) : null;
|
|
6017
|
+
resizeObserver?.observe(ctx.container);
|
|
5173
6018
|
setTimeout(() => {
|
|
5174
|
-
|
|
5175
|
-
scale = calculateFitScale("width");
|
|
6019
|
+
scale = calculateFitScale(fitMode);
|
|
5176
6020
|
applyTransform();
|
|
5177
6021
|
}, 60);
|
|
5178
|
-
let currentPage = 1;
|
|
5179
|
-
let totalPages = 1;
|
|
5180
|
-
let slides = [];
|
|
5181
6022
|
if (isPresentation) {
|
|
5182
6023
|
wrapper.style.maxWidth = "960px";
|
|
5183
6024
|
wrapper.style.aspectRatio = "16 / 9";
|
|
@@ -5278,24 +6119,9 @@ var OpenDocumentPlugin = class {
|
|
|
5278
6119
|
wrapper.appendChild(page);
|
|
5279
6120
|
slides.push(page);
|
|
5280
6121
|
});
|
|
5281
|
-
const pageIndicator = document.createElement("div");
|
|
5282
|
-
pageIndicator.className = "fp-odt-page-indicator";
|
|
5283
|
-
pageIndicator.style.position = "sticky";
|
|
5284
|
-
pageIndicator.style.bottom = "16px";
|
|
5285
|
-
pageIndicator.style.left = "50%";
|
|
5286
|
-
pageIndicator.style.transform = "translateX(-50%)";
|
|
5287
|
-
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
5288
|
-
pageIndicator.style.color = "#fff";
|
|
5289
|
-
pageIndicator.style.padding = "6px 12px";
|
|
5290
|
-
pageIndicator.style.borderRadius = "16px";
|
|
5291
|
-
pageIndicator.style.fontSize = "12px";
|
|
5292
|
-
pageIndicator.style.zIndex = "100";
|
|
5293
|
-
pageIndicator.style.display = "inline-block";
|
|
5294
|
-
pageIndicator.style.width = "fit-content";
|
|
5295
|
-
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
5296
|
-
container.appendChild(pageIndicator);
|
|
5297
6122
|
}
|
|
5298
6123
|
const cleanup = () => {
|
|
6124
|
+
resizeObserver?.disconnect();
|
|
5299
6125
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
5300
6126
|
container.remove();
|
|
5301
6127
|
ctx.container.innerHTML = "";
|
|
@@ -5307,10 +6133,6 @@ var OpenDocumentPlugin = class {
|
|
|
5307
6133
|
slides.forEach((s, idx) => {
|
|
5308
6134
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
5309
6135
|
});
|
|
5310
|
-
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
5311
|
-
if (indicator) {
|
|
5312
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5313
|
-
}
|
|
5314
6136
|
container.scrollTop = 0;
|
|
5315
6137
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5316
6138
|
};
|
|
@@ -5318,21 +6140,25 @@ var OpenDocumentPlugin = class {
|
|
|
5318
6140
|
destroy: cleanup,
|
|
5319
6141
|
isPresentation,
|
|
5320
6142
|
zoomIn: () => {
|
|
6143
|
+
isUserZoomed = true;
|
|
5321
6144
|
scale += 0.15;
|
|
5322
6145
|
applyTransform();
|
|
5323
6146
|
},
|
|
5324
6147
|
zoomOut: () => {
|
|
6148
|
+
isUserZoomed = true;
|
|
5325
6149
|
scale = Math.max(0.2, scale - 0.15);
|
|
5326
6150
|
applyTransform();
|
|
5327
6151
|
},
|
|
5328
6152
|
getZoom: () => scale,
|
|
5329
6153
|
setZoom: (level) => {
|
|
6154
|
+
isUserZoomed = true;
|
|
5330
6155
|
scale = level;
|
|
5331
6156
|
applyTransform();
|
|
5332
6157
|
},
|
|
5333
6158
|
fitToPage: () => {
|
|
5334
|
-
|
|
5335
|
-
|
|
6159
|
+
isUserZoomed = false;
|
|
6160
|
+
fitMode = "width";
|
|
6161
|
+
scale = calculateFitScale("width");
|
|
5336
6162
|
rotation = 0;
|
|
5337
6163
|
applyTransform();
|
|
5338
6164
|
},
|
|
@@ -5348,23 +6174,45 @@ var OpenDocumentPlugin = class {
|
|
|
5348
6174
|
getPageCount: () => totalPages,
|
|
5349
6175
|
getCurrentPage: () => currentPage,
|
|
5350
6176
|
getThumbnails: async () => {
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
canvas
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
6177
|
+
const count = totalPages || slides.length || 1;
|
|
6178
|
+
const items = [];
|
|
6179
|
+
for (let idx = 0; idx < count; idx++) {
|
|
6180
|
+
const itemIdx = idx;
|
|
6181
|
+
items.push({
|
|
6182
|
+
index: itemIdx,
|
|
6183
|
+
label: isPresentation ? `Slide ${itemIdx + 1}` : `Page ${itemIdx + 1}`,
|
|
6184
|
+
render: async (canvas) => {
|
|
6185
|
+
const ctx2d = canvas.getContext("2d");
|
|
6186
|
+
if (!ctx2d) return;
|
|
6187
|
+
if (isPresentation) {
|
|
6188
|
+
canvas.width = 160;
|
|
6189
|
+
canvas.height = 90;
|
|
6190
|
+
ctx2d.fillStyle = "#f8fafc";
|
|
6191
|
+
ctx2d.fillRect(0, 0, 160, 90);
|
|
6192
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6193
|
+
ctx2d.lineWidth = 1;
|
|
6194
|
+
ctx2d.strokeRect(0.5, 0.5, 159, 89);
|
|
6195
|
+
ctx2d.fillStyle = "#334155";
|
|
6196
|
+
ctx2d.font = "bold 11px sans-serif";
|
|
6197
|
+
ctx2d.textAlign = "center";
|
|
6198
|
+
ctx2d.fillText(`Slide ${itemIdx + 1}`, 80, 50);
|
|
6199
|
+
} else {
|
|
6200
|
+
canvas.width = 140;
|
|
6201
|
+
canvas.height = 180;
|
|
6202
|
+
ctx2d.fillStyle = "#ffffff";
|
|
6203
|
+
ctx2d.fillRect(0, 0, 140, 180);
|
|
6204
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6205
|
+
ctx2d.lineWidth = 1;
|
|
6206
|
+
ctx2d.strokeRect(0.5, 0.5, 139, 179);
|
|
6207
|
+
ctx2d.fillStyle = "#64748b";
|
|
6208
|
+
ctx2d.font = "bold 10px sans-serif";
|
|
6209
|
+
ctx2d.textAlign = "center";
|
|
6210
|
+
ctx2d.fillText(`Page ${itemIdx + 1}`, 70, 90);
|
|
6211
|
+
}
|
|
6212
|
+
}
|
|
6213
|
+
});
|
|
6214
|
+
}
|
|
6215
|
+
return items;
|
|
5368
6216
|
},
|
|
5369
6217
|
download: () => {
|
|
5370
6218
|
const mimeType = this.mimeTypes.find((m) => m.includes(ext.replace(".", ""))) || "application/octet-stream";
|
|
@@ -5469,23 +6317,24 @@ var OpenDocumentPlugin = class {
|
|
|
5469
6317
|
case "h": {
|
|
5470
6318
|
const level = Math.min(6, Math.max(1, Number(node.getAttribute("text:outline-level") || 1)));
|
|
5471
6319
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5472
|
-
html += `<h${level} style="${style}; font-family:
|
|
6320
|
+
html += `<h${level} style="${style}; margin: 18px 0 8px; color: #1e3a8a; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${node.textContent || ""}</h${level}>`;
|
|
5473
6321
|
break;
|
|
5474
6322
|
}
|
|
5475
6323
|
case "p": {
|
|
5476
6324
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5477
6325
|
const inner = this.renderSpans(node, styles, images);
|
|
5478
|
-
|
|
6326
|
+
const isInsideLi = node.parentElement?.localName === "list-item" || node.parentElement?.tagName?.toLowerCase() === "list-item";
|
|
6327
|
+
html += `<p style="${style}; line-height: 1.5; margin: ${isInsideLi ? "0" : "8px 0 12px"}; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${inner}</p>`;
|
|
5479
6328
|
break;
|
|
5480
6329
|
}
|
|
5481
6330
|
case "list": {
|
|
5482
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
6331
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
5483
6332
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5484
6333
|
html += "</ul>";
|
|
5485
6334
|
break;
|
|
5486
6335
|
}
|
|
5487
6336
|
case "list-item": {
|
|
5488
|
-
html +=
|
|
6337
|
+
html += '<li style="margin: 4px 0; font-size: 11pt; line-height: 1.5; color: #1e293b;">';
|
|
5489
6338
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5490
6339
|
html += "</li>";
|
|
5491
6340
|
break;
|
|
@@ -5611,28 +6460,26 @@ var DocPlugin = class {
|
|
|
5611
6460
|
getToolbarActions(instance) {
|
|
5612
6461
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5613
6462
|
const actions = [];
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
if (
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
instance.goToPage?.(page);
|
|
5632
|
-
}
|
|
6463
|
+
actions.push({
|
|
6464
|
+
id: "page-nav",
|
|
6465
|
+
icon: "",
|
|
6466
|
+
label: "Page Navigation",
|
|
6467
|
+
type: "page-nav",
|
|
6468
|
+
group: "navigation",
|
|
6469
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
6470
|
+
max: totalPages,
|
|
6471
|
+
execute: (action, page) => {
|
|
6472
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
6473
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
6474
|
+
if (action === "prev") {
|
|
6475
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
6476
|
+
} else if (action === "next") {
|
|
6477
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
6478
|
+
} else if (typeof page === "number") {
|
|
6479
|
+
instance.goToPage?.(page);
|
|
5633
6480
|
}
|
|
5634
|
-
}
|
|
5635
|
-
}
|
|
6481
|
+
}
|
|
6482
|
+
});
|
|
5636
6483
|
actions.push(
|
|
5637
6484
|
{
|
|
5638
6485
|
id: "zoom-out",
|
|
@@ -5706,8 +6553,9 @@ var DocPlugin = class {
|
|
|
5706
6553
|
container.className = "fp-doc-container";
|
|
5707
6554
|
container.style.width = "100%";
|
|
5708
6555
|
container.style.height = "100%";
|
|
5709
|
-
container.style.
|
|
5710
|
-
container.style.
|
|
6556
|
+
container.style.overflowX = "hidden";
|
|
6557
|
+
container.style.overflowY = "auto";
|
|
6558
|
+
container.style.padding = "16px 8px";
|
|
5711
6559
|
container.style.backgroundColor = "#f1f5f9";
|
|
5712
6560
|
container.style.display = "flex";
|
|
5713
6561
|
container.style.justifyContent = "center";
|
|
@@ -5716,8 +6564,17 @@ var DocPlugin = class {
|
|
|
5716
6564
|
let scale = 1;
|
|
5717
6565
|
let extractedRawText = "";
|
|
5718
6566
|
let isFallback = false;
|
|
6567
|
+
let chartSvg = "";
|
|
5719
6568
|
try {
|
|
5720
6569
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
6570
|
+
try {
|
|
6571
|
+
const pkg = cfbf.readStream("package_stream");
|
|
6572
|
+
if (pkg && pkg.length > 100) {
|
|
6573
|
+
chartSvg = this.parseOdfChartToSvg(pkg);
|
|
6574
|
+
}
|
|
6575
|
+
} catch (chartErr) {
|
|
6576
|
+
console.warn("[DocPlugin] Chart stream parsing info:", chartErr);
|
|
6577
|
+
}
|
|
5721
6578
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
5722
6579
|
if (!wordDocStream || wordDocStream.length < 512) {
|
|
5723
6580
|
throw new Error("WordDocument stream not found or invalid in CFBF archive");
|
|
@@ -5735,7 +6592,7 @@ var DocPlugin = class {
|
|
|
5735
6592
|
extractedRawText = fallback;
|
|
5736
6593
|
isFallback = true;
|
|
5737
6594
|
}
|
|
5738
|
-
const rawPages = this.splitIntoPages(extractedRawText);
|
|
6595
|
+
const rawPages = this.splitIntoPages(extractedRawText, chartSvg);
|
|
5739
6596
|
const totalPages = Math.max(1, rawPages.length);
|
|
5740
6597
|
let currentPage = 1;
|
|
5741
6598
|
const pageCards = [];
|
|
@@ -5743,16 +6600,15 @@ var DocPlugin = class {
|
|
|
5743
6600
|
const pageCard = document.createElement("div");
|
|
5744
6601
|
pageCard.className = "fp-doc-page-card";
|
|
5745
6602
|
pageCard.style.width = "816px";
|
|
5746
|
-
pageCard.style.
|
|
6603
|
+
pageCard.style.minHeight = "1056px";
|
|
5747
6604
|
pageCard.style.backgroundColor = "#ffffff";
|
|
5748
|
-
pageCard.style.boxShadow = "0
|
|
6605
|
+
pageCard.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
5749
6606
|
pageCard.style.borderRadius = "4px";
|
|
5750
|
-
pageCard.style.padding = "
|
|
6607
|
+
pageCard.style.padding = "72px 56px";
|
|
5751
6608
|
pageCard.style.boxSizing = "border-box";
|
|
5752
|
-
pageCard.style.overflow = "hidden";
|
|
5753
6609
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5754
6610
|
pageCard.style.transformOrigin = "top center";
|
|
5755
|
-
pageCard.style.transition = "transform 0.
|
|
6611
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
5756
6612
|
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5757
6613
|
pageCard.style.color = "#1e293b";
|
|
5758
6614
|
if (isFallback && i === 0) {
|
|
@@ -5769,34 +6625,15 @@ var DocPlugin = class {
|
|
|
5769
6625
|
container.appendChild(pageCard);
|
|
5770
6626
|
pageCards.push(pageCard);
|
|
5771
6627
|
}
|
|
5772
|
-
let indicator = null;
|
|
5773
|
-
if (totalPages > 1) {
|
|
5774
|
-
indicator = document.createElement("div");
|
|
5775
|
-
indicator.className = "fp-doc-page-indicator";
|
|
5776
|
-
indicator.style.position = "fixed";
|
|
5777
|
-
indicator.style.bottom = "16px";
|
|
5778
|
-
indicator.style.left = "50%";
|
|
5779
|
-
indicator.style.transform = "translateX(-50%)";
|
|
5780
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
5781
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
5782
|
-
indicator.style.color = "#f8fafc";
|
|
5783
|
-
indicator.style.fontSize = "12px";
|
|
5784
|
-
indicator.style.fontWeight = "600";
|
|
5785
|
-
indicator.style.padding = "5px 14px";
|
|
5786
|
-
indicator.style.borderRadius = "20px";
|
|
5787
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
5788
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
5789
|
-
indicator.style.zIndex = "10";
|
|
5790
|
-
indicator.style.userSelect = "none";
|
|
5791
|
-
indicator.style.pointerEvents = "none";
|
|
5792
|
-
indicator.style.textAlign = "center";
|
|
5793
|
-
container.appendChild(indicator);
|
|
5794
|
-
}
|
|
5795
6628
|
let rotation = 0;
|
|
5796
6629
|
const applyTransform = () => {
|
|
5797
6630
|
const activeCard = pageCards[currentPage - 1];
|
|
5798
6631
|
if (activeCard) {
|
|
5799
6632
|
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
6633
|
+
const baseH = activeCard.offsetHeight || 1056;
|
|
6634
|
+
const scaledH = baseH * scale;
|
|
6635
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6636
|
+
activeCard.style.marginBottom = `${extraH + 32}px`;
|
|
5800
6637
|
}
|
|
5801
6638
|
};
|
|
5802
6639
|
const showPage = (pageNum) => {
|
|
@@ -5809,35 +6646,39 @@ var DocPlugin = class {
|
|
|
5809
6646
|
card.style.display = "none";
|
|
5810
6647
|
}
|
|
5811
6648
|
});
|
|
5812
|
-
if (indicator) {
|
|
5813
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5814
|
-
}
|
|
5815
6649
|
container.scrollTop = 0;
|
|
5816
6650
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5817
6651
|
};
|
|
5818
6652
|
if (totalPages > 1) {
|
|
5819
6653
|
showPage(1);
|
|
5820
6654
|
}
|
|
5821
|
-
let fitMode = "width";
|
|
6655
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6656
|
+
let isUserZoomed = false;
|
|
5822
6657
|
const calculateFitScale = (mode = fitMode) => {
|
|
5823
6658
|
const elW = 816;
|
|
5824
6659
|
const elH = 1056;
|
|
5825
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
5826
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
6660
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6661
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5827
6662
|
const sW = availW / elW;
|
|
5828
6663
|
const sH = availH / elH;
|
|
5829
6664
|
if (mode === "page") {
|
|
5830
|
-
return Math.max(0.
|
|
6665
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5831
6666
|
}
|
|
5832
|
-
return Math.max(0.
|
|
6667
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5833
6668
|
};
|
|
6669
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6670
|
+
if (!isUserZoomed) {
|
|
6671
|
+
scale = calculateFitScale(fitMode);
|
|
6672
|
+
applyTransform();
|
|
6673
|
+
}
|
|
6674
|
+
}) : null;
|
|
6675
|
+
resizeObserver?.observe(ctx.container);
|
|
5834
6676
|
setTimeout(() => {
|
|
5835
|
-
|
|
5836
|
-
scale = calculateFitScale("width");
|
|
6677
|
+
scale = calculateFitScale(fitMode);
|
|
5837
6678
|
applyTransform();
|
|
5838
6679
|
}, 60);
|
|
5839
6680
|
const cleanup = () => {
|
|
5840
|
-
|
|
6681
|
+
resizeObserver?.disconnect();
|
|
5841
6682
|
container.remove();
|
|
5842
6683
|
ctx.container.innerHTML = "";
|
|
5843
6684
|
};
|
|
@@ -5848,21 +6689,25 @@ var DocPlugin = class {
|
|
|
5848
6689
|
getCurrentPage: () => currentPage,
|
|
5849
6690
|
goToPage: (page) => showPage(page),
|
|
5850
6691
|
zoomIn: () => {
|
|
6692
|
+
isUserZoomed = true;
|
|
5851
6693
|
scale += 0.15;
|
|
5852
6694
|
applyTransform();
|
|
5853
6695
|
},
|
|
5854
6696
|
zoomOut: () => {
|
|
6697
|
+
isUserZoomed = true;
|
|
5855
6698
|
scale = Math.max(0.2, scale - 0.15);
|
|
5856
6699
|
applyTransform();
|
|
5857
6700
|
},
|
|
5858
6701
|
getZoom: () => scale,
|
|
5859
6702
|
setZoom: (level) => {
|
|
6703
|
+
isUserZoomed = true;
|
|
5860
6704
|
scale = level;
|
|
5861
6705
|
applyTransform();
|
|
5862
6706
|
},
|
|
5863
6707
|
fitToPage: () => {
|
|
5864
|
-
|
|
5865
|
-
|
|
6708
|
+
isUserZoomed = false;
|
|
6709
|
+
fitMode = "width";
|
|
6710
|
+
scale = calculateFitScale("width");
|
|
5866
6711
|
rotation = 0;
|
|
5867
6712
|
applyTransform();
|
|
5868
6713
|
},
|
|
@@ -5977,7 +6822,7 @@ var DocPlugin = class {
|
|
|
5977
6822
|
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
5978
6823
|
const trimmed = run.trim();
|
|
5979
6824
|
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
5980
|
-
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)) {
|
|
6825
|
+
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)) {
|
|
5981
6826
|
seen.add(trimmed);
|
|
5982
6827
|
candidateLines.push(trimmed);
|
|
5983
6828
|
}
|
|
@@ -5988,9 +6833,114 @@ var DocPlugin = class {
|
|
|
5988
6833
|
heuristicTextExtraction(buffer) {
|
|
5989
6834
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
5990
6835
|
}
|
|
5991
|
-
|
|
6836
|
+
/**
|
|
6837
|
+
* Parses an embedded OpenDocument Chart package into a vector SVG bar/column chart
|
|
6838
|
+
*/
|
|
6839
|
+
parseOdfChartToSvg(zipBytes) {
|
|
6840
|
+
try {
|
|
6841
|
+
const unzipped = fflate.unzipSync(zipBytes);
|
|
6842
|
+
const contentXml = unzipped["content.xml"] ? new TextDecoder("utf-8").decode(unzipped["content.xml"]) : "";
|
|
6843
|
+
if (!contentXml) return "";
|
|
6844
|
+
const rowsMatch = contentXml.match(/<table:table-row[\s\S]*?<\/table:table-row>/g) || [];
|
|
6845
|
+
if (rowsMatch.length < 2) return "";
|
|
6846
|
+
const headers = [];
|
|
6847
|
+
const firstRow = rowsMatch[0];
|
|
6848
|
+
const headerCells = firstRow ? firstRow.match(/<text:p>([^<]+)<\/text:p>/g) || [] : [];
|
|
6849
|
+
for (const h of headerCells) {
|
|
6850
|
+
headers.push(h.replace(/<\/?text:p>/g, "").trim());
|
|
6851
|
+
}
|
|
6852
|
+
const categories = [];
|
|
6853
|
+
const seriesValues = headers.map(() => []);
|
|
6854
|
+
for (let r = 1; r < rowsMatch.length; r++) {
|
|
6855
|
+
const rowStr = rowsMatch[r];
|
|
6856
|
+
if (!rowStr) continue;
|
|
6857
|
+
const cells = rowStr.match(/<table:table-cell[\s\S]*?<\/table:table-cell>/g) || [];
|
|
6858
|
+
if (cells.length > 0 && cells[0]) {
|
|
6859
|
+
const catMatch = cells[0].match(/<text:p>([^<]+)<\/text:p>/);
|
|
6860
|
+
categories.push(catMatch ? catMatch[1] : "Row " + r);
|
|
6861
|
+
for (let c = 1; c < cells.length && c - 1 < headers.length; c++) {
|
|
6862
|
+
const cellStr = cells[c];
|
|
6863
|
+
if (!cellStr) continue;
|
|
6864
|
+
const valMatch = cellStr.match(/office:value="([0-9.]+)"/) || cellStr.match(/<text:p>([0-9.]+)<\/text:p>/);
|
|
6865
|
+
const series = seriesValues[c - 1];
|
|
6866
|
+
if (series) {
|
|
6867
|
+
series.push(valMatch ? parseFloat(valMatch[1]) : 0);
|
|
6868
|
+
}
|
|
6869
|
+
}
|
|
6870
|
+
}
|
|
6871
|
+
}
|
|
6872
|
+
const colors = ["#004586", "#ff420e", "#ffd320", "#579d1c", "#7e0021"];
|
|
6873
|
+
const colorMatches = contentXml.matchAll(/draw:fill-color="(#[0-9a-fA-F]{6})"/g);
|
|
6874
|
+
let cIdx = 0;
|
|
6875
|
+
for (const cm of colorMatches) {
|
|
6876
|
+
if (cIdx < colors.length) colors[cIdx] = cm[1];
|
|
6877
|
+
cIdx++;
|
|
6878
|
+
}
|
|
6879
|
+
let maxVal = 10;
|
|
6880
|
+
for (const s of seriesValues) {
|
|
6881
|
+
for (const v of s) {
|
|
6882
|
+
if (v > maxVal) maxVal = v;
|
|
6883
|
+
}
|
|
6884
|
+
}
|
|
6885
|
+
maxVal = Math.ceil(maxVal * 1.15);
|
|
6886
|
+
const width = 560;
|
|
6887
|
+
const height = 280;
|
|
6888
|
+
const padLeft = 45;
|
|
6889
|
+
const padRight = 100;
|
|
6890
|
+
const padTop = 20;
|
|
6891
|
+
const padBottom = 40;
|
|
6892
|
+
const chartW = width - padLeft - padRight;
|
|
6893
|
+
const chartH = height - padTop - padBottom;
|
|
6894
|
+
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);">`;
|
|
6895
|
+
for (let step = 0; step <= 4; step++) {
|
|
6896
|
+
const yVal = (maxVal / 4 * step).toFixed(1);
|
|
6897
|
+
const yPos = padTop + chartH - step / 4 * chartH;
|
|
6898
|
+
svg += `<line x1="${padLeft}" y1="${yPos}" x2="${padLeft + chartW}" y2="${yPos}" stroke="#e2e8f0" stroke-dasharray="2,2" />`;
|
|
6899
|
+
svg += `<text x="${padLeft - 8}" y="${yPos + 4}" font-size="11" fill="#64748b" text-anchor="end">${yVal}</text>`;
|
|
6900
|
+
}
|
|
6901
|
+
const numCats = categories.length;
|
|
6902
|
+
const numSeries = headers.length;
|
|
6903
|
+
const groupW = chartW / numCats;
|
|
6904
|
+
const barW = Math.max(8, groupW * 0.7 / numSeries);
|
|
6905
|
+
const groupPad = (groupW - barW * numSeries) / 2;
|
|
6906
|
+
for (let catIdx = 0; catIdx < numCats; catIdx++) {
|
|
6907
|
+
const groupX = padLeft + catIdx * groupW + groupPad;
|
|
6908
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6909
|
+
const val = seriesValues[sIdx][catIdx] || 0;
|
|
6910
|
+
const barH = val / maxVal * chartH;
|
|
6911
|
+
const barX = groupX + sIdx * barW;
|
|
6912
|
+
const barY = padTop + chartH - barH;
|
|
6913
|
+
const col = colors[sIdx % colors.length];
|
|
6914
|
+
svg += `<rect x="${barX}" y="${barY}" width="${barW - 2}" height="${barH}" fill="${col}" rx="2"><title>${headers[sIdx]}: ${val}</title></rect>`;
|
|
6915
|
+
}
|
|
6916
|
+
const catX = padLeft + catIdx * groupW + groupW / 2;
|
|
6917
|
+
svg += `<text x="${catX}" y="${padTop + chartH + 18}" font-size="11" fill="#475569" text-anchor="middle">${categories[catIdx]}</text>`;
|
|
6918
|
+
}
|
|
6919
|
+
let legendY = padTop + 20;
|
|
6920
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6921
|
+
const col = colors[sIdx % colors.length];
|
|
6922
|
+
svg += `<rect x="${padLeft + chartW + 15}" y="${legendY}" width="12" height="12" fill="${col}" rx="2" />`;
|
|
6923
|
+
svg += `<text x="${padLeft + chartW + 32}" y="${legendY + 10}" font-size="11" fill="#334155">${headers[sIdx]}</text>`;
|
|
6924
|
+
legendY += 20;
|
|
6925
|
+
}
|
|
6926
|
+
svg += "</svg>";
|
|
6927
|
+
return svg;
|
|
6928
|
+
} catch (e) {
|
|
6929
|
+
console.warn("[DocPlugin] Error generating chart SVG:", e);
|
|
6930
|
+
return "";
|
|
6931
|
+
}
|
|
6932
|
+
}
|
|
6933
|
+
cleanWordDocFields(text, chartSvg = "") {
|
|
5992
6934
|
if (!text) return "";
|
|
5993
6935
|
let cleaned = text.replace(
|
|
6936
|
+
/\x13\s*EMBED\b[\s\S]*?\x15/gi,
|
|
6937
|
+
() => chartSvg ? `
|
|
6938
|
+
|
|
6939
|
+
${chartSvg}
|
|
6940
|
+
|
|
6941
|
+
` : ""
|
|
6942
|
+
);
|
|
6943
|
+
cleaned = cleaned.replace(
|
|
5994
6944
|
/\x13\s*HYPERLINK\s*"?([^"\x14]+)"?\s*\x14([\s\S]*?)\x15/gi,
|
|
5995
6945
|
(_match, url, label) => {
|
|
5996
6946
|
const cleanUrl = url.trim();
|
|
@@ -5998,18 +6948,23 @@ var DocPlugin = class {
|
|
|
5998
6948
|
return `<a href="${cleanUrl}" target="_blank" rel="noopener noreferrer" style="color: #2563eb; text-decoration: underline;">${cleanLabel}</a>`;
|
|
5999
6949
|
}
|
|
6000
6950
|
);
|
|
6001
|
-
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g,
|
|
6951
|
+
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g, (_m, res) => {
|
|
6952
|
+
if (/[\x00-\x1F]/.test(res)) return "";
|
|
6953
|
+
return res.trim();
|
|
6954
|
+
});
|
|
6002
6955
|
cleaned = cleaned.replace(/\x13[^\x15]*\x15/g, "");
|
|
6003
6956
|
cleaned = cleaned.replace(/[\x13\x14\x15]/g, "");
|
|
6957
|
+
cleaned = cleaned.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/g, "");
|
|
6958
|
+
cleaned = cleaned.replace(/EMBED\s+LibreOffice\.ChartDocument\.[0-9]+/gi, chartSvg || "");
|
|
6004
6959
|
return cleaned;
|
|
6005
6960
|
}
|
|
6006
|
-
splitIntoPages(text) {
|
|
6961
|
+
splitIntoPages(text, chartSvg = "") {
|
|
6007
6962
|
if (!text) return [""];
|
|
6008
|
-
const cleanedText = this.cleanWordDocFields(text);
|
|
6963
|
+
const cleanedText = this.cleanWordDocFields(text, chartSvg);
|
|
6009
6964
|
const normalized = cleanedText.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ");
|
|
6010
6965
|
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);
|
|
6011
6966
|
if (explicitParts.length === 0) explicitParts.push(normalized);
|
|
6012
|
-
const maxLinesPerPage =
|
|
6967
|
+
const maxLinesPerPage = 34;
|
|
6013
6968
|
const charsPerLine = 80;
|
|
6014
6969
|
const finalPages = [];
|
|
6015
6970
|
for (const part of explicitParts) {
|
|
@@ -6017,8 +6972,8 @@ var DocPlugin = class {
|
|
|
6017
6972
|
let currentLines = [];
|
|
6018
6973
|
let count = 0;
|
|
6019
6974
|
for (const line of lines) {
|
|
6020
|
-
const
|
|
6021
|
-
const vLines = Math.max(1, Math.ceil((
|
|
6975
|
+
const isSvg = line.includes("<svg");
|
|
6976
|
+
const vLines = isSvg ? 12 : Math.max(1, Math.ceil((line.replace(/<[^>]+>/g, "").length || 1) / charsPerLine));
|
|
6022
6977
|
if (count + vLines > maxLinesPerPage && currentLines.length > 0) {
|
|
6023
6978
|
finalPages.push(currentLines.join("\n"));
|
|
6024
6979
|
currentLines = [];
|
|
@@ -6058,9 +7013,44 @@ var DocPlugin = class {
|
|
|
6058
7013
|
tableLines = [];
|
|
6059
7014
|
}
|
|
6060
7015
|
};
|
|
7016
|
+
const sanitizeOptions = {
|
|
7017
|
+
ADD_TAGS: ["a", "svg", "g", "path", "line", "rect", "circle", "text", "title"],
|
|
7018
|
+
ADD_ATTR: [
|
|
7019
|
+
"href",
|
|
7020
|
+
"target",
|
|
7021
|
+
"rel",
|
|
7022
|
+
"style",
|
|
7023
|
+
"viewBox",
|
|
7024
|
+
"width",
|
|
7025
|
+
"height",
|
|
7026
|
+
"x",
|
|
7027
|
+
"y",
|
|
7028
|
+
"x1",
|
|
7029
|
+
"y1",
|
|
7030
|
+
"x2",
|
|
7031
|
+
"y2",
|
|
7032
|
+
"fill",
|
|
7033
|
+
"stroke",
|
|
7034
|
+
"stroke-width",
|
|
7035
|
+
"stroke-dasharray",
|
|
7036
|
+
"rx",
|
|
7037
|
+
"font-size",
|
|
7038
|
+
"text-anchor"
|
|
7039
|
+
]
|
|
7040
|
+
};
|
|
6061
7041
|
let i = 0;
|
|
6062
7042
|
while (i < lines.length) {
|
|
6063
7043
|
let line = lines[i];
|
|
7044
|
+
if (line.includes("<svg")) {
|
|
7045
|
+
if (inList) {
|
|
7046
|
+
html += "</ul>";
|
|
7047
|
+
inList = false;
|
|
7048
|
+
}
|
|
7049
|
+
flushTable();
|
|
7050
|
+
html += line;
|
|
7051
|
+
i++;
|
|
7052
|
+
continue;
|
|
7053
|
+
}
|
|
6064
7054
|
let tabCount = (line.match(/\t/g) || []).length;
|
|
6065
7055
|
if (tabCount > 0) {
|
|
6066
7056
|
let j = i;
|
|
@@ -6094,26 +7084,31 @@ var DocPlugin = class {
|
|
|
6094
7084
|
i++;
|
|
6095
7085
|
continue;
|
|
6096
7086
|
}
|
|
6097
|
-
|
|
6098
|
-
|
|
7087
|
+
if (/^\d{1,2}$/.test(line.trim())) {
|
|
7088
|
+
i++;
|
|
7089
|
+
continue;
|
|
7090
|
+
}
|
|
7091
|
+
const isShortLine = line.length < 60 && !line.endsWith(".") && !line.endsWith(",");
|
|
7092
|
+
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));
|
|
7093
|
+
if (isTitleLike) {
|
|
6099
7094
|
if (inList) {
|
|
6100
7095
|
html += "</ul>";
|
|
6101
7096
|
inList = false;
|
|
6102
7097
|
}
|
|
6103
|
-
html += `<h2 style="font-size:
|
|
7098
|
+
html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 18px 0 10px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6.sanitize(line, sanitizeOptions)}</h2>`;
|
|
6104
7099
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
6105
7100
|
if (!inList) {
|
|
6106
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
7101
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
6107
7102
|
inList = true;
|
|
6108
7103
|
}
|
|
6109
7104
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
6110
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
7105
|
+
html += `<li style="margin: 4px 0; line-height: 1.5; font-size: 11pt; color: #1e293b;">${DOMPurify6.sanitize(bulletText, sanitizeOptions)}</li>`;
|
|
6111
7106
|
} else {
|
|
6112
7107
|
if (inList) {
|
|
6113
7108
|
html += "</ul>";
|
|
6114
7109
|
inList = false;
|
|
6115
7110
|
}
|
|
6116
|
-
html += `<p style="line-height: 1.
|
|
7111
|
+
html += `<p style="line-height: 1.5; margin: 0 0 12px 0; font-size: 11pt; color: #1e293b; text-align: justify;">${DOMPurify6.sanitize(line, sanitizeOptions)}</p>`;
|
|
6117
7112
|
}
|
|
6118
7113
|
i++;
|
|
6119
7114
|
}
|