@files-preview-app/preview-file 1.3.0 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -0
- package/dist/angular.cjs +1477 -482
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.d.cts +1 -1
- package/dist/angular.d.ts +1 -1
- package/dist/angular.js +1477 -482
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +1477 -482
- package/dist/index.cjs.map +1 -1
- package/dist/index.d-B79v0jxi.d.cts +570 -0
- package/dist/index.d-B79v0jxi.d.ts +570 -0
- package/dist/index.d.cts +3227 -19
- package/dist/index.d.ts +3227 -19
- package/dist/index.js +1477 -482
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +1477 -482
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -16
- package/dist/react.d.ts +1 -16
- package/dist/react.js +1477 -482
- package/dist/react.js.map +1 -1
- package/dist/styles.css +195 -14
- package/dist/vue.cjs +1477 -482
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.d.cts +1 -1
- package/dist/vue.d.ts +1 -1
- package/dist/vue.js +1477 -482
- package/dist/vue.js.map +1 -1
- package/package.json +2 -2
package/dist/vue.js
CHANGED
|
@@ -2,6 +2,7 @@ import { defineComponent, ref, onMounted, watch, onBeforeUnmount, h } from 'vue'
|
|
|
2
2
|
import DOMPurify6 from 'dompurify';
|
|
3
3
|
import * as pdfjsLib from 'pdfjs-dist';
|
|
4
4
|
import * as docx from 'docx-preview';
|
|
5
|
+
import * as fflate from 'fflate';
|
|
5
6
|
import { unzipSync, strFromU8, unzip } from 'fflate';
|
|
6
7
|
import * as XLSX from 'xlsx';
|
|
7
8
|
import hljs from 'highlight.js';
|
|
@@ -493,8 +494,7 @@ var ICON_FULLSCREEN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="non
|
|
|
493
494
|
var ICON_COPY = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`;
|
|
494
495
|
var ICON_FAST_FORWARD = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 19 22 12 13 5 13 19"></polygon><polygon points="2 19 11 12 2 5 2 19"></polygon></svg>`;
|
|
495
496
|
var ICON_REWIND = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="11 19 2 12 11 5 11 19"></polygon><polygon points="22 19 13 12 22 5 22 19"></polygon></svg>`;
|
|
496
|
-
var
|
|
497
|
-
var ICON_EXTERNAL_WINDOW = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>`;
|
|
497
|
+
var ICON_EXTERNAL_WINDOW = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"></rect><line x1="3" y1="8" x2="21" y2="8"></line><circle cx="6" cy="5.5" r="0.75" fill="currentColor"></circle><circle cx="8.5" cy="5.5" r="0.75" fill="currentColor"></circle><polyline points="14 13 18 13 18 17"></polyline><line x1="11" y1="20" x2="18" y2="13"></line></svg>`;
|
|
498
498
|
var ICON_MAP = {
|
|
499
499
|
"zoom-in": ICON_ZOOM_IN,
|
|
500
500
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -521,28 +521,177 @@ var ICON_MAP = {
|
|
|
521
521
|
"forward-10": ICON_FAST_FORWARD,
|
|
522
522
|
"rewind": ICON_REWIND,
|
|
523
523
|
"replay-10": ICON_REWIND,
|
|
524
|
-
"speed": ICON_SPEED,
|
|
525
524
|
"open-window": ICON_EXTERNAL_WINDOW,
|
|
526
|
-
"external-window": ICON_EXTERNAL_WINDOW
|
|
525
|
+
"external-window": ICON_EXTERNAL_WINDOW,
|
|
526
|
+
"openWindow": ICON_EXTERNAL_WINDOW,
|
|
527
|
+
"openSeparateWindow": ICON_EXTERNAL_WINDOW
|
|
527
528
|
};
|
|
528
529
|
var ToolbarController = class {
|
|
529
530
|
el;
|
|
530
531
|
toolbarEl;
|
|
531
532
|
actions = [];
|
|
533
|
+
config = {};
|
|
532
534
|
pageInputEl = null;
|
|
533
535
|
pageLabelEl = null;
|
|
534
|
-
|
|
536
|
+
prevPageBtn = null;
|
|
537
|
+
nextPageBtn = null;
|
|
538
|
+
constructor(container, config) {
|
|
535
539
|
this.el = container;
|
|
540
|
+
if (config) this.config = { ...config };
|
|
536
541
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
537
542
|
this.el.appendChild(this.toolbarEl);
|
|
538
543
|
}
|
|
544
|
+
setConfig(config) {
|
|
545
|
+
this.config = { ...config };
|
|
546
|
+
this.render();
|
|
547
|
+
}
|
|
548
|
+
getConfig() {
|
|
549
|
+
return { ...this.config };
|
|
550
|
+
}
|
|
551
|
+
hideAction(actionId) {
|
|
552
|
+
this.config[actionId] = false;
|
|
553
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = false;
|
|
554
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = false;
|
|
555
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
556
|
+
this.config.fitPage = false;
|
|
557
|
+
this.config.fitToPage = false;
|
|
558
|
+
this.config.fitWidth = false;
|
|
559
|
+
}
|
|
560
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = false;
|
|
561
|
+
if (actionId === "fullscreen") this.config.fullscreen = false;
|
|
562
|
+
if (actionId === "download") this.config.download = false;
|
|
563
|
+
if (actionId === "print") this.config.print = false;
|
|
564
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
565
|
+
this.config.openWindow = false;
|
|
566
|
+
this.config.openSeparateWindow = false;
|
|
567
|
+
}
|
|
568
|
+
if (actionId === "copy") this.config.copy = false;
|
|
569
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
570
|
+
this.config.pageNav = false;
|
|
571
|
+
this.config.pagination = false;
|
|
572
|
+
}
|
|
573
|
+
this.render();
|
|
574
|
+
}
|
|
575
|
+
showAction(actionId) {
|
|
576
|
+
this.config[actionId] = true;
|
|
577
|
+
if (actionId === "zoom-in" || actionId === "zoomIn") this.config.zoomIn = true;
|
|
578
|
+
if (actionId === "zoom-out" || actionId === "zoomOut") this.config.zoomOut = true;
|
|
579
|
+
if (actionId === "fit-page" || actionId === "fitPage" || actionId === "fitToPage" || actionId === "fit-width") {
|
|
580
|
+
this.config.fitPage = true;
|
|
581
|
+
this.config.fitToPage = true;
|
|
582
|
+
this.config.fitWidth = true;
|
|
583
|
+
}
|
|
584
|
+
if (actionId === "rotate-cw" || actionId === "rotate" || actionId === "rotateCW") this.config.rotate = true;
|
|
585
|
+
if (actionId === "fullscreen") this.config.fullscreen = true;
|
|
586
|
+
if (actionId === "download") this.config.download = true;
|
|
587
|
+
if (actionId === "print") this.config.print = true;
|
|
588
|
+
if (actionId === "open-window" || actionId === "openWindow" || actionId === "openSeparateWindow") {
|
|
589
|
+
this.config.openWindow = true;
|
|
590
|
+
this.config.openSeparateWindow = true;
|
|
591
|
+
}
|
|
592
|
+
if (actionId === "copy") this.config.copy = true;
|
|
593
|
+
if (actionId === "page-nav" || actionId === "pageNav" || actionId === "pagination") {
|
|
594
|
+
this.config.pageNav = true;
|
|
595
|
+
this.config.pagination = true;
|
|
596
|
+
}
|
|
597
|
+
this.render();
|
|
598
|
+
}
|
|
599
|
+
normalizeActionId(actionId) {
|
|
600
|
+
if (actionId === "zoomIn") return "zoom-in";
|
|
601
|
+
if (actionId === "zoomOut") return "zoom-out";
|
|
602
|
+
if (actionId === "fitPage" || actionId === "fitToPage" || actionId === "fitWidth") return "fit-page";
|
|
603
|
+
if (actionId === "rotateCW") return "rotate-cw";
|
|
604
|
+
if (actionId === "rotateCCW") return "rotate-ccw";
|
|
605
|
+
if (actionId === "openWindow" || actionId === "openSeparateWindow") return "open-window";
|
|
606
|
+
if (actionId === "pageNav") return "page-nav";
|
|
607
|
+
return actionId;
|
|
608
|
+
}
|
|
609
|
+
enableAction(actionId) {
|
|
610
|
+
const norm = this.normalizeActionId(actionId);
|
|
611
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
612
|
+
if (btn) {
|
|
613
|
+
btn.disabled = false;
|
|
614
|
+
btn.classList.remove("disabled");
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
disableAction(actionId) {
|
|
618
|
+
const norm = this.normalizeActionId(actionId);
|
|
619
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
620
|
+
if (btn) {
|
|
621
|
+
btn.disabled = true;
|
|
622
|
+
btn.classList.add("disabled");
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
setActionActive(actionId, active) {
|
|
626
|
+
const norm = this.normalizeActionId(actionId);
|
|
627
|
+
const btn = this.toolbarEl.querySelector(`button[data-action-id="${actionId}"], button[data-action-id="${norm}"]`);
|
|
628
|
+
if (btn) {
|
|
629
|
+
if (active) {
|
|
630
|
+
btn.classList.add("active");
|
|
631
|
+
} else {
|
|
632
|
+
btn.classList.remove("active");
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
isActionEnabled(action) {
|
|
637
|
+
const c = this.config;
|
|
638
|
+
const id = action.id;
|
|
639
|
+
if (c[id] === false) return false;
|
|
640
|
+
if (id === "zoom-in" && (c.zoomIn === false || c["zoom-in"] === false)) return false;
|
|
641
|
+
if (id === "zoom-out" && (c.zoomOut === false || c["zoom-out"] === false)) return false;
|
|
642
|
+
if ((id === "fit-page" || id === "fit-width" || id === "fit-slide") && (c.fitPage === false || c.fitToPage === false || c.fitWidth === false || c["fit-page"] === false || c["fit-width"] === false)) {
|
|
643
|
+
return false;
|
|
644
|
+
}
|
|
645
|
+
if ((id === "rotate-cw" || id === "rotate-ccw" || id === "rotate") && (c.rotate === false || c.rotateCW === false || c.rotateCCW === false || c["rotate-cw"] === false)) {
|
|
646
|
+
return false;
|
|
647
|
+
}
|
|
648
|
+
if (id === "fullscreen" && c.fullscreen === false) return false;
|
|
649
|
+
if (id === "download" && c.download === false) return false;
|
|
650
|
+
if (id === "print" && c.print === false) return false;
|
|
651
|
+
if ((id === "open-window" || id === "external-window") && (c.openWindow === false || c.openSeparateWindow === false || c["open-window"] === false)) {
|
|
652
|
+
return false;
|
|
653
|
+
}
|
|
654
|
+
if (id === "copy" && c.copy === false) return false;
|
|
655
|
+
if (id === "thumbnails" && c.thumbnails === false) return false;
|
|
656
|
+
if (id === "page-nav" && (c.pageNav === false || c.pagination === false || c["page-nav"] === false)) {
|
|
657
|
+
return false;
|
|
658
|
+
}
|
|
659
|
+
if ((id === "prev" || id === "page-prev") && (c.prevPage === false || c.prev === false || c["prev"] === false || c.pageNav === false || c.pagination === false)) {
|
|
660
|
+
return false;
|
|
661
|
+
}
|
|
662
|
+
if ((id === "next" || id === "page-next") && (c.nextPage === false || c.next === false || c["next"] === false || c.pageNav === false || c.pagination === false)) {
|
|
663
|
+
return false;
|
|
664
|
+
}
|
|
665
|
+
if (id === "play" && c.play === false) return false;
|
|
666
|
+
if (id === "pause" && c.pause === false) return false;
|
|
667
|
+
if ((id === "fast-forward" || id === "forward-10") && (c.fastForward === false || c["fast-forward"] === false)) {
|
|
668
|
+
return false;
|
|
669
|
+
}
|
|
670
|
+
if ((id === "rewind" || id === "replay-10") && (c.rewind === false || c["rewind"] === false)) {
|
|
671
|
+
return false;
|
|
672
|
+
}
|
|
673
|
+
if (id === "speed" && c.speed === false) return false;
|
|
674
|
+
return true;
|
|
675
|
+
}
|
|
539
676
|
setPage(page, max) {
|
|
540
677
|
if (this.pageInputEl) {
|
|
541
678
|
this.pageInputEl.value = page.toString();
|
|
679
|
+
if (max !== void 0) {
|
|
680
|
+
this.pageInputEl.max = max.toString();
|
|
681
|
+
}
|
|
542
682
|
}
|
|
543
683
|
if (max !== void 0 && this.pageLabelEl) {
|
|
544
684
|
this.pageLabelEl.textContent = ` / ${max}`;
|
|
545
685
|
}
|
|
686
|
+
const currentMax = max !== void 0 ? max : parseInt(this.pageInputEl?.max || "1", 10) || 1;
|
|
687
|
+
if (this.prevPageBtn) {
|
|
688
|
+
this.prevPageBtn.disabled = page <= 1;
|
|
689
|
+
this.prevPageBtn.style.opacity = page <= 1 ? "0.4" : "1";
|
|
690
|
+
}
|
|
691
|
+
if (this.nextPageBtn) {
|
|
692
|
+
this.nextPageBtn.disabled = page >= currentMax;
|
|
693
|
+
this.nextPageBtn.style.opacity = page >= currentMax ? "0.4" : "1";
|
|
694
|
+
}
|
|
546
695
|
}
|
|
547
696
|
update(actions) {
|
|
548
697
|
this.actions = actions;
|
|
@@ -565,8 +714,9 @@ var ToolbarController = class {
|
|
|
565
714
|
view: [],
|
|
566
715
|
actions: []
|
|
567
716
|
};
|
|
568
|
-
const
|
|
569
|
-
const
|
|
717
|
+
const enabledActions = this.actions.filter((a) => this.isActionEnabled(a));
|
|
718
|
+
const hasPageNav = enabledActions.some((a) => a.type === "page-nav");
|
|
719
|
+
const effectiveActions = hasPageNav ? enabledActions.filter((a) => a.id !== "page-prev" && a.id !== "page-next" && a.id !== "prev" && a.id !== "next") : enabledActions;
|
|
570
720
|
for (const action of effectiveActions) {
|
|
571
721
|
if (groups[action.group]) {
|
|
572
722
|
groups[action.group].push(action);
|
|
@@ -626,6 +776,13 @@ var ToolbarController = class {
|
|
|
626
776
|
action.execute("go", val);
|
|
627
777
|
});
|
|
628
778
|
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
779
|
+
const curVal = action.value ?? 1;
|
|
780
|
+
prevBtn.disabled = curVal <= 1;
|
|
781
|
+
prevBtn.style.opacity = curVal <= 1 ? "0.4" : "1";
|
|
782
|
+
nextBtn.disabled = curVal >= max;
|
|
783
|
+
nextBtn.style.opacity = curVal >= max ? "0.4" : "1";
|
|
784
|
+
this.prevPageBtn = prevBtn;
|
|
785
|
+
this.nextPageBtn = nextBtn;
|
|
629
786
|
this.pageInputEl = input;
|
|
630
787
|
this.pageLabelEl = label;
|
|
631
788
|
groupEl.appendChild(prevBtn);
|
|
@@ -666,9 +823,11 @@ var ToolbarController = class {
|
|
|
666
823
|
type: "button",
|
|
667
824
|
"data-action-id": id
|
|
668
825
|
});
|
|
669
|
-
const
|
|
670
|
-
if (
|
|
671
|
-
btn.innerHTML =
|
|
826
|
+
const internalSvg = ICON_MAP[iconHtml] || ICON_MAP[id];
|
|
827
|
+
if (internalSvg) {
|
|
828
|
+
btn.innerHTML = internalSvg;
|
|
829
|
+
} else if (iconHtml && iconHtml.startsWith("<svg")) {
|
|
830
|
+
btn.innerHTML = sanitizeSVG(iconHtml);
|
|
672
831
|
} else {
|
|
673
832
|
btn.textContent = title || id;
|
|
674
833
|
}
|
|
@@ -679,25 +838,63 @@ var ToolbarController = class {
|
|
|
679
838
|
var ThumbnailPanel = class {
|
|
680
839
|
el;
|
|
681
840
|
panelEl;
|
|
841
|
+
listEl;
|
|
842
|
+
headerEl;
|
|
682
843
|
thumbnails = [];
|
|
683
844
|
onSelect;
|
|
845
|
+
onToggleCallback;
|
|
684
846
|
activeIndex = 0;
|
|
685
|
-
|
|
847
|
+
observer;
|
|
848
|
+
renderedIndices = /* @__PURE__ */ new Set();
|
|
849
|
+
constructor(container, onToggle) {
|
|
686
850
|
this.el = container;
|
|
851
|
+
this.onToggleCallback = onToggle;
|
|
687
852
|
this.panelEl = createElement("div", { className: "fp-thumbnail-panel hidden" });
|
|
853
|
+
this.panelEl.style.width = "0px";
|
|
854
|
+
this.panelEl.style.minWidth = "0px";
|
|
855
|
+
this.panelEl.style.opacity = "0";
|
|
856
|
+
this.headerEl = createElement("div", { className: "fp-thumbnail-header" });
|
|
857
|
+
const title = createElement("span", { className: "fp-thumbnail-title" }, "Pages");
|
|
858
|
+
const closeBtn = createElement("button", {
|
|
859
|
+
className: "fp-thumbnail-close-btn",
|
|
860
|
+
title: "Close Thumbnails",
|
|
861
|
+
type: "button"
|
|
862
|
+
});
|
|
863
|
+
closeBtn.innerHTML = ICON_CLOSE;
|
|
864
|
+
closeBtn.addEventListener("click", (e) => {
|
|
865
|
+
e.stopPropagation();
|
|
866
|
+
this.hide();
|
|
867
|
+
});
|
|
868
|
+
this.headerEl.appendChild(title);
|
|
869
|
+
this.headerEl.appendChild(closeBtn);
|
|
870
|
+
this.listEl = createElement("div", { className: "fp-thumbnail-list" });
|
|
871
|
+
this.panelEl.appendChild(this.headerEl);
|
|
872
|
+
this.panelEl.appendChild(this.listEl);
|
|
688
873
|
this.el.appendChild(this.panelEl);
|
|
689
874
|
}
|
|
875
|
+
isOpen() {
|
|
876
|
+
return !this.panelEl.classList.contains("hidden") && this.panelEl.style.width !== "0px";
|
|
877
|
+
}
|
|
690
878
|
update(thumbnails, onSelect) {
|
|
691
879
|
this.thumbnails = thumbnails;
|
|
692
880
|
this.onSelect = onSelect;
|
|
881
|
+
this.renderedIndices.clear();
|
|
882
|
+
const titleEl = this.headerEl.querySelector(".fp-thumbnail-title");
|
|
883
|
+
if (titleEl) {
|
|
884
|
+
titleEl.textContent = `Pages (${thumbnails.length})`;
|
|
885
|
+
}
|
|
693
886
|
this.render();
|
|
887
|
+
if (this.isOpen()) {
|
|
888
|
+
this.renderAllVisible();
|
|
889
|
+
}
|
|
694
890
|
}
|
|
695
891
|
setActive(index) {
|
|
696
892
|
this.activeIndex = index;
|
|
697
|
-
const items = this.
|
|
893
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
698
894
|
items.forEach((item, i) => {
|
|
699
895
|
if (i === index) {
|
|
700
896
|
item.classList.add("active");
|
|
897
|
+
item.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
701
898
|
} else {
|
|
702
899
|
item.classList.remove("active");
|
|
703
900
|
}
|
|
@@ -705,37 +902,102 @@ var ThumbnailPanel = class {
|
|
|
705
902
|
}
|
|
706
903
|
show() {
|
|
707
904
|
this.panelEl.classList.remove("hidden");
|
|
905
|
+
this.panelEl.style.width = "200px";
|
|
906
|
+
this.panelEl.style.minWidth = "200px";
|
|
907
|
+
this.panelEl.style.opacity = "1";
|
|
908
|
+
this.panelEl.style.display = "flex";
|
|
909
|
+
this.onToggleCallback?.(true);
|
|
910
|
+
this.renderAllVisible();
|
|
708
911
|
}
|
|
709
912
|
hide() {
|
|
710
913
|
this.panelEl.classList.add("hidden");
|
|
914
|
+
this.panelEl.style.width = "0px";
|
|
915
|
+
this.panelEl.style.minWidth = "0px";
|
|
916
|
+
this.panelEl.style.opacity = "0";
|
|
917
|
+
this.onToggleCallback?.(false);
|
|
711
918
|
}
|
|
712
919
|
toggle() {
|
|
713
|
-
this.
|
|
920
|
+
if (this.isOpen()) {
|
|
921
|
+
this.hide();
|
|
922
|
+
} else {
|
|
923
|
+
this.show();
|
|
924
|
+
}
|
|
714
925
|
}
|
|
715
926
|
destroy() {
|
|
927
|
+
if (this.observer) {
|
|
928
|
+
this.observer.disconnect();
|
|
929
|
+
this.observer = void 0;
|
|
930
|
+
}
|
|
931
|
+
this.renderedIndices.clear();
|
|
716
932
|
this.el.innerHTML = "";
|
|
717
933
|
}
|
|
718
|
-
|
|
719
|
-
this.
|
|
934
|
+
renderAllVisible() {
|
|
935
|
+
const items = this.listEl.querySelectorAll(".fp-thumbnail-item");
|
|
936
|
+
items.forEach((item) => {
|
|
937
|
+
const idx = parseInt(item.dataset.thumbIndex || "-1", 10);
|
|
938
|
+
if (idx >= 0 && !this.renderedIndices.has(idx)) {
|
|
939
|
+
this.renderThumbnailItem(idx, item);
|
|
940
|
+
}
|
|
941
|
+
});
|
|
942
|
+
}
|
|
943
|
+
renderThumbnailItem(idx, itemEl) {
|
|
944
|
+
if (this.renderedIndices.has(idx)) return;
|
|
945
|
+
this.renderedIndices.add(idx);
|
|
946
|
+
const canvas = itemEl.querySelector("canvas");
|
|
947
|
+
const thumb = this.thumbnails[idx];
|
|
948
|
+
if (canvas && thumb) {
|
|
949
|
+
Promise.resolve(thumb.render(canvas)).catch((err) => {
|
|
950
|
+
console.warn(`[FilePreview] Error rendering thumbnail ${idx}:`, err);
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
render() {
|
|
955
|
+
if (this.observer) {
|
|
956
|
+
this.observer.disconnect();
|
|
957
|
+
}
|
|
958
|
+
this.listEl.innerHTML = "";
|
|
959
|
+
const useObserver = typeof IntersectionObserver !== "undefined";
|
|
960
|
+
if (useObserver) {
|
|
961
|
+
this.observer = new IntersectionObserver(
|
|
962
|
+
(entries) => {
|
|
963
|
+
for (const entry of entries) {
|
|
964
|
+
if (entry.isIntersecting) {
|
|
965
|
+
const target = entry.target;
|
|
966
|
+
const idx = parseInt(target.dataset.thumbIndex || "-1", 10);
|
|
967
|
+
if (idx >= 0) {
|
|
968
|
+
this.renderThumbnailItem(idx, target);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
},
|
|
973
|
+
{
|
|
974
|
+
root: this.listEl,
|
|
975
|
+
rootMargin: "120px 0px 120px 0px"
|
|
976
|
+
}
|
|
977
|
+
);
|
|
978
|
+
}
|
|
720
979
|
for (let i = 0; i < this.thumbnails.length; i++) {
|
|
721
980
|
const thumb = this.thumbnails[i];
|
|
722
|
-
const itemEl = createElement("div", {
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
981
|
+
const itemEl = createElement("div", {
|
|
982
|
+
className: "fp-thumbnail-item" + (i === this.activeIndex ? " active" : "")
|
|
983
|
+
});
|
|
984
|
+
itemEl.dataset.thumbIndex = i.toString();
|
|
726
985
|
itemEl.addEventListener("click", () => {
|
|
727
986
|
this.setActive(i);
|
|
728
987
|
this.onSelect?.(i);
|
|
729
988
|
});
|
|
730
|
-
const
|
|
731
|
-
const
|
|
732
|
-
|
|
989
|
+
const canvasWrapper = createElement("div", { className: "fp-thumbnail-canvas-wrapper" });
|
|
990
|
+
const canvas = createElement("canvas", { width: "130", height: "170" });
|
|
991
|
+
canvasWrapper.appendChild(canvas);
|
|
992
|
+
const label = createElement("span", { className: "fp-thumbnail-label" }, thumb.label || `Page ${i + 1}`);
|
|
993
|
+
itemEl.appendChild(canvasWrapper);
|
|
733
994
|
itemEl.appendChild(label);
|
|
734
|
-
this.
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
}
|
|
738
|
-
|
|
995
|
+
this.listEl.appendChild(itemEl);
|
|
996
|
+
if (this.observer) {
|
|
997
|
+
this.observer.observe(itemEl);
|
|
998
|
+
}
|
|
999
|
+
if (i < 4) {
|
|
1000
|
+
this.renderThumbnailItem(i, itemEl);
|
|
739
1001
|
}
|
|
740
1002
|
}
|
|
741
1003
|
}
|
|
@@ -756,6 +1018,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
756
1018
|
currentOptions = {};
|
|
757
1019
|
resizeObserver = null;
|
|
758
1020
|
fullscreenHandler = null;
|
|
1021
|
+
titleBarEl = null;
|
|
759
1022
|
/**
|
|
760
1023
|
* Register a preview plugin.
|
|
761
1024
|
*/
|
|
@@ -792,6 +1055,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
792
1055
|
}
|
|
793
1056
|
this.currentBuffer = buffer.slice(0);
|
|
794
1057
|
this.currentMetadata = metadata;
|
|
1058
|
+
this.updateTitleBar(options, metadata);
|
|
795
1059
|
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
796
1060
|
const fileInfo = { metadata, buffer };
|
|
797
1061
|
const matchedPlugin = await this.findPlugin(fileInfo);
|
|
@@ -815,15 +1079,21 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
815
1079
|
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
816
1080
|
const total = payload.total ?? payload.totalPages;
|
|
817
1081
|
this.toolbar?.setPage(payload.page, total);
|
|
1082
|
+
this.thumbnailPanel?.setActive(payload.page - 1);
|
|
818
1083
|
}
|
|
819
1084
|
this.eventEmitter.emit(event, payload);
|
|
820
|
-
}
|
|
1085
|
+
},
|
|
1086
|
+
toggleThumbnails: () => this.toggleThumbnails()
|
|
821
1087
|
});
|
|
822
1088
|
this.activeInstance = instance;
|
|
823
1089
|
instance.openInSeparateWindow = () => this.openInSeparateWindow();
|
|
1090
|
+
instance.toggleThumbnails = () => this.toggleThumbnails();
|
|
824
1091
|
this.hideLoading();
|
|
825
1092
|
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
826
|
-
|
|
1093
|
+
const isToolbarVisible = options.showToolbar !== false && options.toolbar !== false;
|
|
1094
|
+
if (isToolbarVisible && this.toolbar) {
|
|
1095
|
+
const toolbarConfig = this.extractToolbarConfig(options);
|
|
1096
|
+
this.toolbar.setConfig(toolbarConfig);
|
|
827
1097
|
const actions = matchedPlugin.getToolbarActions(instance);
|
|
828
1098
|
const hasFullscreen = actions.some((a) => a.id === "fullscreen");
|
|
829
1099
|
if (!hasFullscreen && this.wrapperEl) {
|
|
@@ -873,6 +1143,12 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
873
1143
|
}
|
|
874
1144
|
});
|
|
875
1145
|
}
|
|
1146
|
+
const thumbAction = actions.find((a) => a.id === "thumbnails");
|
|
1147
|
+
if (thumbAction) {
|
|
1148
|
+
thumbAction.execute = () => {
|
|
1149
|
+
this.toggleThumbnails();
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
876
1152
|
this.toolbar.update(actions);
|
|
877
1153
|
this.toolbar.show();
|
|
878
1154
|
}
|
|
@@ -957,7 +1233,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
957
1233
|
if (targetUrl) {
|
|
958
1234
|
const newWin2 = window.open(targetUrl, "_blank");
|
|
959
1235
|
if (!newWin2) {
|
|
960
|
-
|
|
1236
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
961
1237
|
return null;
|
|
962
1238
|
}
|
|
963
1239
|
return newWin2;
|
|
@@ -965,7 +1241,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
965
1241
|
const title = (this.currentMetadata?.name || "Document Preview") + " - Full Preview";
|
|
966
1242
|
const newWin = window.open("", "_blank");
|
|
967
1243
|
if (!newWin) {
|
|
968
|
-
|
|
1244
|
+
console.warn("[FilePreviewViewer] Popup blocker prevented opening the preview in a separate window.");
|
|
969
1245
|
return null;
|
|
970
1246
|
}
|
|
971
1247
|
newWin.document.title = title;
|
|
@@ -1042,6 +1318,7 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1042
1318
|
this.currentBuffer = null;
|
|
1043
1319
|
this.currentMetadata = null;
|
|
1044
1320
|
this.currentContainer = null;
|
|
1321
|
+
this.titleBarEl = null;
|
|
1045
1322
|
}
|
|
1046
1323
|
/**
|
|
1047
1324
|
* Get the currently active preview instance.
|
|
@@ -1049,7 +1326,218 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1049
1326
|
getInstance() {
|
|
1050
1327
|
return this.activeInstance;
|
|
1051
1328
|
}
|
|
1329
|
+
// --- Toolbar Configuration & Feature Toggles ---
|
|
1330
|
+
/**
|
|
1331
|
+
* Configure toolbar features dynamically through options or methods.
|
|
1332
|
+
* e.g. viewer.setToolbarConfig({ zoomIn: false, print: false })
|
|
1333
|
+
*/
|
|
1334
|
+
setToolbarConfig(config) {
|
|
1335
|
+
this.toolbar?.setConfig(config);
|
|
1336
|
+
}
|
|
1337
|
+
/**
|
|
1338
|
+
* Get current toolbar configuration.
|
|
1339
|
+
*/
|
|
1340
|
+
getToolbarConfig() {
|
|
1341
|
+
return this.toolbar?.getConfig() ?? {};
|
|
1342
|
+
}
|
|
1343
|
+
/**
|
|
1344
|
+
* Hide a specific toolbar action by ID or alias (e.g. 'zoom-in', 'print', 'download').
|
|
1345
|
+
*/
|
|
1346
|
+
hideToolbarAction(actionId) {
|
|
1347
|
+
this.toolbar?.hideAction(actionId);
|
|
1348
|
+
}
|
|
1349
|
+
/**
|
|
1350
|
+
* Show a specific toolbar action by ID or alias.
|
|
1351
|
+
*/
|
|
1352
|
+
showToolbarAction(actionId) {
|
|
1353
|
+
this.toolbar?.showAction(actionId);
|
|
1354
|
+
}
|
|
1355
|
+
/**
|
|
1356
|
+
* Enable a specific toolbar action button.
|
|
1357
|
+
*/
|
|
1358
|
+
enableToolbarAction(actionId) {
|
|
1359
|
+
this.toolbar?.enableAction(actionId);
|
|
1360
|
+
}
|
|
1361
|
+
/**
|
|
1362
|
+
* Disable a specific toolbar action button.
|
|
1363
|
+
*/
|
|
1364
|
+
disableToolbarAction(actionId) {
|
|
1365
|
+
this.toolbar?.disableAction(actionId);
|
|
1366
|
+
}
|
|
1367
|
+
// --- Programmatic Toolbar Action Methods ---
|
|
1368
|
+
/**
|
|
1369
|
+
* Fit document to page so it fills the frame width with minimal margins.
|
|
1370
|
+
*/
|
|
1371
|
+
fitToPage() {
|
|
1372
|
+
this.activeInstance?.fitToPage?.();
|
|
1373
|
+
}
|
|
1374
|
+
/**
|
|
1375
|
+
* Zoom in.
|
|
1376
|
+
*/
|
|
1377
|
+
zoomIn() {
|
|
1378
|
+
this.activeInstance?.zoomIn?.();
|
|
1379
|
+
}
|
|
1380
|
+
/**
|
|
1381
|
+
* Zoom out.
|
|
1382
|
+
*/
|
|
1383
|
+
zoomOut() {
|
|
1384
|
+
this.activeInstance?.zoomOut?.();
|
|
1385
|
+
}
|
|
1386
|
+
/**
|
|
1387
|
+
* Set specific zoom level.
|
|
1388
|
+
*/
|
|
1389
|
+
setZoom(level) {
|
|
1390
|
+
this.activeInstance?.setZoom?.(level);
|
|
1391
|
+
}
|
|
1392
|
+
/**
|
|
1393
|
+
* Get current zoom level.
|
|
1394
|
+
*/
|
|
1395
|
+
getZoom() {
|
|
1396
|
+
return this.activeInstance?.getZoom?.() ?? 1;
|
|
1397
|
+
}
|
|
1398
|
+
/**
|
|
1399
|
+
* Rotate 90 degrees clockwise.
|
|
1400
|
+
*/
|
|
1401
|
+
rotateCW() {
|
|
1402
|
+
this.activeInstance?.rotateCW?.();
|
|
1403
|
+
}
|
|
1404
|
+
/**
|
|
1405
|
+
* Rotate 90 degrees counter-clockwise.
|
|
1406
|
+
*/
|
|
1407
|
+
rotateCCW() {
|
|
1408
|
+
this.activeInstance?.rotateCCW?.();
|
|
1409
|
+
}
|
|
1410
|
+
/**
|
|
1411
|
+
* Navigate to a specific page number.
|
|
1412
|
+
*/
|
|
1413
|
+
goToPage(page) {
|
|
1414
|
+
this.activeInstance?.goToPage?.(page);
|
|
1415
|
+
this.toolbar?.setPage(page);
|
|
1416
|
+
}
|
|
1417
|
+
/**
|
|
1418
|
+
* Navigate to next page.
|
|
1419
|
+
*/
|
|
1420
|
+
nextPage() {
|
|
1421
|
+
const cur = this.getCurrentPage();
|
|
1422
|
+
const max = this.getPageCount();
|
|
1423
|
+
if (cur < max) {
|
|
1424
|
+
this.goToPage(cur + 1);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
/**
|
|
1428
|
+
* Navigate to previous page.
|
|
1429
|
+
*/
|
|
1430
|
+
prevPage() {
|
|
1431
|
+
const cur = this.getCurrentPage();
|
|
1432
|
+
if (cur > 1) {
|
|
1433
|
+
this.goToPage(cur - 1);
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
/**
|
|
1437
|
+
* Get total page count.
|
|
1438
|
+
*/
|
|
1439
|
+
getPageCount() {
|
|
1440
|
+
return this.activeInstance?.getPageCount?.() ?? 1;
|
|
1441
|
+
}
|
|
1442
|
+
/**
|
|
1443
|
+
* Get current page number.
|
|
1444
|
+
*/
|
|
1445
|
+
getCurrentPage() {
|
|
1446
|
+
return this.activeInstance?.getCurrentPage?.() ?? 1;
|
|
1447
|
+
}
|
|
1448
|
+
/**
|
|
1449
|
+
* Download the current document.
|
|
1450
|
+
*/
|
|
1451
|
+
download() {
|
|
1452
|
+
this.activeInstance?.download?.();
|
|
1453
|
+
}
|
|
1454
|
+
/**
|
|
1455
|
+
* Print the current document.
|
|
1456
|
+
*/
|
|
1457
|
+
print() {
|
|
1458
|
+
this.activeInstance?.print?.();
|
|
1459
|
+
}
|
|
1460
|
+
/**
|
|
1461
|
+
* Toggle fullscreen mode.
|
|
1462
|
+
*/
|
|
1463
|
+
toggleFullscreen() {
|
|
1464
|
+
try {
|
|
1465
|
+
if (!document.fullscreenElement) {
|
|
1466
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
1467
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
1468
|
+
} else {
|
|
1469
|
+
document.exitFullscreen?.();
|
|
1470
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
1471
|
+
}
|
|
1472
|
+
} catch {
|
|
1473
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
1474
|
+
}
|
|
1475
|
+
setTimeout(() => {
|
|
1476
|
+
this.activeInstance?.fitToPage?.();
|
|
1477
|
+
}, 120);
|
|
1478
|
+
}
|
|
1479
|
+
/**
|
|
1480
|
+
* Toggle thumbnails sidebar panel.
|
|
1481
|
+
*/
|
|
1482
|
+
toggleThumbnails() {
|
|
1483
|
+
if (!this.thumbnailPanel) return;
|
|
1484
|
+
this.thumbnailPanel.toggle();
|
|
1485
|
+
const isOpen = this.thumbnailPanel.isOpen();
|
|
1486
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1487
|
+
setTimeout(() => {
|
|
1488
|
+
this.activeInstance?.fitToPage?.();
|
|
1489
|
+
}, 260);
|
|
1490
|
+
}
|
|
1491
|
+
/**
|
|
1492
|
+
* Set whether to display the file name / title bar above the toolbar.
|
|
1493
|
+
*/
|
|
1494
|
+
setShowFileName(show) {
|
|
1495
|
+
if (this.currentOptions) {
|
|
1496
|
+
this.currentOptions.showFileName = show;
|
|
1497
|
+
}
|
|
1498
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1499
|
+
}
|
|
1500
|
+
/**
|
|
1501
|
+
* Set or override the displayed file name in the preview panel.
|
|
1502
|
+
*/
|
|
1503
|
+
setFileName(name) {
|
|
1504
|
+
if (this.currentOptions) {
|
|
1505
|
+
this.currentOptions.fileName = name;
|
|
1506
|
+
}
|
|
1507
|
+
this.updateTitleBar(this.currentOptions, this.currentMetadata);
|
|
1508
|
+
}
|
|
1052
1509
|
// --- Private methods ---
|
|
1510
|
+
updateTitleBar(options, metadata) {
|
|
1511
|
+
if (!this.titleBarEl) return;
|
|
1512
|
+
const show = options?.showFileName !== false;
|
|
1513
|
+
if (!show) {
|
|
1514
|
+
this.titleBarEl.style.display = "none";
|
|
1515
|
+
return;
|
|
1516
|
+
}
|
|
1517
|
+
const name = options?.fileName || metadata?.name || this.currentMetadata?.name || "";
|
|
1518
|
+
if (!name) {
|
|
1519
|
+
this.titleBarEl.style.display = "none";
|
|
1520
|
+
return;
|
|
1521
|
+
}
|
|
1522
|
+
this.titleBarEl.style.display = "flex";
|
|
1523
|
+
const ext = metadata?.extension || (name.includes(".") ? "." + name.split(".").pop() : "");
|
|
1524
|
+
const badge = ext ? ext.replace(".", "").toUpperCase() : "";
|
|
1525
|
+
this.titleBarEl.innerHTML = `
|
|
1526
|
+
<div class="fp-titlebar-info">
|
|
1527
|
+
<span class="fp-titlebar-icon">\u{1F4C4}</span>
|
|
1528
|
+
<span class="fp-titlebar-name" title="${name}">${name}</span>
|
|
1529
|
+
${badge ? `<span class="fp-titlebar-badge">${badge}</span>` : ""}
|
|
1530
|
+
</div>
|
|
1531
|
+
`;
|
|
1532
|
+
}
|
|
1533
|
+
extractToolbarConfig(options) {
|
|
1534
|
+
if (!options) return {};
|
|
1535
|
+
const nested = typeof options.toolbar === "object" ? options.toolbar : {};
|
|
1536
|
+
return {
|
|
1537
|
+
...options,
|
|
1538
|
+
...nested
|
|
1539
|
+
};
|
|
1540
|
+
}
|
|
1053
1541
|
abort() {
|
|
1054
1542
|
if (this.abortController) {
|
|
1055
1543
|
this.abortController.abort();
|
|
@@ -1092,17 +1580,29 @@ var FilePreviewViewer = class _FilePreviewViewer {
|
|
|
1092
1580
|
bodyEl.className = "fp-body";
|
|
1093
1581
|
bodyEl.appendChild(thumbnailEl);
|
|
1094
1582
|
bodyEl.appendChild(this.contentEl);
|
|
1583
|
+
const titleBarEl = document.createElement("div");
|
|
1584
|
+
titleBarEl.className = "fp-titlebar";
|
|
1585
|
+
this.titleBarEl = titleBarEl;
|
|
1586
|
+
this.updateTitleBar(options, this.currentMetadata);
|
|
1095
1587
|
if (toolbarPos === "top") {
|
|
1588
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1096
1589
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1097
1590
|
this.wrapperEl.appendChild(bodyEl);
|
|
1098
1591
|
} else {
|
|
1592
|
+
this.wrapperEl.appendChild(titleBarEl);
|
|
1099
1593
|
this.wrapperEl.appendChild(bodyEl);
|
|
1100
1594
|
this.wrapperEl.appendChild(toolbarEl);
|
|
1101
1595
|
}
|
|
1102
1596
|
container.innerHTML = "";
|
|
1103
1597
|
container.appendChild(this.wrapperEl);
|
|
1104
|
-
|
|
1105
|
-
this.
|
|
1598
|
+
const initialToolbarConfig = this.extractToolbarConfig(options);
|
|
1599
|
+
this.toolbar = new ToolbarController(toolbarEl, initialToolbarConfig);
|
|
1600
|
+
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl, (isOpen) => {
|
|
1601
|
+
this.toolbar?.setActionActive("thumbnails", isOpen);
|
|
1602
|
+
setTimeout(() => {
|
|
1603
|
+
this.activeInstance?.fitToPage?.();
|
|
1604
|
+
}, 260);
|
|
1605
|
+
});
|
|
1106
1606
|
this.setupKeyboardShortcuts();
|
|
1107
1607
|
this.setupDragAndDrop(container, options);
|
|
1108
1608
|
this.setupResizeAndFullscreenListeners();
|
|
@@ -1492,6 +1992,14 @@ var PdfPlugin = class {
|
|
|
1492
1992
|
group: "zoom",
|
|
1493
1993
|
execute: () => instance.fitToPage?.()
|
|
1494
1994
|
},
|
|
1995
|
+
{
|
|
1996
|
+
id: "fit-width",
|
|
1997
|
+
icon: "fit-width",
|
|
1998
|
+
label: "Fit to Width",
|
|
1999
|
+
type: "button",
|
|
2000
|
+
group: "zoom",
|
|
2001
|
+
execute: () => instance.fitToWidth?.()
|
|
2002
|
+
},
|
|
1495
2003
|
{
|
|
1496
2004
|
id: "rotate-cw",
|
|
1497
2005
|
icon: "rotate-cw",
|
|
@@ -1500,6 +2008,14 @@ var PdfPlugin = class {
|
|
|
1500
2008
|
group: "view",
|
|
1501
2009
|
execute: () => instance.rotateCW?.()
|
|
1502
2010
|
},
|
|
2011
|
+
{
|
|
2012
|
+
id: "rotate-ccw",
|
|
2013
|
+
icon: "rotate-ccw",
|
|
2014
|
+
label: "Rotate Counter-Clockwise",
|
|
2015
|
+
type: "button",
|
|
2016
|
+
group: "view",
|
|
2017
|
+
execute: () => instance.rotateCCW?.()
|
|
2018
|
+
},
|
|
1503
2019
|
{
|
|
1504
2020
|
id: "download",
|
|
1505
2021
|
icon: "download",
|
|
@@ -1531,12 +2047,13 @@ var PdfPlugin = class {
|
|
|
1531
2047
|
container.className = "fp-pdf-container";
|
|
1532
2048
|
container.style.width = "100%";
|
|
1533
2049
|
container.style.height = "100%";
|
|
1534
|
-
container.style.
|
|
2050
|
+
container.style.overflowX = "hidden";
|
|
2051
|
+
container.style.overflowY = "auto";
|
|
1535
2052
|
container.style.display = "flex";
|
|
1536
2053
|
container.style.flexDirection = "column";
|
|
1537
2054
|
container.style.alignItems = "center";
|
|
1538
2055
|
container.style.justifyContent = "flex-start";
|
|
1539
|
-
container.style.padding = "
|
|
2056
|
+
container.style.padding = "16px 8px";
|
|
1540
2057
|
container.style.backgroundColor = "#0f172a";
|
|
1541
2058
|
container.style.boxSizing = "border-box";
|
|
1542
2059
|
container.style.position = "relative";
|
|
@@ -1547,30 +2064,12 @@ var PdfPlugin = class {
|
|
|
1547
2064
|
pageCard.style.borderRadius = "4px";
|
|
1548
2065
|
pageCard.style.overflow = "hidden";
|
|
1549
2066
|
pageCard.style.lineHeight = "0";
|
|
1550
|
-
pageCard.style.transition = "transform 0.15s ease";
|
|
1551
2067
|
pageCard.style.position = "relative";
|
|
1552
2068
|
pageCard.style.flexShrink = "0";
|
|
2069
|
+
pageCard.style.transition = "box-shadow 0.2s ease";
|
|
1553
2070
|
let canvas = document.createElement("canvas");
|
|
1554
2071
|
pageCard.appendChild(canvas);
|
|
1555
2072
|
container.appendChild(pageCard);
|
|
1556
|
-
const indicator = document.createElement("div");
|
|
1557
|
-
indicator.className = "fp-pdf-page-indicator";
|
|
1558
|
-
indicator.style.position = "sticky";
|
|
1559
|
-
indicator.style.bottom = "16px";
|
|
1560
|
-
indicator.style.marginTop = "16px";
|
|
1561
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1562
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
1563
|
-
indicator.style.color = "#f8fafc";
|
|
1564
|
-
indicator.style.fontSize = "12px";
|
|
1565
|
-
indicator.style.fontWeight = "600";
|
|
1566
|
-
indicator.style.padding = "5px 14px";
|
|
1567
|
-
indicator.style.borderRadius = "20px";
|
|
1568
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1569
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1570
|
-
indicator.style.zIndex = "10";
|
|
1571
|
-
indicator.style.userSelect = "none";
|
|
1572
|
-
indicator.style.pointerEvents = "none";
|
|
1573
|
-
container.appendChild(indicator);
|
|
1574
2073
|
ctx.container.appendChild(container);
|
|
1575
2074
|
const standardFontsUrl = typeof window !== "undefined" && window.__PDF_STANDARD_FONTS_URL__ || "./standard_fonts/";
|
|
1576
2075
|
const cmapsUrl = typeof window !== "undefined" && window.__PDF_CMAPS_URL__ || "./cmaps/";
|
|
@@ -1586,8 +2085,9 @@ var PdfPlugin = class {
|
|
|
1586
2085
|
let currentPage = 1;
|
|
1587
2086
|
let zoomScale = 1;
|
|
1588
2087
|
let rotation = 0;
|
|
1589
|
-
let fitMode = "
|
|
2088
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
1590
2089
|
let currentRenderTask = null;
|
|
2090
|
+
let textLayerDiv = null;
|
|
1591
2091
|
const renderPage = async (pageNum) => {
|
|
1592
2092
|
if (currentRenderTask) {
|
|
1593
2093
|
try {
|
|
@@ -1599,30 +2099,37 @@ var PdfPlugin = class {
|
|
|
1599
2099
|
const newCanvas = document.createElement("canvas");
|
|
1600
2100
|
pageCard.replaceChild(newCanvas, canvas);
|
|
1601
2101
|
canvas = newCanvas;
|
|
2102
|
+
if (textLayerDiv) {
|
|
2103
|
+
textLayerDiv.remove();
|
|
2104
|
+
textLayerDiv = null;
|
|
2105
|
+
}
|
|
1602
2106
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1603
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1604
2107
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1605
2108
|
const page = await pdfDoc.getPage(currentPage);
|
|
1606
2109
|
const containerWidth = container.clientWidth || 900;
|
|
1607
2110
|
const containerHeight = container.clientHeight || 700;
|
|
1608
2111
|
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1609
|
-
const availWidth = Math.max(
|
|
1610
|
-
const availHeight = Math.max(
|
|
2112
|
+
const availWidth = Math.max(280, containerWidth - 36);
|
|
2113
|
+
const availHeight = Math.max(280, containerHeight - 32);
|
|
1611
2114
|
const scaleW = availWidth / unscaledVp.width;
|
|
1612
2115
|
const scaleH = availHeight / unscaledVp.height;
|
|
1613
2116
|
let fitScale;
|
|
1614
2117
|
if (fitMode === "page") {
|
|
1615
|
-
fitScale = Math.max(0.4, Math.min(scaleW, scaleH));
|
|
2118
|
+
fitScale = Math.max(0.2, Math.min(4, Math.min(scaleW, scaleH)));
|
|
1616
2119
|
} else {
|
|
1617
|
-
fitScale = Math.max(0.
|
|
2120
|
+
fitScale = Math.max(0.2, Math.min(4, scaleW));
|
|
1618
2121
|
}
|
|
1619
2122
|
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1620
2123
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
1621
2124
|
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
2125
|
+
const displayWidth = Math.floor(viewport.width);
|
|
2126
|
+
const displayHeight = Math.floor(viewport.height);
|
|
1622
2127
|
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1623
2128
|
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1624
|
-
canvas.style.width = `${
|
|
1625
|
-
canvas.style.height = `${
|
|
2129
|
+
canvas.style.width = `${displayWidth}px`;
|
|
2130
|
+
canvas.style.height = `${displayHeight}px`;
|
|
2131
|
+
pageCard.style.width = `${displayWidth}px`;
|
|
2132
|
+
pageCard.style.height = `${displayHeight}px`;
|
|
1626
2133
|
const canvasCtx = canvas.getContext("2d");
|
|
1627
2134
|
if (!canvasCtx) return;
|
|
1628
2135
|
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
@@ -1636,9 +2143,31 @@ var PdfPlugin = class {
|
|
|
1636
2143
|
if (err?.name !== "RenderingCancelledException") {
|
|
1637
2144
|
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1638
2145
|
}
|
|
2146
|
+
return;
|
|
1639
2147
|
} finally {
|
|
1640
2148
|
currentRenderTask = null;
|
|
1641
2149
|
}
|
|
2150
|
+
try {
|
|
2151
|
+
textLayerDiv = document.createElement("div");
|
|
2152
|
+
textLayerDiv.className = "textLayer";
|
|
2153
|
+
textLayerDiv.style.width = `${displayWidth}px`;
|
|
2154
|
+
textLayerDiv.style.height = `${displayHeight}px`;
|
|
2155
|
+
textLayerDiv.style.position = "absolute";
|
|
2156
|
+
textLayerDiv.style.top = "0";
|
|
2157
|
+
textLayerDiv.style.left = "0";
|
|
2158
|
+
textLayerDiv.style.lineHeight = "1";
|
|
2159
|
+
pageCard.appendChild(textLayerDiv);
|
|
2160
|
+
if (pdfjsLib.TextLayer) {
|
|
2161
|
+
const textLayer = new pdfjsLib.TextLayer({
|
|
2162
|
+
textContentSource: page.streamTextContent(),
|
|
2163
|
+
container: textLayerDiv,
|
|
2164
|
+
viewport
|
|
2165
|
+
});
|
|
2166
|
+
await textLayer.render();
|
|
2167
|
+
}
|
|
2168
|
+
} catch (err) {
|
|
2169
|
+
console.debug("[PdfPlugin] TextLayer notice:", err);
|
|
2170
|
+
}
|
|
1642
2171
|
};
|
|
1643
2172
|
renderPage(1);
|
|
1644
2173
|
let resizeTimer = null;
|
|
@@ -1648,11 +2177,48 @@ var PdfPlugin = class {
|
|
|
1648
2177
|
if (Math.abs(zoomScale - 1) < 0.05) {
|
|
1649
2178
|
renderPage(currentPage);
|
|
1650
2179
|
}
|
|
1651
|
-
},
|
|
2180
|
+
}, 120);
|
|
1652
2181
|
});
|
|
1653
2182
|
resizeObserver.observe(container);
|
|
2183
|
+
const onWheel = (e) => {
|
|
2184
|
+
if (e.ctrlKey || e.metaKey) {
|
|
2185
|
+
e.preventDefault();
|
|
2186
|
+
const delta = e.deltaY > 0 ? -0.15 : 0.15;
|
|
2187
|
+
zoomScale = Math.max(0.25, Math.min(4, Math.round((zoomScale + delta) * 100) / 100));
|
|
2188
|
+
renderPage(currentPage);
|
|
2189
|
+
}
|
|
2190
|
+
};
|
|
2191
|
+
container.addEventListener("wheel", onWheel, { passive: false });
|
|
2192
|
+
const onKeyDown = (e) => {
|
|
2193
|
+
const tag = e.target?.tagName?.toLowerCase();
|
|
2194
|
+
if (tag === "input" || tag === "textarea" || tag === "select") return;
|
|
2195
|
+
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
2196
|
+
if (currentPage < totalPages) {
|
|
2197
|
+
e.preventDefault();
|
|
2198
|
+
container.scrollTop = 0;
|
|
2199
|
+
renderPage(currentPage + 1);
|
|
2200
|
+
}
|
|
2201
|
+
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
2202
|
+
if (currentPage > 1) {
|
|
2203
|
+
e.preventDefault();
|
|
2204
|
+
container.scrollTop = 0;
|
|
2205
|
+
renderPage(currentPage - 1);
|
|
2206
|
+
}
|
|
2207
|
+
} else if (e.key === "Home") {
|
|
2208
|
+
e.preventDefault();
|
|
2209
|
+
container.scrollTop = 0;
|
|
2210
|
+
renderPage(1);
|
|
2211
|
+
} else if (e.key === "End") {
|
|
2212
|
+
e.preventDefault();
|
|
2213
|
+
container.scrollTop = 0;
|
|
2214
|
+
renderPage(totalPages);
|
|
2215
|
+
}
|
|
2216
|
+
};
|
|
2217
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1654
2218
|
const cleanup = () => {
|
|
1655
2219
|
resizeObserver.disconnect();
|
|
2220
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
2221
|
+
container.removeEventListener("wheel", onWheel);
|
|
1656
2222
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
1657
2223
|
if (currentRenderTask) {
|
|
1658
2224
|
try {
|
|
@@ -1671,22 +2237,26 @@ var PdfPlugin = class {
|
|
|
1671
2237
|
const instance = {
|
|
1672
2238
|
destroy: cleanup,
|
|
1673
2239
|
zoomIn: () => {
|
|
1674
|
-
zoomScale = Math.min(
|
|
2240
|
+
zoomScale = Math.min(4, Math.round((zoomScale + 0.2) * 10) / 10);
|
|
1675
2241
|
renderPage(currentPage);
|
|
1676
2242
|
},
|
|
1677
2243
|
zoomOut: () => {
|
|
1678
|
-
zoomScale = Math.max(0.
|
|
2244
|
+
zoomScale = Math.max(0.25, Math.round((zoomScale - 0.2) * 10) / 10);
|
|
1679
2245
|
renderPage(currentPage);
|
|
1680
2246
|
},
|
|
1681
2247
|
getZoom: () => zoomScale,
|
|
1682
2248
|
setZoom: (level) => {
|
|
1683
|
-
zoomScale = Math.max(0.
|
|
2249
|
+
zoomScale = Math.max(0.25, Math.min(4, level));
|
|
1684
2250
|
renderPage(currentPage);
|
|
1685
2251
|
},
|
|
1686
2252
|
fitToPage: () => {
|
|
1687
|
-
fitMode =
|
|
2253
|
+
fitMode = "page";
|
|
2254
|
+
zoomScale = 1;
|
|
2255
|
+
renderPage(currentPage);
|
|
2256
|
+
},
|
|
2257
|
+
fitToWidth: () => {
|
|
2258
|
+
fitMode = "width";
|
|
1688
2259
|
zoomScale = 1;
|
|
1689
|
-
rotation = 0;
|
|
1690
2260
|
renderPage(currentPage);
|
|
1691
2261
|
},
|
|
1692
2262
|
rotateCW: () => {
|
|
@@ -1704,6 +2274,9 @@ var PdfPlugin = class {
|
|
|
1704
2274
|
container.scrollTop = 0;
|
|
1705
2275
|
renderPage(page);
|
|
1706
2276
|
},
|
|
2277
|
+
toggleThumbnails: () => {
|
|
2278
|
+
ctx?.toggleThumbnails?.();
|
|
2279
|
+
},
|
|
1707
2280
|
download: () => {
|
|
1708
2281
|
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1709
2282
|
const url = URL.createObjectURL(blob);
|
|
@@ -1737,7 +2310,7 @@ var PdfPlugin = class {
|
|
|
1737
2310
|
},
|
|
1738
2311
|
getThumbnails: async () => {
|
|
1739
2312
|
const thumbnails = [];
|
|
1740
|
-
const count =
|
|
2313
|
+
const count = totalPages;
|
|
1741
2314
|
for (let i = 1; i <= count; i++) {
|
|
1742
2315
|
thumbnails.push({
|
|
1743
2316
|
index: i,
|
|
@@ -1745,9 +2318,10 @@ var PdfPlugin = class {
|
|
|
1745
2318
|
render: async (thumbCanvas) => {
|
|
1746
2319
|
try {
|
|
1747
2320
|
const p = await pdfDoc.getPage(i);
|
|
1748
|
-
const baseVp = p.getViewport({ scale: 1 });
|
|
1749
|
-
const
|
|
1750
|
-
const
|
|
2321
|
+
const baseVp = p.getViewport({ scale: 1, rotation });
|
|
2322
|
+
const targetW = thumbCanvas.width || 130;
|
|
2323
|
+
const thumbScale = targetW / baseVp.width;
|
|
2324
|
+
const thumbVp = p.getViewport({ scale: thumbScale, rotation });
|
|
1751
2325
|
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1752
2326
|
const tCtx = thumbCanvas.getContext("2d");
|
|
1753
2327
|
if (tCtx) {
|
|
@@ -2091,28 +2665,26 @@ var DocxPlugin = class {
|
|
|
2091
2665
|
getToolbarActions(instance) {
|
|
2092
2666
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2093
2667
|
const actions = [];
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
if (
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
instance.goToPage?.(page);
|
|
2112
|
-
}
|
|
2668
|
+
actions.push({
|
|
2669
|
+
id: "page-nav",
|
|
2670
|
+
icon: "",
|
|
2671
|
+
label: "Page Navigation",
|
|
2672
|
+
type: "page-nav",
|
|
2673
|
+
group: "navigation",
|
|
2674
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2675
|
+
max: totalPages,
|
|
2676
|
+
execute: (action, page) => {
|
|
2677
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2678
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2679
|
+
if (action === "prev") {
|
|
2680
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2681
|
+
} else if (action === "next") {
|
|
2682
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2683
|
+
} else if (typeof page === "number") {
|
|
2684
|
+
instance.goToPage?.(page);
|
|
2113
2685
|
}
|
|
2114
|
-
}
|
|
2115
|
-
}
|
|
2686
|
+
}
|
|
2687
|
+
});
|
|
2116
2688
|
actions.push(
|
|
2117
2689
|
{
|
|
2118
2690
|
id: "zoom-out",
|
|
@@ -2178,11 +2750,17 @@ var DocxPlugin = class {
|
|
|
2178
2750
|
wrapper.className = "fp-docx-wrapper";
|
|
2179
2751
|
wrapper.style.transformOrigin = "top center";
|
|
2180
2752
|
wrapper.style.transition = "transform 0.2s ease";
|
|
2181
|
-
wrapper.style.padding = "
|
|
2182
|
-
wrapper.style.maxWidth = "
|
|
2753
|
+
wrapper.style.padding = "0";
|
|
2754
|
+
wrapper.style.maxWidth = "none";
|
|
2755
|
+
wrapper.style.width = "816px";
|
|
2183
2756
|
wrapper.style.margin = "0 auto";
|
|
2757
|
+
wrapper.style.display = "flex";
|
|
2758
|
+
wrapper.style.flexDirection = "column";
|
|
2759
|
+
wrapper.style.alignItems = "center";
|
|
2184
2760
|
wrapper.style.boxSizing = "border-box";
|
|
2185
|
-
ctx.container.style.
|
|
2761
|
+
ctx.container.style.overflowX = "hidden";
|
|
2762
|
+
ctx.container.style.overflowY = "auto";
|
|
2763
|
+
ctx.container.style.padding = "16px 8px";
|
|
2186
2764
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
2187
2765
|
ctx.container.appendChild(wrapper);
|
|
2188
2766
|
const styleOverride = document.createElement("style");
|
|
@@ -2356,39 +2934,13 @@ var DocxPlugin = class {
|
|
|
2356
2934
|
const pageElements = sections.length > 0 ? sections : cards;
|
|
2357
2935
|
const totalPages = Math.max(1, pageElements.length);
|
|
2358
2936
|
let currentPage = 1;
|
|
2359
|
-
let indicator = null;
|
|
2360
|
-
if (totalPages > 1) {
|
|
2361
|
-
indicator = document.createElement("div");
|
|
2362
|
-
indicator.className = "fp-docx-page-indicator";
|
|
2363
|
-
indicator.style.position = "sticky";
|
|
2364
|
-
indicator.style.bottom = "16px";
|
|
2365
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2366
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
2367
|
-
indicator.style.color = "#f8fafc";
|
|
2368
|
-
indicator.style.fontSize = "12px";
|
|
2369
|
-
indicator.style.fontWeight = "600";
|
|
2370
|
-
indicator.style.padding = "5px 14px";
|
|
2371
|
-
indicator.style.borderRadius = "20px";
|
|
2372
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2373
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2374
|
-
indicator.style.zIndex = "10";
|
|
2375
|
-
indicator.style.userSelect = "none";
|
|
2376
|
-
indicator.style.pointerEvents = "none";
|
|
2377
|
-
indicator.style.textAlign = "center";
|
|
2378
|
-
indicator.style.width = "fit-content";
|
|
2379
|
-
indicator.style.margin = "16px auto 0";
|
|
2380
|
-
ctx.container.appendChild(indicator);
|
|
2381
|
-
}
|
|
2382
2937
|
const showPage = (pageNum) => {
|
|
2383
2938
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2384
2939
|
if (pageElements.length > 1) {
|
|
2385
2940
|
pageElements.forEach((sec, idx) => {
|
|
2386
|
-
sec.style.display = idx + 1 === currentPage ? "
|
|
2941
|
+
sec.style.display = idx + 1 === currentPage ? "" : "none";
|
|
2387
2942
|
});
|
|
2388
2943
|
}
|
|
2389
|
-
if (indicator) {
|
|
2390
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2391
|
-
}
|
|
2392
2944
|
ctx.container.scrollTop = 0;
|
|
2393
2945
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2394
2946
|
};
|
|
@@ -2397,31 +2949,46 @@ var DocxPlugin = class {
|
|
|
2397
2949
|
}
|
|
2398
2950
|
scale = 1;
|
|
2399
2951
|
let rotation = 0;
|
|
2400
|
-
let fitMode = "
|
|
2401
|
-
|
|
2402
|
-
|
|
2952
|
+
let fitMode = "page";
|
|
2953
|
+
let isUserZoomed = false;
|
|
2954
|
+
const calculateFitScale = (_mode = fitMode) => {
|
|
2955
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
2403
2956
|
const elW = activeEl.offsetWidth || 816;
|
|
2404
|
-
const
|
|
2405
|
-
const availW = Math.max(280, ctx.container.clientWidth - 48);
|
|
2406
|
-
const availH = Math.max(280, ctx.container.clientHeight - 80);
|
|
2957
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
2407
2958
|
const sW = availW / elW;
|
|
2408
|
-
|
|
2409
|
-
if (mode === "page") {
|
|
2410
|
-
return Math.max(0.55, Math.min(1.15, Math.min(sW, sH)));
|
|
2411
|
-
}
|
|
2412
|
-
return Math.max(0.65, Math.min(1.05, sW));
|
|
2959
|
+
return Math.max(0.35, Math.min(3, sW));
|
|
2413
2960
|
};
|
|
2414
2961
|
const applyTransform = () => {
|
|
2415
2962
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2416
2963
|
wrapper.style.transformOrigin = "top center";
|
|
2964
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.querySelector("section.docx") || wrapper;
|
|
2965
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
2966
|
+
if (scale > 1) {
|
|
2967
|
+
wrapper.style.marginBottom = `${Math.round(elH * scale - elH + 32)}px`;
|
|
2968
|
+
} else {
|
|
2969
|
+
wrapper.style.marginBottom = "32px";
|
|
2970
|
+
}
|
|
2417
2971
|
};
|
|
2972
|
+
let resizeObserver = null;
|
|
2973
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
2974
|
+
resizeObserver = new ResizeObserver(() => {
|
|
2975
|
+
if (!isUserZoomed) {
|
|
2976
|
+
const newFit = calculateFitScale("page");
|
|
2977
|
+
if (Math.abs(scale - newFit) > 0.015) {
|
|
2978
|
+
scale = newFit;
|
|
2979
|
+
applyTransform();
|
|
2980
|
+
}
|
|
2981
|
+
}
|
|
2982
|
+
});
|
|
2983
|
+
resizeObserver.observe(ctx.container);
|
|
2984
|
+
}
|
|
2418
2985
|
setTimeout(() => {
|
|
2419
|
-
|
|
2420
|
-
scale = calculateFitScale("width");
|
|
2986
|
+
scale = calculateFitScale("page");
|
|
2421
2987
|
applyTransform();
|
|
2422
|
-
},
|
|
2988
|
+
}, 40);
|
|
2423
2989
|
const cleanup = () => {
|
|
2424
|
-
|
|
2990
|
+
resizeObserver?.disconnect();
|
|
2991
|
+
resizeObserver = null;
|
|
2425
2992
|
for (const url of createdBlobUrls) {
|
|
2426
2993
|
URL.revokeObjectURL(url);
|
|
2427
2994
|
}
|
|
@@ -2438,21 +3005,24 @@ var DocxPlugin = class {
|
|
|
2438
3005
|
showPage(page);
|
|
2439
3006
|
},
|
|
2440
3007
|
zoomIn: () => {
|
|
2441
|
-
|
|
3008
|
+
isUserZoomed = true;
|
|
3009
|
+
scale = Math.min(3.5, scale + 0.15);
|
|
2442
3010
|
applyTransform();
|
|
2443
3011
|
},
|
|
2444
3012
|
zoomOut: () => {
|
|
3013
|
+
isUserZoomed = true;
|
|
2445
3014
|
scale = Math.max(0.2, scale - 0.15);
|
|
2446
3015
|
applyTransform();
|
|
2447
3016
|
},
|
|
2448
3017
|
getZoom: () => scale,
|
|
2449
3018
|
setZoom: (level) => {
|
|
3019
|
+
isUserZoomed = true;
|
|
2450
3020
|
scale = level;
|
|
2451
3021
|
applyTransform();
|
|
2452
3022
|
},
|
|
2453
3023
|
fitToPage: () => {
|
|
2454
|
-
|
|
2455
|
-
scale = calculateFitScale(
|
|
3024
|
+
isUserZoomed = false;
|
|
3025
|
+
scale = calculateFitScale("page");
|
|
2456
3026
|
rotation = 0;
|
|
2457
3027
|
applyTransform();
|
|
2458
3028
|
},
|
|
@@ -2842,7 +3412,7 @@ var ExcelPlugin = class {
|
|
|
2842
3412
|
"application/vnd.ms-excel.template.macroEnabled.12",
|
|
2843
3413
|
"application/vnd.oasis.opendocument.spreadsheet"
|
|
2844
3414
|
];
|
|
2845
|
-
weight =
|
|
3415
|
+
weight = 85;
|
|
2846
3416
|
supports(file) {
|
|
2847
3417
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2848
3418
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
@@ -2854,6 +3424,14 @@ var ExcelPlugin = class {
|
|
|
2854
3424
|
getToolbarActions(instance) {
|
|
2855
3425
|
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2856
3426
|
const actions = [];
|
|
3427
|
+
actions.push({
|
|
3428
|
+
id: "thumbnails",
|
|
3429
|
+
icon: "thumbnails",
|
|
3430
|
+
label: "Sheet Thumbnails",
|
|
3431
|
+
type: "button",
|
|
3432
|
+
group: "navigation",
|
|
3433
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3434
|
+
});
|
|
2857
3435
|
if (totalSheets > 1) {
|
|
2858
3436
|
actions.push({
|
|
2859
3437
|
id: "page-nav",
|
|
@@ -2936,6 +3514,16 @@ var ExcelPlugin = class {
|
|
|
2936
3514
|
execute: () => {
|
|
2937
3515
|
instance.print?.();
|
|
2938
3516
|
}
|
|
3517
|
+
},
|
|
3518
|
+
{
|
|
3519
|
+
id: "open-window",
|
|
3520
|
+
icon: "open-window",
|
|
3521
|
+
label: "Open in Separate Full Window",
|
|
3522
|
+
type: "button",
|
|
3523
|
+
group: "actions",
|
|
3524
|
+
execute: () => {
|
|
3525
|
+
instance.openInSeparateWindow?.();
|
|
3526
|
+
}
|
|
2939
3527
|
}
|
|
2940
3528
|
);
|
|
2941
3529
|
return actions;
|
|
@@ -3101,6 +3689,63 @@ var ExcelPlugin = class {
|
|
|
3101
3689
|
},
|
|
3102
3690
|
getPageCount: () => sheetNames.length,
|
|
3103
3691
|
getCurrentPage: () => currentSheetIndex,
|
|
3692
|
+
getThumbnails: () => {
|
|
3693
|
+
return sheetNames.map((name, idx) => ({
|
|
3694
|
+
index: idx,
|
|
3695
|
+
label: name,
|
|
3696
|
+
render: async (canvas) => {
|
|
3697
|
+
canvas.width = 140;
|
|
3698
|
+
canvas.height = 100;
|
|
3699
|
+
const c = canvas.getContext("2d");
|
|
3700
|
+
if (!c) return;
|
|
3701
|
+
c.fillStyle = "#ffffff";
|
|
3702
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
3703
|
+
c.fillStyle = "#107c41";
|
|
3704
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
3705
|
+
c.fillStyle = "#ffffff";
|
|
3706
|
+
c.font = 'bold 8px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
3707
|
+
c.fillText(`\u{1F4CA} ${name.slice(0, 16)}`, 6, 11);
|
|
3708
|
+
const startY = 17;
|
|
3709
|
+
const rowH = 13;
|
|
3710
|
+
const colW = 30;
|
|
3711
|
+
const colHeaders = ["A", "B", "C", "D"];
|
|
3712
|
+
c.fillStyle = "#f1f5f9";
|
|
3713
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
3714
|
+
c.strokeStyle = "#cbd5e1";
|
|
3715
|
+
c.lineWidth = 0.8;
|
|
3716
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
3717
|
+
c.fillStyle = "#64748b";
|
|
3718
|
+
c.font = "bold 7px sans-serif";
|
|
3719
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3720
|
+
c.fillText(colHeaders[ci], 14 + ci * colW, startY + 9);
|
|
3721
|
+
}
|
|
3722
|
+
const ws = wb?.Sheets[name];
|
|
3723
|
+
for (let ri = 1; ri <= 5; ri++) {
|
|
3724
|
+
const y = startY + ri * rowH;
|
|
3725
|
+
if (y > canvas.height - 2) break;
|
|
3726
|
+
c.fillStyle = "#f8fafc";
|
|
3727
|
+
c.fillRect(0, y, 12, rowH);
|
|
3728
|
+
c.fillStyle = "#94a3b8";
|
|
3729
|
+
c.font = "6px sans-serif";
|
|
3730
|
+
c.fillText(String(ri), 3, y + 9);
|
|
3731
|
+
c.strokeStyle = "#e2e8f0";
|
|
3732
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
3733
|
+
c.fillStyle = "#334155";
|
|
3734
|
+
c.font = "6px sans-serif";
|
|
3735
|
+
for (let ci = 0; ci < colHeaders.length; ci++) {
|
|
3736
|
+
const cellRef = `${colHeaders[ci]}${ri}`;
|
|
3737
|
+
const cellVal = ws?.[cellRef]?.w || ws?.[cellRef]?.v;
|
|
3738
|
+
if (cellVal !== void 0) {
|
|
3739
|
+
c.fillText(String(cellVal).slice(0, 6), 14 + ci * colW, y + 9);
|
|
3740
|
+
}
|
|
3741
|
+
}
|
|
3742
|
+
}
|
|
3743
|
+
c.strokeStyle = "#cbd5e1";
|
|
3744
|
+
c.lineWidth = 1;
|
|
3745
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
3746
|
+
}
|
|
3747
|
+
}));
|
|
3748
|
+
},
|
|
3104
3749
|
download: () => {
|
|
3105
3750
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
3106
3751
|
const url = URL.createObjectURL(blob);
|
|
@@ -3133,7 +3778,39 @@ var CsvPlugin = class {
|
|
|
3133
3778
|
return ext === ".csv" || ext === ".tsv" || mime === "text/csv" || mime === "text/tab-separated-values";
|
|
3134
3779
|
}
|
|
3135
3780
|
getToolbarActions(instance) {
|
|
3136
|
-
|
|
3781
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3782
|
+
const actions = [];
|
|
3783
|
+
actions.push({
|
|
3784
|
+
id: "thumbnails",
|
|
3785
|
+
icon: "thumbnails",
|
|
3786
|
+
label: "Page Thumbnails",
|
|
3787
|
+
type: "button",
|
|
3788
|
+
group: "navigation",
|
|
3789
|
+
execute: () => instance.toggleThumbnails?.()
|
|
3790
|
+
});
|
|
3791
|
+
if (totalPages > 1) {
|
|
3792
|
+
actions.push({
|
|
3793
|
+
id: "page-nav",
|
|
3794
|
+
icon: "",
|
|
3795
|
+
label: "Page Navigation",
|
|
3796
|
+
type: "page-nav",
|
|
3797
|
+
group: "navigation",
|
|
3798
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3799
|
+
max: totalPages,
|
|
3800
|
+
execute: (action, page) => {
|
|
3801
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3802
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
3803
|
+
if (action === "prev") {
|
|
3804
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3805
|
+
} else if (action === "next") {
|
|
3806
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
3807
|
+
} else if (typeof page === "number") {
|
|
3808
|
+
instance.goToPage?.(page);
|
|
3809
|
+
}
|
|
3810
|
+
}
|
|
3811
|
+
});
|
|
3812
|
+
}
|
|
3813
|
+
actions.push(
|
|
3137
3814
|
{
|
|
3138
3815
|
id: "zoom-out",
|
|
3139
3816
|
icon: "zoom-out",
|
|
@@ -3154,6 +3831,16 @@ var CsvPlugin = class {
|
|
|
3154
3831
|
instance.zoomIn?.();
|
|
3155
3832
|
}
|
|
3156
3833
|
},
|
|
3834
|
+
{
|
|
3835
|
+
id: "fit-page",
|
|
3836
|
+
icon: "fit-page",
|
|
3837
|
+
label: "Fit to View",
|
|
3838
|
+
type: "button",
|
|
3839
|
+
group: "zoom",
|
|
3840
|
+
execute: () => {
|
|
3841
|
+
instance.fitToPage?.();
|
|
3842
|
+
}
|
|
3843
|
+
},
|
|
3157
3844
|
{
|
|
3158
3845
|
id: "download",
|
|
3159
3846
|
icon: "download",
|
|
@@ -3171,10 +3858,21 @@ var CsvPlugin = class {
|
|
|
3171
3858
|
type: "button",
|
|
3172
3859
|
group: "actions",
|
|
3173
3860
|
execute: () => {
|
|
3174
|
-
instance.print?.();
|
|
3861
|
+
instance.print?.();
|
|
3862
|
+
}
|
|
3863
|
+
},
|
|
3864
|
+
{
|
|
3865
|
+
id: "open-window",
|
|
3866
|
+
icon: "open-window",
|
|
3867
|
+
label: "Open in Separate Full Window",
|
|
3868
|
+
type: "button",
|
|
3869
|
+
group: "actions",
|
|
3870
|
+
execute: () => {
|
|
3871
|
+
instance.openInSeparateWindow?.();
|
|
3175
3872
|
}
|
|
3176
3873
|
}
|
|
3177
|
-
|
|
3874
|
+
);
|
|
3875
|
+
return actions;
|
|
3178
3876
|
}
|
|
3179
3877
|
async render(ctx) {
|
|
3180
3878
|
const decoder = new TextDecoder("utf-8");
|
|
@@ -3186,33 +3884,62 @@ var CsvPlugin = class {
|
|
|
3186
3884
|
container.style.padding = "16px";
|
|
3187
3885
|
container.style.boxSizing = "border-box";
|
|
3188
3886
|
container.style.transformOrigin = "top left";
|
|
3887
|
+
const delimiter = ctx.metadata.extension === ".tsv" ? " " : ",";
|
|
3888
|
+
const allLines = text.split(/\r?\n/).filter((r) => r.trim().length > 0);
|
|
3889
|
+
const headerLine = allLines[0] || "";
|
|
3890
|
+
const headerCells = headerLine.split(delimiter);
|
|
3891
|
+
const dataLines = allLines.slice(1);
|
|
3892
|
+
const ROWS_PER_PAGE = 100;
|
|
3893
|
+
const totalPages = Math.max(1, Math.ceil(dataLines.length / ROWS_PER_PAGE));
|
|
3894
|
+
let currentPage = 1;
|
|
3189
3895
|
const table = document.createElement("table");
|
|
3190
3896
|
table.style.borderCollapse = "collapse";
|
|
3191
3897
|
table.style.width = "100%";
|
|
3192
|
-
table.style.fontFamily = "monospace
|
|
3898
|
+
table.style.fontFamily = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace';
|
|
3193
3899
|
table.style.fontSize = "13px";
|
|
3194
|
-
const
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
td.style.fontWeight = "bold";
|
|
3208
|
-
}
|
|
3209
|
-
tr.appendChild(td);
|
|
3900
|
+
const renderPage = (pageNum) => {
|
|
3901
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3902
|
+
table.innerHTML = "";
|
|
3903
|
+
const headerTr = document.createElement("tr");
|
|
3904
|
+
headerCells.forEach((cell) => {
|
|
3905
|
+
const th = document.createElement("th");
|
|
3906
|
+
th.textContent = cell.trim();
|
|
3907
|
+
th.style.border = "1px solid #d0d7de";
|
|
3908
|
+
th.style.padding = "8px 12px";
|
|
3909
|
+
th.style.backgroundColor = "#f6f8fa";
|
|
3910
|
+
th.style.fontWeight = "600";
|
|
3911
|
+
th.style.whiteSpace = "nowrap";
|
|
3912
|
+
headerTr.appendChild(th);
|
|
3210
3913
|
});
|
|
3211
|
-
table.appendChild(
|
|
3212
|
-
|
|
3914
|
+
table.appendChild(headerTr);
|
|
3915
|
+
const start = (currentPage - 1) * ROWS_PER_PAGE;
|
|
3916
|
+
const end = Math.min(dataLines.length, start + ROWS_PER_PAGE);
|
|
3917
|
+
const pageRows = dataLines.slice(start, end);
|
|
3918
|
+
pageRows.forEach((row, idx) => {
|
|
3919
|
+
const tr = document.createElement("tr");
|
|
3920
|
+
if (idx % 2 === 1) tr.style.backgroundColor = "#f8fafc";
|
|
3921
|
+
const cells = row.split(delimiter);
|
|
3922
|
+
cells.forEach((cell) => {
|
|
3923
|
+
const td = document.createElement("td");
|
|
3924
|
+
td.textContent = cell.trim();
|
|
3925
|
+
td.style.border = "1px solid #d0d7de";
|
|
3926
|
+
td.style.padding = "6px 12px";
|
|
3927
|
+
td.style.whiteSpace = "nowrap";
|
|
3928
|
+
tr.appendChild(td);
|
|
3929
|
+
});
|
|
3930
|
+
table.appendChild(tr);
|
|
3931
|
+
});
|
|
3932
|
+
container.scrollTop = 0;
|
|
3933
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3934
|
+
};
|
|
3935
|
+
renderPage(1);
|
|
3213
3936
|
container.appendChild(table);
|
|
3214
3937
|
ctx.container.appendChild(container);
|
|
3215
3938
|
let scale = 1;
|
|
3939
|
+
const applyScale = () => {
|
|
3940
|
+
container.style.transform = `scale(${scale})`;
|
|
3941
|
+
container.style.transformOrigin = "top left";
|
|
3942
|
+
};
|
|
3216
3943
|
const cleanup = () => {
|
|
3217
3944
|
container.remove();
|
|
3218
3945
|
ctx.container.innerHTML = "";
|
|
@@ -3220,22 +3947,86 @@ var CsvPlugin = class {
|
|
|
3220
3947
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3221
3948
|
return {
|
|
3222
3949
|
destroy: cleanup,
|
|
3950
|
+
getPageCount: () => totalPages,
|
|
3951
|
+
getCurrentPage: () => currentPage,
|
|
3952
|
+
goToPage: (page) => renderPage(page),
|
|
3953
|
+
getThumbnails: () => {
|
|
3954
|
+
const thumbnails = [];
|
|
3955
|
+
for (let i = 0; i < totalPages; i++) {
|
|
3956
|
+
const pageIdx = i;
|
|
3957
|
+
const startRow = pageIdx * ROWS_PER_PAGE + 1;
|
|
3958
|
+
const endRow = Math.min(dataLines.length, (pageIdx + 1) * ROWS_PER_PAGE);
|
|
3959
|
+
const label = totalPages === 1 ? "Table" : `Page ${pageIdx + 1} (${startRow}-${endRow})`;
|
|
3960
|
+
thumbnails.push({
|
|
3961
|
+
index: pageIdx,
|
|
3962
|
+
label,
|
|
3963
|
+
render: async (canvas) => {
|
|
3964
|
+
canvas.width = 140;
|
|
3965
|
+
canvas.height = 100;
|
|
3966
|
+
const c = canvas.getContext("2d");
|
|
3967
|
+
if (!c) return;
|
|
3968
|
+
c.fillStyle = "#ffffff";
|
|
3969
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
3970
|
+
c.fillStyle = "#2563eb";
|
|
3971
|
+
c.fillRect(0, 0, canvas.width, 16);
|
|
3972
|
+
c.fillStyle = "#ffffff";
|
|
3973
|
+
c.font = "bold 8px sans-serif";
|
|
3974
|
+
c.fillText(`\u{1F4C8} ${label.slice(0, 18)}`, 6, 11);
|
|
3975
|
+
const startY = 17;
|
|
3976
|
+
const rowH = 13;
|
|
3977
|
+
const colW = 28;
|
|
3978
|
+
const cols = Math.min(4, headerCells.length || 4);
|
|
3979
|
+
c.fillStyle = "#f1f5f9";
|
|
3980
|
+
c.fillRect(0, startY, canvas.width, rowH);
|
|
3981
|
+
c.strokeStyle = "#cbd5e1";
|
|
3982
|
+
c.lineWidth = 0.8;
|
|
3983
|
+
c.strokeRect(0, startY, canvas.width, rowH);
|
|
3984
|
+
c.fillStyle = "#64748b";
|
|
3985
|
+
c.font = "bold 7px sans-serif";
|
|
3986
|
+
for (let ci = 0; ci < cols; ci++) {
|
|
3987
|
+
const hName = headerCells[ci] || `Col ${ci + 1}`;
|
|
3988
|
+
c.fillText(hName.slice(0, 5), 8 + ci * colW, startY + 9);
|
|
3989
|
+
}
|
|
3990
|
+
const rowsToPreview = dataLines.slice(pageIdx * ROWS_PER_PAGE, pageIdx * ROWS_PER_PAGE + 5);
|
|
3991
|
+
for (let ri = 0; ri < rowsToPreview.length; ri++) {
|
|
3992
|
+
const y = startY + (ri + 1) * rowH;
|
|
3993
|
+
if (y > canvas.height - 2) break;
|
|
3994
|
+
c.strokeStyle = "#e2e8f0";
|
|
3995
|
+
c.strokeRect(0, y, canvas.width, rowH);
|
|
3996
|
+
const cVals = rowsToPreview[ri].split(delimiter);
|
|
3997
|
+
c.fillStyle = "#334155";
|
|
3998
|
+
c.font = "6px sans-serif";
|
|
3999
|
+
for (let ci = 0; ci < cols; ci++) {
|
|
4000
|
+
const val = cVals[ci] || "";
|
|
4001
|
+
c.fillText(val.trim().slice(0, 6), 8 + ci * colW, y + 9);
|
|
4002
|
+
}
|
|
4003
|
+
}
|
|
4004
|
+
c.strokeStyle = "#cbd5e1";
|
|
4005
|
+
c.lineWidth = 1;
|
|
4006
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4007
|
+
}
|
|
4008
|
+
});
|
|
4009
|
+
}
|
|
4010
|
+
return thumbnails;
|
|
4011
|
+
},
|
|
3223
4012
|
zoomIn: () => {
|
|
3224
4013
|
scale += 0.1;
|
|
3225
|
-
|
|
4014
|
+
applyScale();
|
|
3226
4015
|
},
|
|
3227
4016
|
zoomOut: () => {
|
|
3228
4017
|
scale = Math.max(0.2, scale - 0.1);
|
|
3229
|
-
|
|
4018
|
+
applyScale();
|
|
3230
4019
|
},
|
|
3231
4020
|
getZoom: () => scale,
|
|
3232
4021
|
setZoom: (level) => {
|
|
3233
4022
|
scale = level;
|
|
3234
|
-
|
|
4023
|
+
applyScale();
|
|
3235
4024
|
},
|
|
3236
4025
|
fitToPage: () => {
|
|
3237
|
-
|
|
3238
|
-
|
|
4026
|
+
const availW = Math.max(280, (ctx.container.clientWidth || window.innerWidth) - 48);
|
|
4027
|
+
const tW = table.offsetWidth || 600;
|
|
4028
|
+
scale = Math.max(0.35, Math.min(1, availW / tW));
|
|
4029
|
+
applyScale();
|
|
3239
4030
|
},
|
|
3240
4031
|
download: () => {
|
|
3241
4032
|
const blob = new Blob([ctx.buffer], { type: "text/csv" });
|
|
@@ -3299,28 +4090,34 @@ var CodePlugin = class {
|
|
|
3299
4090
|
getToolbarActions(instance) {
|
|
3300
4091
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3301
4092
|
const actions = [];
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
4093
|
+
actions.push({
|
|
4094
|
+
id: "thumbnails",
|
|
4095
|
+
icon: "thumbnails",
|
|
4096
|
+
label: "Page Thumbnails",
|
|
4097
|
+
type: "button",
|
|
4098
|
+
group: "navigation",
|
|
4099
|
+
execute: () => instance.toggleThumbnails?.()
|
|
4100
|
+
});
|
|
4101
|
+
actions.push({
|
|
4102
|
+
id: "page-nav",
|
|
4103
|
+
icon: "",
|
|
4104
|
+
label: "Page Navigation",
|
|
4105
|
+
type: "page-nav",
|
|
4106
|
+
group: "navigation",
|
|
4107
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4108
|
+
max: totalPages,
|
|
4109
|
+
execute: (action, page) => {
|
|
4110
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4111
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4112
|
+
if (action === "prev") {
|
|
4113
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4114
|
+
} else if (action === "next") {
|
|
4115
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4116
|
+
} else if (typeof page === "number") {
|
|
4117
|
+
instance.goToPage?.(page);
|
|
3321
4118
|
}
|
|
3322
|
-
}
|
|
3323
|
-
}
|
|
4119
|
+
}
|
|
4120
|
+
});
|
|
3324
4121
|
actions.push(
|
|
3325
4122
|
{
|
|
3326
4123
|
id: "zoom-out",
|
|
@@ -3464,16 +4261,19 @@ var CodePlugin = class {
|
|
|
3464
4261
|
let fontSize = 13;
|
|
3465
4262
|
let rotation = 0;
|
|
3466
4263
|
let zoomLevel = 1;
|
|
4264
|
+
let isUserZoomed = false;
|
|
3467
4265
|
const pre = document.createElement("pre");
|
|
3468
4266
|
const code = document.createElement("code");
|
|
3469
4267
|
if (isTxt) {
|
|
4268
|
+
container.style.overflowX = "hidden";
|
|
4269
|
+
container.style.overflowY = "auto";
|
|
3470
4270
|
container.style.backgroundColor = "#f1f5f9";
|
|
3471
|
-
container.style.padding = "
|
|
4271
|
+
container.style.padding = "16px 8px";
|
|
3472
4272
|
container.style.boxSizing = "border-box";
|
|
3473
4273
|
container.style.display = "flex";
|
|
3474
4274
|
container.style.flexDirection = "column";
|
|
3475
4275
|
container.style.alignItems = "center";
|
|
3476
|
-
pre.style.margin = "0";
|
|
4276
|
+
pre.style.margin = "0 auto";
|
|
3477
4277
|
pre.style.fontFamily = "Consolas, 'Courier New', monospace";
|
|
3478
4278
|
pre.style.fontSize = "13px";
|
|
3479
4279
|
pre.style.color = "#1e293b";
|
|
@@ -3485,10 +4285,12 @@ var CodePlugin = class {
|
|
|
3485
4285
|
pre.style.minHeight = "1056px";
|
|
3486
4286
|
pre.style.padding = "72px 56px";
|
|
3487
4287
|
pre.style.boxSizing = "border-box";
|
|
3488
|
-
pre.style.boxShadow = "0 4px
|
|
4288
|
+
pre.style.boxShadow = "0 4px 24px rgba(0, 0, 0, 0.08)";
|
|
3489
4289
|
pre.style.borderRadius = "4px";
|
|
3490
4290
|
pre.style.transformOrigin = "top center";
|
|
4291
|
+
pre.style.transition = "transform 0.15s ease";
|
|
3491
4292
|
} else {
|
|
4293
|
+
container.style.overflow = "auto";
|
|
3492
4294
|
container.style.backgroundColor = "#1e1e1e";
|
|
3493
4295
|
container.style.color = "#d4d4d4";
|
|
3494
4296
|
container.style.padding = "16px";
|
|
@@ -3520,42 +4322,9 @@ var CodePlugin = class {
|
|
|
3520
4322
|
renderCodePage(rawPages[0] || (isTxt ? "" : fullText));
|
|
3521
4323
|
pre.appendChild(code);
|
|
3522
4324
|
container.appendChild(pre);
|
|
3523
|
-
let indicator = null;
|
|
3524
|
-
if (totalPages > 1) {
|
|
3525
|
-
indicator = document.createElement("div");
|
|
3526
|
-
indicator.className = "fp-code-page-indicator";
|
|
3527
|
-
indicator.style.position = "sticky";
|
|
3528
|
-
indicator.style.bottom = "16px";
|
|
3529
|
-
if (isTxt) {
|
|
3530
|
-
indicator.style.backgroundColor = "rgba(255, 255, 255, 0.9)";
|
|
3531
|
-
indicator.style.color = "#334155";
|
|
3532
|
-
indicator.style.border = "1px solid #e2e8f0";
|
|
3533
|
-
indicator.style.boxShadow = "0 1px 3px rgba(0,0,0,0.1)";
|
|
3534
|
-
} else {
|
|
3535
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3536
|
-
indicator.style.color = "#f8fafc";
|
|
3537
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3538
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3539
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
3540
|
-
}
|
|
3541
|
-
indicator.style.fontSize = "12px";
|
|
3542
|
-
indicator.style.fontWeight = "600";
|
|
3543
|
-
indicator.style.padding = "5px 14px";
|
|
3544
|
-
indicator.style.borderRadius = "20px";
|
|
3545
|
-
indicator.style.zIndex = "10";
|
|
3546
|
-
indicator.style.userSelect = "none";
|
|
3547
|
-
indicator.style.pointerEvents = "none";
|
|
3548
|
-
indicator.style.textAlign = "center";
|
|
3549
|
-
indicator.style.width = "fit-content";
|
|
3550
|
-
indicator.style.margin = "16px auto 0";
|
|
3551
|
-
container.appendChild(indicator);
|
|
3552
|
-
}
|
|
3553
4325
|
const showPage = (pageNum) => {
|
|
3554
4326
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3555
4327
|
renderCodePage(rawPages[currentPage - 1] || (isTxt ? "" : fullText));
|
|
3556
|
-
if (indicator) {
|
|
3557
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3558
|
-
}
|
|
3559
4328
|
container.scrollTop = 0;
|
|
3560
4329
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3561
4330
|
};
|
|
@@ -3563,36 +4332,90 @@ var CodePlugin = class {
|
|
|
3563
4332
|
showPage(1);
|
|
3564
4333
|
}
|
|
3565
4334
|
ctx.container.appendChild(container);
|
|
3566
|
-
const
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
ctx.container.innerHTML = "";
|
|
4335
|
+
const calculateTxtFit = () => {
|
|
4336
|
+
const availW = Math.max(280, container.clientWidth - 32);
|
|
4337
|
+
return Math.max(0.4, Math.min(3, availW / 816));
|
|
3570
4338
|
};
|
|
3571
|
-
ctx.signal.addEventListener("abort", cleanup);
|
|
3572
4339
|
const updateTransform = () => {
|
|
3573
4340
|
if (isTxt) {
|
|
3574
4341
|
pre.style.transform = `scale(${zoomLevel}) rotate(${rotation}deg)`;
|
|
4342
|
+
const scaledH = 1056 * zoomLevel;
|
|
4343
|
+
const extraH = Math.max(0, scaledH - 1056);
|
|
4344
|
+
pre.style.marginBottom = `${extraH + 32}px`;
|
|
3575
4345
|
} else {
|
|
3576
4346
|
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3577
4347
|
pre.style.fontSize = `${fontSize}px`;
|
|
3578
4348
|
}
|
|
3579
4349
|
};
|
|
4350
|
+
let resizeObserver = null;
|
|
4351
|
+
if (isTxt) {
|
|
4352
|
+
setTimeout(() => {
|
|
4353
|
+
zoomLevel = calculateTxtFit();
|
|
4354
|
+
updateTransform();
|
|
4355
|
+
}, 60);
|
|
4356
|
+
resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
4357
|
+
if (!isUserZoomed) {
|
|
4358
|
+
zoomLevel = calculateTxtFit();
|
|
4359
|
+
updateTransform();
|
|
4360
|
+
}
|
|
4361
|
+
}) : null;
|
|
4362
|
+
resizeObserver?.observe(container);
|
|
4363
|
+
}
|
|
4364
|
+
const cleanup = () => {
|
|
4365
|
+
resizeObserver?.disconnect();
|
|
4366
|
+
container.remove();
|
|
4367
|
+
ctx.container.innerHTML = "";
|
|
4368
|
+
};
|
|
4369
|
+
ctx.signal.addEventListener("abort", cleanup);
|
|
3580
4370
|
return {
|
|
3581
4371
|
destroy: cleanup,
|
|
3582
4372
|
getPageCount: () => totalPages,
|
|
3583
4373
|
getCurrentPage: () => currentPage,
|
|
3584
4374
|
goToPage: (page) => showPage(page),
|
|
4375
|
+
getThumbnails: () => {
|
|
4376
|
+
return rawPages.map((pageText, idx) => ({
|
|
4377
|
+
index: idx,
|
|
4378
|
+
label: `Page ${idx + 1}`,
|
|
4379
|
+
render: async (canvas) => {
|
|
4380
|
+
canvas.width = 140;
|
|
4381
|
+
canvas.height = 180;
|
|
4382
|
+
const c = canvas.getContext("2d");
|
|
4383
|
+
if (!c) return;
|
|
4384
|
+
c.fillStyle = "#ffffff";
|
|
4385
|
+
c.fillRect(0, 0, canvas.width, canvas.height);
|
|
4386
|
+
c.strokeStyle = "#cbd5e1";
|
|
4387
|
+
c.lineWidth = 1;
|
|
4388
|
+
c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
|
|
4389
|
+
c.fillStyle = "#64748b";
|
|
4390
|
+
const lines = (pageText || "").split("\n").slice(0, 24);
|
|
4391
|
+
const lineH = 6;
|
|
4392
|
+
const startY = 14;
|
|
4393
|
+
const startX = 12;
|
|
4394
|
+
const maxW = canvas.width - 24;
|
|
4395
|
+
c.font = "5px monospace";
|
|
4396
|
+
for (let li = 0; li < lines.length; li++) {
|
|
4397
|
+
const l = lines[li].trim();
|
|
4398
|
+
if (!l) continue;
|
|
4399
|
+
const y = startY + li * lineH;
|
|
4400
|
+
if (y > canvas.height - 12) break;
|
|
4401
|
+
c.fillText(l.slice(0, 30), startX, y, maxW);
|
|
4402
|
+
}
|
|
4403
|
+
}
|
|
4404
|
+
}));
|
|
4405
|
+
},
|
|
3585
4406
|
zoomIn: () => {
|
|
4407
|
+
isUserZoomed = true;
|
|
3586
4408
|
if (isTxt) {
|
|
3587
|
-
zoomLevel = Math.min(3, zoomLevel + 0.
|
|
4409
|
+
zoomLevel = Math.min(3.5, zoomLevel + 0.15);
|
|
3588
4410
|
} else {
|
|
3589
4411
|
fontSize = Math.min(32, fontSize + 2);
|
|
3590
4412
|
}
|
|
3591
4413
|
updateTransform();
|
|
3592
4414
|
},
|
|
3593
4415
|
zoomOut: () => {
|
|
4416
|
+
isUserZoomed = true;
|
|
3594
4417
|
if (isTxt) {
|
|
3595
|
-
zoomLevel = Math.max(0.1, zoomLevel - 0.
|
|
4418
|
+
zoomLevel = Math.max(0.1, zoomLevel - 0.15);
|
|
3596
4419
|
} else {
|
|
3597
4420
|
fontSize = Math.max(8, fontSize - 2);
|
|
3598
4421
|
}
|
|
@@ -3600,6 +4423,7 @@ var CodePlugin = class {
|
|
|
3600
4423
|
},
|
|
3601
4424
|
getZoom: () => isTxt ? zoomLevel : fontSize / 13,
|
|
3602
4425
|
setZoom: (level) => {
|
|
4426
|
+
isUserZoomed = true;
|
|
3603
4427
|
if (isTxt) {
|
|
3604
4428
|
zoomLevel = level;
|
|
3605
4429
|
} else {
|
|
@@ -3608,9 +4432,10 @@ var CodePlugin = class {
|
|
|
3608
4432
|
updateTransform();
|
|
3609
4433
|
},
|
|
3610
4434
|
fitToPage: () => {
|
|
4435
|
+
isUserZoomed = false;
|
|
3611
4436
|
fontSize = 13;
|
|
3612
4437
|
rotation = 0;
|
|
3613
|
-
zoomLevel = isTxt ?
|
|
4438
|
+
zoomLevel = isTxt ? calculateTxtFit() : 1;
|
|
3614
4439
|
updateTransform();
|
|
3615
4440
|
},
|
|
3616
4441
|
rotateCW: () => {
|
|
@@ -4491,28 +5316,26 @@ var RtfPlugin = class {
|
|
|
4491
5316
|
getToolbarActions(instance) {
|
|
4492
5317
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4493
5318
|
const actions = [];
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
if (
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
instance.goToPage?.(page);
|
|
4512
|
-
}
|
|
5319
|
+
actions.push({
|
|
5320
|
+
id: "page-nav",
|
|
5321
|
+
icon: "",
|
|
5322
|
+
label: "Page Navigation",
|
|
5323
|
+
type: "page-nav",
|
|
5324
|
+
group: "navigation",
|
|
5325
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5326
|
+
max: totalPages,
|
|
5327
|
+
execute: (action, page) => {
|
|
5328
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5329
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5330
|
+
if (action === "prev") {
|
|
5331
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5332
|
+
} else if (action === "next") {
|
|
5333
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5334
|
+
} else if (typeof page === "number") {
|
|
5335
|
+
instance.goToPage?.(page);
|
|
4513
5336
|
}
|
|
4514
|
-
}
|
|
4515
|
-
}
|
|
5337
|
+
}
|
|
5338
|
+
});
|
|
4516
5339
|
actions.push(
|
|
4517
5340
|
{
|
|
4518
5341
|
id: "zoom-out",
|
|
@@ -4584,43 +5407,57 @@ var RtfPlugin = class {
|
|
|
4584
5407
|
async render(ctx) {
|
|
4585
5408
|
const wrapper = document.createElement("div");
|
|
4586
5409
|
wrapper.className = "fp-rtf-wrapper";
|
|
4587
|
-
wrapper.style.padding = "
|
|
4588
|
-
wrapper.style.
|
|
5410
|
+
wrapper.style.padding = "0";
|
|
5411
|
+
wrapper.style.width = "816px";
|
|
4589
5412
|
wrapper.style.margin = "0 auto";
|
|
4590
|
-
wrapper.style.
|
|
4591
|
-
wrapper.style.
|
|
4592
|
-
wrapper.style.
|
|
4593
|
-
wrapper.style.
|
|
5413
|
+
wrapper.style.boxSizing = "border-box";
|
|
5414
|
+
wrapper.style.display = "flex";
|
|
5415
|
+
wrapper.style.flexDirection = "column";
|
|
5416
|
+
wrapper.style.alignItems = "center";
|
|
5417
|
+
wrapper.style.backgroundColor = "transparent";
|
|
4594
5418
|
wrapper.style.transformOrigin = "top center";
|
|
4595
|
-
wrapper.style.transition = "transform 0.
|
|
4596
|
-
ctx.container.style.
|
|
4597
|
-
ctx.container.style.
|
|
5419
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5420
|
+
ctx.container.style.overflowX = "hidden";
|
|
5421
|
+
ctx.container.style.overflowY = "auto";
|
|
5422
|
+
ctx.container.style.padding = "16px 8px";
|
|
4598
5423
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
4599
5424
|
ctx.container.appendChild(wrapper);
|
|
4600
5425
|
let scale = 1;
|
|
4601
5426
|
let rotation = 0;
|
|
4602
5427
|
let pageElements = [];
|
|
4603
|
-
let
|
|
5428
|
+
let isUserZoomed = false;
|
|
5429
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
4604
5430
|
const calculateFitScale = (mode = fitMode) => {
|
|
4605
5431
|
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4606
|
-
const elW =
|
|
4607
|
-
const singlePageH =
|
|
4608
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
4609
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
5432
|
+
const elW = 816;
|
|
5433
|
+
const singlePageH = activeEl?.offsetHeight || 1056;
|
|
5434
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
5435
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
4610
5436
|
const sW = availW / elW;
|
|
4611
5437
|
const sH = availH / singlePageH;
|
|
4612
5438
|
if (mode === "page") {
|
|
4613
|
-
return Math.max(0.
|
|
5439
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
4614
5440
|
}
|
|
4615
|
-
return Math.max(0.
|
|
5441
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
4616
5442
|
};
|
|
4617
5443
|
const applyTransform = () => {
|
|
4618
5444
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4619
5445
|
wrapper.style.transformOrigin = "top center";
|
|
5446
|
+
const activeEl = pageElements[currentPage - 1];
|
|
5447
|
+
const baseH = activeEl?.offsetHeight || 1056;
|
|
5448
|
+
const scaledH = baseH * scale;
|
|
5449
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
5450
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
4620
5451
|
};
|
|
5452
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
5453
|
+
if (!isUserZoomed) {
|
|
5454
|
+
scale = calculateFitScale(fitMode);
|
|
5455
|
+
applyTransform();
|
|
5456
|
+
}
|
|
5457
|
+
}) : null;
|
|
5458
|
+
resizeObserver?.observe(ctx.container);
|
|
4621
5459
|
setTimeout(() => {
|
|
4622
|
-
|
|
4623
|
-
scale = calculateFitScale("width");
|
|
5460
|
+
scale = calculateFitScale(fitMode);
|
|
4624
5461
|
applyTransform();
|
|
4625
5462
|
}, 60);
|
|
4626
5463
|
try {
|
|
@@ -4630,20 +5467,34 @@ var RtfPlugin = class {
|
|
|
4630
5467
|
const doc = new RTFJS.Document(ctx.buffer, {});
|
|
4631
5468
|
const htmlElements = await doc.render();
|
|
4632
5469
|
const contentNodes = [];
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
5470
|
+
const extractBlocks = (nodes) => {
|
|
5471
|
+
for (const item of nodes) {
|
|
5472
|
+
if (!item || !(item instanceof HTMLElement)) continue;
|
|
5473
|
+
const tag = item.tagName.toLowerCase();
|
|
5474
|
+
const hasChildBlocks = Array.from(item.children).some((c) => {
|
|
5475
|
+
const ct = c.tagName.toLowerCase();
|
|
5476
|
+
return ["p", "div", "table", "h1", "h2", "h3", "h4", "h5", "h6", "section", "article", "ul", "ol"].includes(ct);
|
|
5477
|
+
});
|
|
5478
|
+
if (hasChildBlocks && !["table", "tr", "td", "th", "ul", "ol", "li"].includes(tag)) {
|
|
5479
|
+
extractBlocks(Array.from(item.children));
|
|
5480
|
+
} else {
|
|
5481
|
+
if (tag === "p" || tag === "div") {
|
|
5482
|
+
item.style.display = "block";
|
|
5483
|
+
item.style.marginBottom = "12px";
|
|
5484
|
+
item.style.lineHeight = "1.6";
|
|
5485
|
+
}
|
|
5486
|
+
contentNodes.push(item);
|
|
5487
|
+
}
|
|
4638
5488
|
}
|
|
4639
|
-
}
|
|
5489
|
+
};
|
|
5490
|
+
extractBlocks(htmlElements);
|
|
4640
5491
|
wrapper.innerHTML = "";
|
|
4641
5492
|
contentNodes.forEach((node) => wrapper.appendChild(node));
|
|
4642
5493
|
const childHeights = contentNodes.map((c) => {
|
|
4643
5494
|
const rectH = c.getBoundingClientRect ? c.getBoundingClientRect().height : 0;
|
|
4644
5495
|
const offH = c.offsetHeight || 0;
|
|
4645
5496
|
const textLen = c.textContent?.trim().length || 0;
|
|
4646
|
-
const estH = Math.max(
|
|
5497
|
+
const estH = Math.max(28, Math.ceil(textLen / 75) * 24 + 16);
|
|
4647
5498
|
return Math.max(rectH, offH, estH);
|
|
4648
5499
|
});
|
|
4649
5500
|
wrapper.innerHTML = "";
|
|
@@ -4660,6 +5511,7 @@ var RtfPlugin = class {
|
|
|
4660
5511
|
card.style.marginBottom = "24px";
|
|
4661
5512
|
card.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4662
5513
|
card.style.lineHeight = "1.6";
|
|
5514
|
+
card.style.color = "#1e293b";
|
|
4663
5515
|
return card;
|
|
4664
5516
|
};
|
|
4665
5517
|
let curCard = createRtfCard();
|
|
@@ -4695,9 +5547,8 @@ var RtfPlugin = class {
|
|
|
4695
5547
|
pageCard.style.padding = "72px 56px";
|
|
4696
5548
|
pageCard.style.width = "816px";
|
|
4697
5549
|
pageCard.style.minHeight = "1056px";
|
|
4698
|
-
pageCard.style.maxWidth = "100%";
|
|
4699
5550
|
pageCard.style.boxSizing = "border-box";
|
|
4700
|
-
pageCard.style.fontFamily = "serif
|
|
5551
|
+
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
4701
5552
|
pageCard.style.fontSize = "12pt";
|
|
4702
5553
|
pageCard.style.lineHeight = "1.6";
|
|
4703
5554
|
pageCard.style.color = "#1e293b";
|
|
@@ -4710,29 +5561,6 @@ var RtfPlugin = class {
|
|
|
4710
5561
|
}
|
|
4711
5562
|
const totalPages = Math.max(1, pageElements.length);
|
|
4712
5563
|
let currentPage = 1;
|
|
4713
|
-
let indicator = null;
|
|
4714
|
-
if (totalPages > 1) {
|
|
4715
|
-
indicator = document.createElement("div");
|
|
4716
|
-
indicator.className = "fp-rtf-page-indicator";
|
|
4717
|
-
indicator.style.position = "sticky";
|
|
4718
|
-
indicator.style.bottom = "16px";
|
|
4719
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4720
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
4721
|
-
indicator.style.color = "#f8fafc";
|
|
4722
|
-
indicator.style.fontSize = "12px";
|
|
4723
|
-
indicator.style.fontWeight = "600";
|
|
4724
|
-
indicator.style.padding = "5px 14px";
|
|
4725
|
-
indicator.style.borderRadius = "20px";
|
|
4726
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4727
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4728
|
-
indicator.style.zIndex = "10";
|
|
4729
|
-
indicator.style.userSelect = "none";
|
|
4730
|
-
indicator.style.pointerEvents = "none";
|
|
4731
|
-
indicator.style.textAlign = "center";
|
|
4732
|
-
indicator.style.width = "fit-content";
|
|
4733
|
-
indicator.style.margin = "16px auto 0";
|
|
4734
|
-
ctx.container.appendChild(indicator);
|
|
4735
|
-
}
|
|
4736
5564
|
const showPage = (pageNum) => {
|
|
4737
5565
|
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4738
5566
|
if (totalPages > 1) {
|
|
@@ -4740,9 +5568,6 @@ var RtfPlugin = class {
|
|
|
4740
5568
|
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4741
5569
|
});
|
|
4742
5570
|
}
|
|
4743
|
-
if (indicator) {
|
|
4744
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4745
|
-
}
|
|
4746
5571
|
ctx.container.scrollTop = 0;
|
|
4747
5572
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4748
5573
|
};
|
|
@@ -4750,7 +5575,7 @@ var RtfPlugin = class {
|
|
|
4750
5575
|
showPage(1);
|
|
4751
5576
|
}
|
|
4752
5577
|
const cleanup = () => {
|
|
4753
|
-
|
|
5578
|
+
resizeObserver?.disconnect();
|
|
4754
5579
|
wrapper.remove();
|
|
4755
5580
|
ctx.container.innerHTML = "";
|
|
4756
5581
|
};
|
|
@@ -4761,21 +5586,25 @@ var RtfPlugin = class {
|
|
|
4761
5586
|
getCurrentPage: () => currentPage,
|
|
4762
5587
|
goToPage: (page) => showPage(page),
|
|
4763
5588
|
zoomIn: () => {
|
|
5589
|
+
isUserZoomed = true;
|
|
4764
5590
|
scale += 0.15;
|
|
4765
5591
|
applyTransform();
|
|
4766
5592
|
},
|
|
4767
5593
|
zoomOut: () => {
|
|
5594
|
+
isUserZoomed = true;
|
|
4768
5595
|
scale = Math.max(0.2, scale - 0.15);
|
|
4769
5596
|
applyTransform();
|
|
4770
5597
|
},
|
|
4771
5598
|
getZoom: () => scale,
|
|
4772
5599
|
setZoom: (level) => {
|
|
5600
|
+
isUserZoomed = true;
|
|
4773
5601
|
scale = level;
|
|
4774
5602
|
applyTransform();
|
|
4775
5603
|
},
|
|
4776
5604
|
fitToPage: () => {
|
|
4777
|
-
|
|
4778
|
-
|
|
5605
|
+
isUserZoomed = false;
|
|
5606
|
+
fitMode = "width";
|
|
5607
|
+
scale = calculateFitScale("width");
|
|
4779
5608
|
rotation = 0;
|
|
4780
5609
|
applyTransform();
|
|
4781
5610
|
},
|
|
@@ -4963,40 +5792,36 @@ var OpenDocumentPlugin = class {
|
|
|
4963
5792
|
const isPresentation = instance.isPresentation;
|
|
4964
5793
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4965
5794
|
const actions = [];
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
max
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
if (
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
instance.goToPage?.(page);
|
|
4994
|
-
} else if (typeof action === "number") {
|
|
4995
|
-
instance.goToPage?.(action);
|
|
4996
|
-
}
|
|
5795
|
+
actions.push({
|
|
5796
|
+
id: "thumbnails",
|
|
5797
|
+
icon: "thumbnails",
|
|
5798
|
+
label: isPresentation ? "Slide Thumbnails" : "Page Thumbnails",
|
|
5799
|
+
type: "button",
|
|
5800
|
+
group: "navigation",
|
|
5801
|
+
execute: () => instance.toggleThumbnails?.()
|
|
5802
|
+
});
|
|
5803
|
+
actions.push({
|
|
5804
|
+
id: "page-nav",
|
|
5805
|
+
icon: "",
|
|
5806
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
5807
|
+
type: "page-nav",
|
|
5808
|
+
group: "navigation",
|
|
5809
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
5810
|
+
max: totalPages,
|
|
5811
|
+
execute: (action, page) => {
|
|
5812
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
5813
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
5814
|
+
if (action === "prev") {
|
|
5815
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
5816
|
+
} else if (action === "next") {
|
|
5817
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
5818
|
+
} else if (typeof page === "number") {
|
|
5819
|
+
instance.goToPage?.(page);
|
|
5820
|
+
} else if (typeof action === "number") {
|
|
5821
|
+
instance.goToPage?.(action);
|
|
4997
5822
|
}
|
|
4998
|
-
}
|
|
4999
|
-
}
|
|
5823
|
+
}
|
|
5824
|
+
});
|
|
5000
5825
|
actions.push(
|
|
5001
5826
|
{
|
|
5002
5827
|
id: "zoom-out",
|
|
@@ -5087,49 +5912,65 @@ var OpenDocumentPlugin = class {
|
|
|
5087
5912
|
container.className = "fp-odf-container";
|
|
5088
5913
|
container.style.width = "100%";
|
|
5089
5914
|
container.style.height = "100%";
|
|
5090
|
-
container.style.
|
|
5091
|
-
container.style.
|
|
5915
|
+
container.style.overflowX = "hidden";
|
|
5916
|
+
container.style.overflowY = "auto";
|
|
5917
|
+
container.style.padding = "16px 8px";
|
|
5092
5918
|
container.style.backgroundColor = "#f1f5f9";
|
|
5093
5919
|
const wrapper = document.createElement("div");
|
|
5094
5920
|
wrapper.className = "fp-odf-wrapper";
|
|
5095
5921
|
wrapper.style.margin = "0 auto";
|
|
5922
|
+
wrapper.style.width = isPresentation ? "960px" : "816px";
|
|
5923
|
+
wrapper.style.boxSizing = "border-box";
|
|
5096
5924
|
wrapper.style.backgroundColor = "#ffffff";
|
|
5097
5925
|
wrapper.style.boxShadow = "0 2px 10px rgba(0,0,0,0.08)";
|
|
5098
5926
|
wrapper.style.borderRadius = "4px";
|
|
5099
5927
|
wrapper.style.transformOrigin = "top center";
|
|
5100
|
-
wrapper.style.transition = "transform 0.
|
|
5928
|
+
wrapper.style.transition = "transform 0.15s ease";
|
|
5101
5929
|
container.appendChild(wrapper);
|
|
5102
5930
|
ctx.container.appendChild(container);
|
|
5103
5931
|
let scale = 1;
|
|
5104
5932
|
let rotation = 0;
|
|
5105
|
-
let
|
|
5933
|
+
let isUserZoomed = false;
|
|
5934
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
5935
|
+
let currentPage = 1;
|
|
5936
|
+
let totalPages = 1;
|
|
5937
|
+
let slides = [];
|
|
5106
5938
|
const calculateFitScale = (mode = fitMode) => {
|
|
5107
|
-
const
|
|
5108
|
-
const
|
|
5109
|
-
const
|
|
5110
|
-
const
|
|
5939
|
+
const activeSlide = slides[currentPage - 1];
|
|
5940
|
+
const elW = isPresentation ? 960 : 816;
|
|
5941
|
+
const singlePageH = Math.min(activeSlide?.offsetHeight || wrapper.offsetHeight || 1056, Math.round(elW * 1.32));
|
|
5942
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
5943
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5111
5944
|
const sW = availW / elW;
|
|
5112
5945
|
const sH = availH / (isPresentation ? 540 : singlePageH);
|
|
5113
5946
|
if (isPresentation) {
|
|
5114
|
-
return Math.min(
|
|
5947
|
+
return Math.min(2.5, Math.min(sW, sH));
|
|
5115
5948
|
}
|
|
5116
5949
|
if (mode === "page") {
|
|
5117
|
-
return Math.max(0.
|
|
5950
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5118
5951
|
}
|
|
5119
|
-
return Math.max(0.
|
|
5952
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5120
5953
|
};
|
|
5121
5954
|
const applyTransform = () => {
|
|
5122
5955
|
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5123
5956
|
wrapper.style.transformOrigin = "top center";
|
|
5957
|
+
const activeSlide = slides[currentPage - 1];
|
|
5958
|
+
const baseH = activeSlide?.offsetHeight || wrapper.offsetHeight || 1056;
|
|
5959
|
+
const scaledH = baseH * scale;
|
|
5960
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
5961
|
+
wrapper.style.marginBottom = `${extraH + 32}px`;
|
|
5124
5962
|
};
|
|
5963
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
5964
|
+
if (!isUserZoomed) {
|
|
5965
|
+
scale = calculateFitScale(fitMode);
|
|
5966
|
+
applyTransform();
|
|
5967
|
+
}
|
|
5968
|
+
}) : null;
|
|
5969
|
+
resizeObserver?.observe(ctx.container);
|
|
5125
5970
|
setTimeout(() => {
|
|
5126
|
-
|
|
5127
|
-
scale = calculateFitScale("width");
|
|
5971
|
+
scale = calculateFitScale(fitMode);
|
|
5128
5972
|
applyTransform();
|
|
5129
5973
|
}, 60);
|
|
5130
|
-
let currentPage = 1;
|
|
5131
|
-
let totalPages = 1;
|
|
5132
|
-
let slides = [];
|
|
5133
5974
|
if (isPresentation) {
|
|
5134
5975
|
wrapper.style.maxWidth = "960px";
|
|
5135
5976
|
wrapper.style.aspectRatio = "16 / 9";
|
|
@@ -5230,24 +6071,9 @@ var OpenDocumentPlugin = class {
|
|
|
5230
6071
|
wrapper.appendChild(page);
|
|
5231
6072
|
slides.push(page);
|
|
5232
6073
|
});
|
|
5233
|
-
const pageIndicator = document.createElement("div");
|
|
5234
|
-
pageIndicator.className = "fp-odt-page-indicator";
|
|
5235
|
-
pageIndicator.style.position = "sticky";
|
|
5236
|
-
pageIndicator.style.bottom = "16px";
|
|
5237
|
-
pageIndicator.style.left = "50%";
|
|
5238
|
-
pageIndicator.style.transform = "translateX(-50%)";
|
|
5239
|
-
pageIndicator.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
|
5240
|
-
pageIndicator.style.color = "#fff";
|
|
5241
|
-
pageIndicator.style.padding = "6px 12px";
|
|
5242
|
-
pageIndicator.style.borderRadius = "16px";
|
|
5243
|
-
pageIndicator.style.fontSize = "12px";
|
|
5244
|
-
pageIndicator.style.zIndex = "100";
|
|
5245
|
-
pageIndicator.style.display = "inline-block";
|
|
5246
|
-
pageIndicator.style.width = "fit-content";
|
|
5247
|
-
pageIndicator.textContent = `Page 1 of ${totalPages}`;
|
|
5248
|
-
container.appendChild(pageIndicator);
|
|
5249
6074
|
}
|
|
5250
6075
|
const cleanup = () => {
|
|
6076
|
+
resizeObserver?.disconnect();
|
|
5251
6077
|
imageUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
5252
6078
|
container.remove();
|
|
5253
6079
|
ctx.container.innerHTML = "";
|
|
@@ -5259,10 +6085,6 @@ var OpenDocumentPlugin = class {
|
|
|
5259
6085
|
slides.forEach((s, idx) => {
|
|
5260
6086
|
s.style.display = idx === page - 1 ? "block" : "none";
|
|
5261
6087
|
});
|
|
5262
|
-
const indicator = container.querySelector(".fp-odt-page-indicator");
|
|
5263
|
-
if (indicator) {
|
|
5264
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5265
|
-
}
|
|
5266
6088
|
container.scrollTop = 0;
|
|
5267
6089
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5268
6090
|
};
|
|
@@ -5270,21 +6092,25 @@ var OpenDocumentPlugin = class {
|
|
|
5270
6092
|
destroy: cleanup,
|
|
5271
6093
|
isPresentation,
|
|
5272
6094
|
zoomIn: () => {
|
|
6095
|
+
isUserZoomed = true;
|
|
5273
6096
|
scale += 0.15;
|
|
5274
6097
|
applyTransform();
|
|
5275
6098
|
},
|
|
5276
6099
|
zoomOut: () => {
|
|
6100
|
+
isUserZoomed = true;
|
|
5277
6101
|
scale = Math.max(0.2, scale - 0.15);
|
|
5278
6102
|
applyTransform();
|
|
5279
6103
|
},
|
|
5280
6104
|
getZoom: () => scale,
|
|
5281
6105
|
setZoom: (level) => {
|
|
6106
|
+
isUserZoomed = true;
|
|
5282
6107
|
scale = level;
|
|
5283
6108
|
applyTransform();
|
|
5284
6109
|
},
|
|
5285
6110
|
fitToPage: () => {
|
|
5286
|
-
|
|
5287
|
-
|
|
6111
|
+
isUserZoomed = false;
|
|
6112
|
+
fitMode = "width";
|
|
6113
|
+
scale = calculateFitScale("width");
|
|
5288
6114
|
rotation = 0;
|
|
5289
6115
|
applyTransform();
|
|
5290
6116
|
},
|
|
@@ -5300,23 +6126,45 @@ var OpenDocumentPlugin = class {
|
|
|
5300
6126
|
getPageCount: () => totalPages,
|
|
5301
6127
|
getCurrentPage: () => currentPage,
|
|
5302
6128
|
getThumbnails: async () => {
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
canvas
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
6129
|
+
const count = totalPages || slides.length || 1;
|
|
6130
|
+
const items = [];
|
|
6131
|
+
for (let idx = 0; idx < count; idx++) {
|
|
6132
|
+
const itemIdx = idx;
|
|
6133
|
+
items.push({
|
|
6134
|
+
index: itemIdx,
|
|
6135
|
+
label: isPresentation ? `Slide ${itemIdx + 1}` : `Page ${itemIdx + 1}`,
|
|
6136
|
+
render: async (canvas) => {
|
|
6137
|
+
const ctx2d = canvas.getContext("2d");
|
|
6138
|
+
if (!ctx2d) return;
|
|
6139
|
+
if (isPresentation) {
|
|
6140
|
+
canvas.width = 160;
|
|
6141
|
+
canvas.height = 90;
|
|
6142
|
+
ctx2d.fillStyle = "#f8fafc";
|
|
6143
|
+
ctx2d.fillRect(0, 0, 160, 90);
|
|
6144
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6145
|
+
ctx2d.lineWidth = 1;
|
|
6146
|
+
ctx2d.strokeRect(0.5, 0.5, 159, 89);
|
|
6147
|
+
ctx2d.fillStyle = "#334155";
|
|
6148
|
+
ctx2d.font = "bold 11px sans-serif";
|
|
6149
|
+
ctx2d.textAlign = "center";
|
|
6150
|
+
ctx2d.fillText(`Slide ${itemIdx + 1}`, 80, 50);
|
|
6151
|
+
} else {
|
|
6152
|
+
canvas.width = 140;
|
|
6153
|
+
canvas.height = 180;
|
|
6154
|
+
ctx2d.fillStyle = "#ffffff";
|
|
6155
|
+
ctx2d.fillRect(0, 0, 140, 180);
|
|
6156
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
6157
|
+
ctx2d.lineWidth = 1;
|
|
6158
|
+
ctx2d.strokeRect(0.5, 0.5, 139, 179);
|
|
6159
|
+
ctx2d.fillStyle = "#64748b";
|
|
6160
|
+
ctx2d.font = "bold 10px sans-serif";
|
|
6161
|
+
ctx2d.textAlign = "center";
|
|
6162
|
+
ctx2d.fillText(`Page ${itemIdx + 1}`, 70, 90);
|
|
6163
|
+
}
|
|
6164
|
+
}
|
|
6165
|
+
});
|
|
6166
|
+
}
|
|
6167
|
+
return items;
|
|
5320
6168
|
},
|
|
5321
6169
|
download: () => {
|
|
5322
6170
|
const mimeType = this.mimeTypes.find((m) => m.includes(ext.replace(".", ""))) || "application/octet-stream";
|
|
@@ -5421,23 +6269,24 @@ var OpenDocumentPlugin = class {
|
|
|
5421
6269
|
case "h": {
|
|
5422
6270
|
const level = Math.min(6, Math.max(1, Number(node.getAttribute("text:outline-level") || 1)));
|
|
5423
6271
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5424
|
-
html += `<h${level} style="${style}; font-family:
|
|
6272
|
+
html += `<h${level} style="${style}; margin: 18px 0 8px; color: #1e3a8a; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${node.textContent || ""}</h${level}>`;
|
|
5425
6273
|
break;
|
|
5426
6274
|
}
|
|
5427
6275
|
case "p": {
|
|
5428
6276
|
const style = styles.get(node.getAttribute("text:style-name") || "") || "";
|
|
5429
6277
|
const inner = this.renderSpans(node, styles, images);
|
|
5430
|
-
|
|
6278
|
+
const isInsideLi = node.parentElement?.localName === "list-item" || node.parentElement?.tagName?.toLowerCase() === "list-item";
|
|
6279
|
+
html += `<p style="${style}; line-height: 1.5; margin: ${isInsideLi ? "0" : "8px 0 12px"}; font-family: Calibri, 'Segoe UI', Arial, sans-serif;">${inner}</p>`;
|
|
5431
6280
|
break;
|
|
5432
6281
|
}
|
|
5433
6282
|
case "list": {
|
|
5434
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
6283
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
5435
6284
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5436
6285
|
html += "</ul>";
|
|
5437
6286
|
break;
|
|
5438
6287
|
}
|
|
5439
6288
|
case "list-item": {
|
|
5440
|
-
html +=
|
|
6289
|
+
html += '<li style="margin: 4px 0; font-size: 11pt; line-height: 1.5; color: #1e293b;">';
|
|
5441
6290
|
Array.from(node.children).forEach((c) => walk(c));
|
|
5442
6291
|
html += "</li>";
|
|
5443
6292
|
break;
|
|
@@ -5563,28 +6412,26 @@ var DocPlugin = class {
|
|
|
5563
6412
|
getToolbarActions(instance) {
|
|
5564
6413
|
const totalPages = instance.getPageCount?.() ?? 1;
|
|
5565
6414
|
const actions = [];
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
if (
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
instance.goToPage?.(page);
|
|
5584
|
-
}
|
|
6415
|
+
actions.push({
|
|
6416
|
+
id: "page-nav",
|
|
6417
|
+
icon: "",
|
|
6418
|
+
label: "Page Navigation",
|
|
6419
|
+
type: "page-nav",
|
|
6420
|
+
group: "navigation",
|
|
6421
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
6422
|
+
max: totalPages,
|
|
6423
|
+
execute: (action, page) => {
|
|
6424
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
6425
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
6426
|
+
if (action === "prev") {
|
|
6427
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
6428
|
+
} else if (action === "next") {
|
|
6429
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
6430
|
+
} else if (typeof page === "number") {
|
|
6431
|
+
instance.goToPage?.(page);
|
|
5585
6432
|
}
|
|
5586
|
-
}
|
|
5587
|
-
}
|
|
6433
|
+
}
|
|
6434
|
+
});
|
|
5588
6435
|
actions.push(
|
|
5589
6436
|
{
|
|
5590
6437
|
id: "zoom-out",
|
|
@@ -5658,8 +6505,9 @@ var DocPlugin = class {
|
|
|
5658
6505
|
container.className = "fp-doc-container";
|
|
5659
6506
|
container.style.width = "100%";
|
|
5660
6507
|
container.style.height = "100%";
|
|
5661
|
-
container.style.
|
|
5662
|
-
container.style.
|
|
6508
|
+
container.style.overflowX = "hidden";
|
|
6509
|
+
container.style.overflowY = "auto";
|
|
6510
|
+
container.style.padding = "16px 8px";
|
|
5663
6511
|
container.style.backgroundColor = "#f1f5f9";
|
|
5664
6512
|
container.style.display = "flex";
|
|
5665
6513
|
container.style.justifyContent = "center";
|
|
@@ -5668,8 +6516,17 @@ var DocPlugin = class {
|
|
|
5668
6516
|
let scale = 1;
|
|
5669
6517
|
let extractedRawText = "";
|
|
5670
6518
|
let isFallback = false;
|
|
6519
|
+
let chartSvg = "";
|
|
5671
6520
|
try {
|
|
5672
6521
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
6522
|
+
try {
|
|
6523
|
+
const pkg = cfbf.readStream("package_stream");
|
|
6524
|
+
if (pkg && pkg.length > 100) {
|
|
6525
|
+
chartSvg = this.parseOdfChartToSvg(pkg);
|
|
6526
|
+
}
|
|
6527
|
+
} catch (chartErr) {
|
|
6528
|
+
console.warn("[DocPlugin] Chart stream parsing info:", chartErr);
|
|
6529
|
+
}
|
|
5673
6530
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
5674
6531
|
if (!wordDocStream || wordDocStream.length < 512) {
|
|
5675
6532
|
throw new Error("WordDocument stream not found or invalid in CFBF archive");
|
|
@@ -5687,7 +6544,7 @@ var DocPlugin = class {
|
|
|
5687
6544
|
extractedRawText = fallback;
|
|
5688
6545
|
isFallback = true;
|
|
5689
6546
|
}
|
|
5690
|
-
const rawPages = this.splitIntoPages(extractedRawText);
|
|
6547
|
+
const rawPages = this.splitIntoPages(extractedRawText, chartSvg);
|
|
5691
6548
|
const totalPages = Math.max(1, rawPages.length);
|
|
5692
6549
|
let currentPage = 1;
|
|
5693
6550
|
const pageCards = [];
|
|
@@ -5695,16 +6552,15 @@ var DocPlugin = class {
|
|
|
5695
6552
|
const pageCard = document.createElement("div");
|
|
5696
6553
|
pageCard.className = "fp-doc-page-card";
|
|
5697
6554
|
pageCard.style.width = "816px";
|
|
5698
|
-
pageCard.style.
|
|
6555
|
+
pageCard.style.minHeight = "1056px";
|
|
5699
6556
|
pageCard.style.backgroundColor = "#ffffff";
|
|
5700
|
-
pageCard.style.boxShadow = "0
|
|
6557
|
+
pageCard.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
5701
6558
|
pageCard.style.borderRadius = "4px";
|
|
5702
|
-
pageCard.style.padding = "
|
|
6559
|
+
pageCard.style.padding = "72px 56px";
|
|
5703
6560
|
pageCard.style.boxSizing = "border-box";
|
|
5704
|
-
pageCard.style.overflow = "hidden";
|
|
5705
6561
|
pageCard.style.display = i === 0 ? "block" : "none";
|
|
5706
6562
|
pageCard.style.transformOrigin = "top center";
|
|
5707
|
-
pageCard.style.transition = "transform 0.
|
|
6563
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
5708
6564
|
pageCard.style.fontFamily = 'Calibri, "Segoe UI", Arial, sans-serif';
|
|
5709
6565
|
pageCard.style.color = "#1e293b";
|
|
5710
6566
|
if (isFallback && i === 0) {
|
|
@@ -5721,34 +6577,15 @@ var DocPlugin = class {
|
|
|
5721
6577
|
container.appendChild(pageCard);
|
|
5722
6578
|
pageCards.push(pageCard);
|
|
5723
6579
|
}
|
|
5724
|
-
let indicator = null;
|
|
5725
|
-
if (totalPages > 1) {
|
|
5726
|
-
indicator = document.createElement("div");
|
|
5727
|
-
indicator.className = "fp-doc-page-indicator";
|
|
5728
|
-
indicator.style.position = "fixed";
|
|
5729
|
-
indicator.style.bottom = "16px";
|
|
5730
|
-
indicator.style.left = "50%";
|
|
5731
|
-
indicator.style.transform = "translateX(-50%)";
|
|
5732
|
-
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
5733
|
-
indicator.style.backdropFilter = "blur(8px)";
|
|
5734
|
-
indicator.style.color = "#f8fafc";
|
|
5735
|
-
indicator.style.fontSize = "12px";
|
|
5736
|
-
indicator.style.fontWeight = "600";
|
|
5737
|
-
indicator.style.padding = "5px 14px";
|
|
5738
|
-
indicator.style.borderRadius = "20px";
|
|
5739
|
-
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
5740
|
-
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
5741
|
-
indicator.style.zIndex = "10";
|
|
5742
|
-
indicator.style.userSelect = "none";
|
|
5743
|
-
indicator.style.pointerEvents = "none";
|
|
5744
|
-
indicator.style.textAlign = "center";
|
|
5745
|
-
container.appendChild(indicator);
|
|
5746
|
-
}
|
|
5747
6580
|
let rotation = 0;
|
|
5748
6581
|
const applyTransform = () => {
|
|
5749
6582
|
const activeCard = pageCards[currentPage - 1];
|
|
5750
6583
|
if (activeCard) {
|
|
5751
6584
|
activeCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
6585
|
+
const baseH = activeCard.offsetHeight || 1056;
|
|
6586
|
+
const scaledH = baseH * scale;
|
|
6587
|
+
const extraH = Math.max(0, scaledH - baseH);
|
|
6588
|
+
activeCard.style.marginBottom = `${extraH + 32}px`;
|
|
5752
6589
|
}
|
|
5753
6590
|
};
|
|
5754
6591
|
const showPage = (pageNum) => {
|
|
@@ -5761,35 +6598,39 @@ var DocPlugin = class {
|
|
|
5761
6598
|
card.style.display = "none";
|
|
5762
6599
|
}
|
|
5763
6600
|
});
|
|
5764
|
-
if (indicator) {
|
|
5765
|
-
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5766
|
-
}
|
|
5767
6601
|
container.scrollTop = 0;
|
|
5768
6602
|
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5769
6603
|
};
|
|
5770
6604
|
if (totalPages > 1) {
|
|
5771
6605
|
showPage(1);
|
|
5772
6606
|
}
|
|
5773
|
-
let fitMode = "width";
|
|
6607
|
+
let fitMode = ctx?.options?.fitMode || "width";
|
|
6608
|
+
let isUserZoomed = false;
|
|
5774
6609
|
const calculateFitScale = (mode = fitMode) => {
|
|
5775
6610
|
const elW = 816;
|
|
5776
6611
|
const elH = 1056;
|
|
5777
|
-
const availW = Math.max(280, ctx.container.clientWidth -
|
|
5778
|
-
const availH = Math.max(280, ctx.container.clientHeight -
|
|
6612
|
+
const availW = Math.max(280, ctx.container.clientWidth - 32);
|
|
6613
|
+
const availH = Math.max(280, ctx.container.clientHeight - 32);
|
|
5779
6614
|
const sW = availW / elW;
|
|
5780
6615
|
const sH = availH / elH;
|
|
5781
6616
|
if (mode === "page") {
|
|
5782
|
-
return Math.max(0.
|
|
6617
|
+
return Math.max(0.35, Math.min(3, Math.min(sW, sH)));
|
|
5783
6618
|
}
|
|
5784
|
-
return Math.max(0.
|
|
6619
|
+
return Math.max(0.4, Math.min(3, sW));
|
|
5785
6620
|
};
|
|
6621
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
6622
|
+
if (!isUserZoomed) {
|
|
6623
|
+
scale = calculateFitScale(fitMode);
|
|
6624
|
+
applyTransform();
|
|
6625
|
+
}
|
|
6626
|
+
}) : null;
|
|
6627
|
+
resizeObserver?.observe(ctx.container);
|
|
5786
6628
|
setTimeout(() => {
|
|
5787
|
-
|
|
5788
|
-
scale = calculateFitScale("width");
|
|
6629
|
+
scale = calculateFitScale(fitMode);
|
|
5789
6630
|
applyTransform();
|
|
5790
6631
|
}, 60);
|
|
5791
6632
|
const cleanup = () => {
|
|
5792
|
-
|
|
6633
|
+
resizeObserver?.disconnect();
|
|
5793
6634
|
container.remove();
|
|
5794
6635
|
ctx.container.innerHTML = "";
|
|
5795
6636
|
};
|
|
@@ -5800,21 +6641,25 @@ var DocPlugin = class {
|
|
|
5800
6641
|
getCurrentPage: () => currentPage,
|
|
5801
6642
|
goToPage: (page) => showPage(page),
|
|
5802
6643
|
zoomIn: () => {
|
|
6644
|
+
isUserZoomed = true;
|
|
5803
6645
|
scale += 0.15;
|
|
5804
6646
|
applyTransform();
|
|
5805
6647
|
},
|
|
5806
6648
|
zoomOut: () => {
|
|
6649
|
+
isUserZoomed = true;
|
|
5807
6650
|
scale = Math.max(0.2, scale - 0.15);
|
|
5808
6651
|
applyTransform();
|
|
5809
6652
|
},
|
|
5810
6653
|
getZoom: () => scale,
|
|
5811
6654
|
setZoom: (level) => {
|
|
6655
|
+
isUserZoomed = true;
|
|
5812
6656
|
scale = level;
|
|
5813
6657
|
applyTransform();
|
|
5814
6658
|
},
|
|
5815
6659
|
fitToPage: () => {
|
|
5816
|
-
|
|
5817
|
-
|
|
6660
|
+
isUserZoomed = false;
|
|
6661
|
+
fitMode = "width";
|
|
6662
|
+
scale = calculateFitScale("width");
|
|
5818
6663
|
rotation = 0;
|
|
5819
6664
|
applyTransform();
|
|
5820
6665
|
},
|
|
@@ -5929,7 +6774,7 @@ var DocPlugin = class {
|
|
|
5929
6774
|
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
5930
6775
|
const trimmed = run.trim();
|
|
5931
6776
|
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
5932
|
-
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)) {
|
|
6777
|
+
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)) {
|
|
5933
6778
|
seen.add(trimmed);
|
|
5934
6779
|
candidateLines.push(trimmed);
|
|
5935
6780
|
}
|
|
@@ -5940,9 +6785,114 @@ var DocPlugin = class {
|
|
|
5940
6785
|
heuristicTextExtraction(buffer) {
|
|
5941
6786
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
5942
6787
|
}
|
|
5943
|
-
|
|
6788
|
+
/**
|
|
6789
|
+
* Parses an embedded OpenDocument Chart package into a vector SVG bar/column chart
|
|
6790
|
+
*/
|
|
6791
|
+
parseOdfChartToSvg(zipBytes) {
|
|
6792
|
+
try {
|
|
6793
|
+
const unzipped = fflate.unzipSync(zipBytes);
|
|
6794
|
+
const contentXml = unzipped["content.xml"] ? new TextDecoder("utf-8").decode(unzipped["content.xml"]) : "";
|
|
6795
|
+
if (!contentXml) return "";
|
|
6796
|
+
const rowsMatch = contentXml.match(/<table:table-row[\s\S]*?<\/table:table-row>/g) || [];
|
|
6797
|
+
if (rowsMatch.length < 2) return "";
|
|
6798
|
+
const headers = [];
|
|
6799
|
+
const firstRow = rowsMatch[0];
|
|
6800
|
+
const headerCells = firstRow ? firstRow.match(/<text:p>([^<]+)<\/text:p>/g) || [] : [];
|
|
6801
|
+
for (const h2 of headerCells) {
|
|
6802
|
+
headers.push(h2.replace(/<\/?text:p>/g, "").trim());
|
|
6803
|
+
}
|
|
6804
|
+
const categories = [];
|
|
6805
|
+
const seriesValues = headers.map(() => []);
|
|
6806
|
+
for (let r = 1; r < rowsMatch.length; r++) {
|
|
6807
|
+
const rowStr = rowsMatch[r];
|
|
6808
|
+
if (!rowStr) continue;
|
|
6809
|
+
const cells = rowStr.match(/<table:table-cell[\s\S]*?<\/table:table-cell>/g) || [];
|
|
6810
|
+
if (cells.length > 0 && cells[0]) {
|
|
6811
|
+
const catMatch = cells[0].match(/<text:p>([^<]+)<\/text:p>/);
|
|
6812
|
+
categories.push(catMatch ? catMatch[1] : "Row " + r);
|
|
6813
|
+
for (let c = 1; c < cells.length && c - 1 < headers.length; c++) {
|
|
6814
|
+
const cellStr = cells[c];
|
|
6815
|
+
if (!cellStr) continue;
|
|
6816
|
+
const valMatch = cellStr.match(/office:value="([0-9.]+)"/) || cellStr.match(/<text:p>([0-9.]+)<\/text:p>/);
|
|
6817
|
+
const series = seriesValues[c - 1];
|
|
6818
|
+
if (series) {
|
|
6819
|
+
series.push(valMatch ? parseFloat(valMatch[1]) : 0);
|
|
6820
|
+
}
|
|
6821
|
+
}
|
|
6822
|
+
}
|
|
6823
|
+
}
|
|
6824
|
+
const colors = ["#004586", "#ff420e", "#ffd320", "#579d1c", "#7e0021"];
|
|
6825
|
+
const colorMatches = contentXml.matchAll(/draw:fill-color="(#[0-9a-fA-F]{6})"/g);
|
|
6826
|
+
let cIdx = 0;
|
|
6827
|
+
for (const cm of colorMatches) {
|
|
6828
|
+
if (cIdx < colors.length) colors[cIdx] = cm[1];
|
|
6829
|
+
cIdx++;
|
|
6830
|
+
}
|
|
6831
|
+
let maxVal = 10;
|
|
6832
|
+
for (const s of seriesValues) {
|
|
6833
|
+
for (const v of s) {
|
|
6834
|
+
if (v > maxVal) maxVal = v;
|
|
6835
|
+
}
|
|
6836
|
+
}
|
|
6837
|
+
maxVal = Math.ceil(maxVal * 1.15);
|
|
6838
|
+
const width = 560;
|
|
6839
|
+
const height = 280;
|
|
6840
|
+
const padLeft = 45;
|
|
6841
|
+
const padRight = 100;
|
|
6842
|
+
const padTop = 20;
|
|
6843
|
+
const padBottom = 40;
|
|
6844
|
+
const chartW = width - padLeft - padRight;
|
|
6845
|
+
const chartH = height - padTop - padBottom;
|
|
6846
|
+
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);">`;
|
|
6847
|
+
for (let step = 0; step <= 4; step++) {
|
|
6848
|
+
const yVal = (maxVal / 4 * step).toFixed(1);
|
|
6849
|
+
const yPos = padTop + chartH - step / 4 * chartH;
|
|
6850
|
+
svg += `<line x1="${padLeft}" y1="${yPos}" x2="${padLeft + chartW}" y2="${yPos}" stroke="#e2e8f0" stroke-dasharray="2,2" />`;
|
|
6851
|
+
svg += `<text x="${padLeft - 8}" y="${yPos + 4}" font-size="11" fill="#64748b" text-anchor="end">${yVal}</text>`;
|
|
6852
|
+
}
|
|
6853
|
+
const numCats = categories.length;
|
|
6854
|
+
const numSeries = headers.length;
|
|
6855
|
+
const groupW = chartW / numCats;
|
|
6856
|
+
const barW = Math.max(8, groupW * 0.7 / numSeries);
|
|
6857
|
+
const groupPad = (groupW - barW * numSeries) / 2;
|
|
6858
|
+
for (let catIdx = 0; catIdx < numCats; catIdx++) {
|
|
6859
|
+
const groupX = padLeft + catIdx * groupW + groupPad;
|
|
6860
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6861
|
+
const val = seriesValues[sIdx][catIdx] || 0;
|
|
6862
|
+
const barH = val / maxVal * chartH;
|
|
6863
|
+
const barX = groupX + sIdx * barW;
|
|
6864
|
+
const barY = padTop + chartH - barH;
|
|
6865
|
+
const col = colors[sIdx % colors.length];
|
|
6866
|
+
svg += `<rect x="${barX}" y="${barY}" width="${barW - 2}" height="${barH}" fill="${col}" rx="2"><title>${headers[sIdx]}: ${val}</title></rect>`;
|
|
6867
|
+
}
|
|
6868
|
+
const catX = padLeft + catIdx * groupW + groupW / 2;
|
|
6869
|
+
svg += `<text x="${catX}" y="${padTop + chartH + 18}" font-size="11" fill="#475569" text-anchor="middle">${categories[catIdx]}</text>`;
|
|
6870
|
+
}
|
|
6871
|
+
let legendY = padTop + 20;
|
|
6872
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6873
|
+
const col = colors[sIdx % colors.length];
|
|
6874
|
+
svg += `<rect x="${padLeft + chartW + 15}" y="${legendY}" width="12" height="12" fill="${col}" rx="2" />`;
|
|
6875
|
+
svg += `<text x="${padLeft + chartW + 32}" y="${legendY + 10}" font-size="11" fill="#334155">${headers[sIdx]}</text>`;
|
|
6876
|
+
legendY += 20;
|
|
6877
|
+
}
|
|
6878
|
+
svg += "</svg>";
|
|
6879
|
+
return svg;
|
|
6880
|
+
} catch (e) {
|
|
6881
|
+
console.warn("[DocPlugin] Error generating chart SVG:", e);
|
|
6882
|
+
return "";
|
|
6883
|
+
}
|
|
6884
|
+
}
|
|
6885
|
+
cleanWordDocFields(text, chartSvg = "") {
|
|
5944
6886
|
if (!text) return "";
|
|
5945
6887
|
let cleaned = text.replace(
|
|
6888
|
+
/\x13\s*EMBED\b[\s\S]*?\x15/gi,
|
|
6889
|
+
() => chartSvg ? `
|
|
6890
|
+
|
|
6891
|
+
${chartSvg}
|
|
6892
|
+
|
|
6893
|
+
` : ""
|
|
6894
|
+
);
|
|
6895
|
+
cleaned = cleaned.replace(
|
|
5946
6896
|
/\x13\s*HYPERLINK\s*"?([^"\x14]+)"?\s*\x14([\s\S]*?)\x15/gi,
|
|
5947
6897
|
(_match, url, label) => {
|
|
5948
6898
|
const cleanUrl = url.trim();
|
|
@@ -5950,18 +6900,23 @@ var DocPlugin = class {
|
|
|
5950
6900
|
return `<a href="${cleanUrl}" target="_blank" rel="noopener noreferrer" style="color: #2563eb; text-decoration: underline;">${cleanLabel}</a>`;
|
|
5951
6901
|
}
|
|
5952
6902
|
);
|
|
5953
|
-
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g,
|
|
6903
|
+
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g, (_m, res) => {
|
|
6904
|
+
if (/[\x00-\x1F]/.test(res)) return "";
|
|
6905
|
+
return res.trim();
|
|
6906
|
+
});
|
|
5954
6907
|
cleaned = cleaned.replace(/\x13[^\x15]*\x15/g, "");
|
|
5955
6908
|
cleaned = cleaned.replace(/[\x13\x14\x15]/g, "");
|
|
6909
|
+
cleaned = cleaned.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/g, "");
|
|
6910
|
+
cleaned = cleaned.replace(/EMBED\s+LibreOffice\.ChartDocument\.[0-9]+/gi, chartSvg || "");
|
|
5956
6911
|
return cleaned;
|
|
5957
6912
|
}
|
|
5958
|
-
splitIntoPages(text) {
|
|
6913
|
+
splitIntoPages(text, chartSvg = "") {
|
|
5959
6914
|
if (!text) return [""];
|
|
5960
|
-
const cleanedText = this.cleanWordDocFields(text);
|
|
6915
|
+
const cleanedText = this.cleanWordDocFields(text, chartSvg);
|
|
5961
6916
|
const normalized = cleanedText.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ");
|
|
5962
6917
|
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);
|
|
5963
6918
|
if (explicitParts.length === 0) explicitParts.push(normalized);
|
|
5964
|
-
const maxLinesPerPage =
|
|
6919
|
+
const maxLinesPerPage = 34;
|
|
5965
6920
|
const charsPerLine = 80;
|
|
5966
6921
|
const finalPages = [];
|
|
5967
6922
|
for (const part of explicitParts) {
|
|
@@ -5969,8 +6924,8 @@ var DocPlugin = class {
|
|
|
5969
6924
|
let currentLines = [];
|
|
5970
6925
|
let count = 0;
|
|
5971
6926
|
for (const line of lines) {
|
|
5972
|
-
const
|
|
5973
|
-
const vLines = Math.max(1, Math.ceil((
|
|
6927
|
+
const isSvg = line.includes("<svg");
|
|
6928
|
+
const vLines = isSvg ? 12 : Math.max(1, Math.ceil((line.replace(/<[^>]+>/g, "").length || 1) / charsPerLine));
|
|
5974
6929
|
if (count + vLines > maxLinesPerPage && currentLines.length > 0) {
|
|
5975
6930
|
finalPages.push(currentLines.join("\n"));
|
|
5976
6931
|
currentLines = [];
|
|
@@ -6010,9 +6965,44 @@ var DocPlugin = class {
|
|
|
6010
6965
|
tableLines = [];
|
|
6011
6966
|
}
|
|
6012
6967
|
};
|
|
6968
|
+
const sanitizeOptions = {
|
|
6969
|
+
ADD_TAGS: ["a", "svg", "g", "path", "line", "rect", "circle", "text", "title"],
|
|
6970
|
+
ADD_ATTR: [
|
|
6971
|
+
"href",
|
|
6972
|
+
"target",
|
|
6973
|
+
"rel",
|
|
6974
|
+
"style",
|
|
6975
|
+
"viewBox",
|
|
6976
|
+
"width",
|
|
6977
|
+
"height",
|
|
6978
|
+
"x",
|
|
6979
|
+
"y",
|
|
6980
|
+
"x1",
|
|
6981
|
+
"y1",
|
|
6982
|
+
"x2",
|
|
6983
|
+
"y2",
|
|
6984
|
+
"fill",
|
|
6985
|
+
"stroke",
|
|
6986
|
+
"stroke-width",
|
|
6987
|
+
"stroke-dasharray",
|
|
6988
|
+
"rx",
|
|
6989
|
+
"font-size",
|
|
6990
|
+
"text-anchor"
|
|
6991
|
+
]
|
|
6992
|
+
};
|
|
6013
6993
|
let i = 0;
|
|
6014
6994
|
while (i < lines.length) {
|
|
6015
6995
|
let line = lines[i];
|
|
6996
|
+
if (line.includes("<svg")) {
|
|
6997
|
+
if (inList) {
|
|
6998
|
+
html += "</ul>";
|
|
6999
|
+
inList = false;
|
|
7000
|
+
}
|
|
7001
|
+
flushTable();
|
|
7002
|
+
html += line;
|
|
7003
|
+
i++;
|
|
7004
|
+
continue;
|
|
7005
|
+
}
|
|
6016
7006
|
let tabCount = (line.match(/\t/g) || []).length;
|
|
6017
7007
|
if (tabCount > 0) {
|
|
6018
7008
|
let j = i;
|
|
@@ -6046,26 +7036,31 @@ var DocPlugin = class {
|
|
|
6046
7036
|
i++;
|
|
6047
7037
|
continue;
|
|
6048
7038
|
}
|
|
6049
|
-
|
|
6050
|
-
|
|
7039
|
+
if (/^\d{1,2}$/.test(line.trim())) {
|
|
7040
|
+
i++;
|
|
7041
|
+
continue;
|
|
7042
|
+
}
|
|
7043
|
+
const isShortLine = line.length < 60 && !line.endsWith(".") && !line.endsWith(",");
|
|
7044
|
+
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));
|
|
7045
|
+
if (isTitleLike) {
|
|
6051
7046
|
if (inList) {
|
|
6052
7047
|
html += "</ul>";
|
|
6053
7048
|
inList = false;
|
|
6054
7049
|
}
|
|
6055
|
-
html += `<h2 style="font-size:
|
|
7050
|
+
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>`;
|
|
6056
7051
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
6057
7052
|
if (!inList) {
|
|
6058
|
-
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
7053
|
+
html += '<ul style="margin: 8px 0 12px; padding-left: 24px;">';
|
|
6059
7054
|
inList = true;
|
|
6060
7055
|
}
|
|
6061
7056
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
6062
|
-
html += `<li style="margin: 4px 0; line-height: 1.
|
|
7057
|
+
html += `<li style="margin: 4px 0; line-height: 1.5; font-size: 11pt; color: #1e293b;">${DOMPurify6.sanitize(bulletText, sanitizeOptions)}</li>`;
|
|
6063
7058
|
} else {
|
|
6064
7059
|
if (inList) {
|
|
6065
7060
|
html += "</ul>";
|
|
6066
7061
|
inList = false;
|
|
6067
7062
|
}
|
|
6068
|
-
html += `<p style="line-height: 1.
|
|
7063
|
+
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>`;
|
|
6069
7064
|
}
|
|
6070
7065
|
i++;
|
|
6071
7066
|
}
|