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