@files-preview-app/preview-file 1.1.3 → 1.1.5
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/LICENSE +21 -21
- package/README.md +674 -674
- package/THIRD_PARTY_LICENSES.md +18 -18
- package/dist/angular.cjs +175 -15
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +175 -15
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +175 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +175 -15
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +175 -15
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +175 -15
- package/dist/react.js.map +1 -1
- package/dist/styles.css +202 -190
- package/dist/vue.cjs +175 -15
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +175 -15
- package/dist/vue.js.map +1 -1
- package/package.json +161 -161
package/dist/react.cjs
CHANGED
|
@@ -372,8 +372,39 @@ function createElement(tag, attrs, ...children) {
|
|
|
372
372
|
}
|
|
373
373
|
return el;
|
|
374
374
|
}
|
|
375
|
+
var ICON_ZOOM_IN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="11" y1="8" x2="11" y2="14"></line><line x1="8" y1="11" x2="14" y2="11"></line></svg>`;
|
|
376
|
+
var ICON_ZOOM_OUT = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="8" y1="11" x2="14" y2="11"></line></svg>`;
|
|
377
|
+
var ICON_FIT_PAGE = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" y1="3" x2="14" y2="10"></line><line x1="3" y1="21" x2="10" y2="14"></line></svg>`;
|
|
378
|
+
var ICON_ROTATE_CW = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"></polyline><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path></svg>`;
|
|
379
|
+
var ICON_ROTATE_CCW = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="1 4 1 10 7 10"></polyline><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"></path></svg>`;
|
|
380
|
+
var ICON_DOWNLOAD = `<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="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>`;
|
|
381
|
+
var ICON_PRINT = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 6 2 18 2 18 9"></polyline><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"></path><rect x="6" y="14" width="12" height="8"></rect></svg>`;
|
|
375
382
|
var ICON_PAGE_PREV = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"></polyline></svg>`;
|
|
376
383
|
var ICON_PAGE_NEXT = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>`;
|
|
384
|
+
var ICON_PLAY = `<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="5 3 19 12 5 21 5 3"></polygon></svg>`;
|
|
385
|
+
var ICON_PAUSE = `<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="6" y="4" width="4" height="16"></rect><rect x="14" y="4" width="4" height="16"></rect></svg>`;
|
|
386
|
+
var ICON_THUMBNAILS = `<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="7" height="7"></rect><rect x="14" y="3" width="7" height="7"></rect><rect x="14" y="14" width="7" height="7"></rect><rect x="3" y="14" width="7" height="7"></rect></svg>`;
|
|
387
|
+
var ICON_CLOSE = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>`;
|
|
388
|
+
var ICON_FULLSCREEN = `<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="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"></path></svg>`;
|
|
389
|
+
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>`;
|
|
390
|
+
var ICON_MAP = {
|
|
391
|
+
"zoom-in": ICON_ZOOM_IN,
|
|
392
|
+
"zoom-out": ICON_ZOOM_OUT,
|
|
393
|
+
"fit-page": ICON_FIT_PAGE,
|
|
394
|
+
"fit-slide": ICON_FIT_PAGE,
|
|
395
|
+
"rotate-cw": ICON_ROTATE_CW,
|
|
396
|
+
"rotate-ccw": ICON_ROTATE_CCW,
|
|
397
|
+
"download": ICON_DOWNLOAD,
|
|
398
|
+
"print": ICON_PRINT,
|
|
399
|
+
"thumbnails": ICON_THUMBNAILS,
|
|
400
|
+
"fullscreen": ICON_FULLSCREEN,
|
|
401
|
+
"play": ICON_PLAY,
|
|
402
|
+
"pause": ICON_PAUSE,
|
|
403
|
+
"close": ICON_CLOSE,
|
|
404
|
+
"copy": ICON_COPY,
|
|
405
|
+
"prev": ICON_PAGE_PREV,
|
|
406
|
+
"next": ICON_PAGE_NEXT
|
|
407
|
+
};
|
|
377
408
|
var ToolbarController = class {
|
|
378
409
|
el;
|
|
379
410
|
toolbarEl;
|
|
@@ -484,10 +515,11 @@ var ToolbarController = class {
|
|
|
484
515
|
type: "button",
|
|
485
516
|
"data-action-id": id
|
|
486
517
|
});
|
|
487
|
-
|
|
488
|
-
|
|
518
|
+
const svg = ICON_MAP[iconHtml] || iconHtml;
|
|
519
|
+
if (svg && svg.startsWith("<svg")) {
|
|
520
|
+
btn.innerHTML = sanitizeSVG(svg);
|
|
489
521
|
} else {
|
|
490
|
-
btn.textContent =
|
|
522
|
+
btn.textContent = svg || title;
|
|
491
523
|
}
|
|
492
524
|
btn.addEventListener("click", onClick);
|
|
493
525
|
return btn;
|
|
@@ -568,6 +600,9 @@ var FilePreviewViewer = class {
|
|
|
568
600
|
contentEl = null;
|
|
569
601
|
currentBuffer = null;
|
|
570
602
|
currentMetadata = null;
|
|
603
|
+
keyHandler = null;
|
|
604
|
+
currentContainer = null;
|
|
605
|
+
currentOptions = {};
|
|
571
606
|
/**
|
|
572
607
|
* Register a preview plugin.
|
|
573
608
|
*/
|
|
@@ -622,24 +657,47 @@ var FilePreviewViewer = class {
|
|
|
622
657
|
emit: (event, payload) => this.eventEmitter.emit(event, payload)
|
|
623
658
|
});
|
|
624
659
|
this.activeInstance = instance;
|
|
660
|
+
this.hideLoading();
|
|
661
|
+
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
625
662
|
if (options.showToolbar !== false && this.toolbar) {
|
|
626
663
|
const actions = matchedPlugin.getToolbarActions(instance);
|
|
664
|
+
const hasFullscreen = actions.some((a) => a.id === "fullscreen");
|
|
665
|
+
if (!hasFullscreen && this.wrapperEl) {
|
|
666
|
+
actions.push({
|
|
667
|
+
id: "fullscreen",
|
|
668
|
+
icon: "fullscreen",
|
|
669
|
+
label: "Toggle Fullscreen",
|
|
670
|
+
type: "button",
|
|
671
|
+
group: "view",
|
|
672
|
+
execute: () => {
|
|
673
|
+
if (!document.fullscreenElement) {
|
|
674
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
675
|
+
} else {
|
|
676
|
+
document.exitFullscreen?.();
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
});
|
|
680
|
+
}
|
|
627
681
|
this.toolbar.update(actions);
|
|
628
682
|
this.toolbar.show();
|
|
629
683
|
}
|
|
630
684
|
if (instance.getThumbnails && this.thumbnailPanel) {
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
685
|
+
Promise.resolve().then(async () => {
|
|
686
|
+
try {
|
|
687
|
+
const thumbnails = await Promise.resolve(instance.getThumbnails());
|
|
688
|
+
if (thumbnails && thumbnails.length > 0 && this.thumbnailPanel) {
|
|
689
|
+
this.thumbnailPanel.update(thumbnails, (index) => {
|
|
690
|
+
instance.goToPage?.(index + 1);
|
|
691
|
+
});
|
|
692
|
+
if (options.showThumbnails) {
|
|
693
|
+
this.thumbnailPanel.show();
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
} catch (e) {
|
|
697
|
+
console.warn("[FilePreview] Non-critical thumbnail load error:", e);
|
|
638
698
|
}
|
|
639
|
-
}
|
|
699
|
+
});
|
|
640
700
|
}
|
|
641
|
-
this.hideLoading();
|
|
642
|
-
this.eventEmitter.emit("loaded", { metadata, plugin: matchedPlugin.id });
|
|
643
701
|
return instance;
|
|
644
702
|
} catch (error) {
|
|
645
703
|
this.hideLoading();
|
|
@@ -661,6 +719,10 @@ var FilePreviewViewer = class {
|
|
|
661
719
|
* Destroy the viewer and clean up all resources.
|
|
662
720
|
*/
|
|
663
721
|
destroy() {
|
|
722
|
+
if (this.keyHandler) {
|
|
723
|
+
window.removeEventListener("keydown", this.keyHandler);
|
|
724
|
+
this.keyHandler = null;
|
|
725
|
+
}
|
|
664
726
|
this.abort();
|
|
665
727
|
this.destroyInstance();
|
|
666
728
|
this.toolbar?.destroy();
|
|
@@ -676,6 +738,7 @@ var FilePreviewViewer = class {
|
|
|
676
738
|
this.thumbnailPanel = null;
|
|
677
739
|
this.currentBuffer = null;
|
|
678
740
|
this.currentMetadata = null;
|
|
741
|
+
this.currentContainer = null;
|
|
679
742
|
}
|
|
680
743
|
/**
|
|
681
744
|
* Get the currently active preview instance.
|
|
@@ -705,6 +768,8 @@ var FilePreviewViewer = class {
|
|
|
705
768
|
return null;
|
|
706
769
|
}
|
|
707
770
|
setupDOM(container, options) {
|
|
771
|
+
this.currentContainer = container;
|
|
772
|
+
this.currentOptions = options;
|
|
708
773
|
if (this.wrapperEl?.parentNode === container) return;
|
|
709
774
|
if (this.wrapperEl?.parentNode) {
|
|
710
775
|
this.wrapperEl.parentNode.removeChild(this.wrapperEl);
|
|
@@ -713,6 +778,7 @@ var FilePreviewViewer = class {
|
|
|
713
778
|
const toolbarPos = options.toolbarPosition ?? "top";
|
|
714
779
|
this.wrapperEl = document.createElement("div");
|
|
715
780
|
this.wrapperEl.className = `fp-viewer ${themeClass} ${options.className ?? ""}`.trim();
|
|
781
|
+
this.wrapperEl.tabIndex = 0;
|
|
716
782
|
const toolbarEl = document.createElement("div");
|
|
717
783
|
toolbarEl.className = "fp-toolbar-container";
|
|
718
784
|
this.contentEl = document.createElement("div");
|
|
@@ -734,6 +800,59 @@ var FilePreviewViewer = class {
|
|
|
734
800
|
container.appendChild(this.wrapperEl);
|
|
735
801
|
this.toolbar = new ToolbarController(toolbarEl);
|
|
736
802
|
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl);
|
|
803
|
+
this.setupKeyboardShortcuts();
|
|
804
|
+
this.setupDragAndDrop(container, options);
|
|
805
|
+
}
|
|
806
|
+
setupKeyboardShortcuts() {
|
|
807
|
+
if (this.keyHandler) return;
|
|
808
|
+
this.keyHandler = (e) => {
|
|
809
|
+
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement || e.target?.isContentEditable) {
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
if (!this.activeInstance) return;
|
|
813
|
+
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
814
|
+
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
815
|
+
this.activeInstance.goToPage?.(cur + 1);
|
|
816
|
+
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
817
|
+
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
818
|
+
this.activeInstance.goToPage?.(Math.max(1, cur - 1));
|
|
819
|
+
} else if (e.key === "+" || e.key === "=") {
|
|
820
|
+
this.activeInstance.zoomIn?.();
|
|
821
|
+
} else if (e.key === "-" || e.key === "_") {
|
|
822
|
+
this.activeInstance.zoomOut?.();
|
|
823
|
+
} else if (e.key === "0") {
|
|
824
|
+
this.activeInstance.fitToPage?.();
|
|
825
|
+
} else if (e.key === "r" || e.key === "R") {
|
|
826
|
+
this.activeInstance.rotateCW?.();
|
|
827
|
+
} else if (e.key === "f" || e.key === "F") {
|
|
828
|
+
if (!document.fullscreenElement) {
|
|
829
|
+
this.wrapperEl?.requestFullscreen?.();
|
|
830
|
+
} else {
|
|
831
|
+
document.exitFullscreen?.();
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
window.addEventListener("keydown", this.keyHandler);
|
|
836
|
+
}
|
|
837
|
+
setupDragAndDrop(container, options) {
|
|
838
|
+
if (!this.wrapperEl) return;
|
|
839
|
+
this.wrapperEl.addEventListener("dragover", (e) => {
|
|
840
|
+
e.preventDefault();
|
|
841
|
+
this.wrapperEl?.classList.add("fp-dragover");
|
|
842
|
+
});
|
|
843
|
+
this.wrapperEl.addEventListener("dragleave", (e) => {
|
|
844
|
+
if (e.relatedTarget === null || !this.wrapperEl?.contains(e.relatedTarget)) {
|
|
845
|
+
this.wrapperEl?.classList.remove("fp-dragover");
|
|
846
|
+
}
|
|
847
|
+
});
|
|
848
|
+
this.wrapperEl.addEventListener("drop", (e) => {
|
|
849
|
+
e.preventDefault();
|
|
850
|
+
this.wrapperEl?.classList.remove("fp-dragover");
|
|
851
|
+
const file = e.dataTransfer?.files?.[0];
|
|
852
|
+
if (file) {
|
|
853
|
+
this.preview(container, file, options);
|
|
854
|
+
}
|
|
855
|
+
});
|
|
737
856
|
}
|
|
738
857
|
showLoading() {
|
|
739
858
|
if (!this.contentEl) return;
|
|
@@ -752,10 +871,27 @@ var FilePreviewViewer = class {
|
|
|
752
871
|
this.contentEl.innerHTML = "";
|
|
753
872
|
const errorEl = document.createElement("div");
|
|
754
873
|
errorEl.className = "fp-error";
|
|
874
|
+
errorEl.style.display = "flex";
|
|
875
|
+
errorEl.style.flexDirection = "column";
|
|
876
|
+
errorEl.style.alignItems = "center";
|
|
877
|
+
errorEl.style.justifyContent = "center";
|
|
878
|
+
errorEl.style.padding = "32px";
|
|
879
|
+
errorEl.style.textAlign = "center";
|
|
880
|
+
const hasDownload = !!(this.currentBuffer && this.currentMetadata);
|
|
755
881
|
errorEl.innerHTML = `
|
|
756
|
-
<div class="fp-error-icon">\u26A0\uFE0F</div>
|
|
757
|
-
<div class="fp-error-message"
|
|
882
|
+
<div class="fp-error-icon" style="font-size:36px;margin-bottom:8px;">\u26A0\uFE0F</div>
|
|
883
|
+
<div class="fp-error-message" style="font-size:16px;font-weight:600;margin-bottom:6px;">Cannot preview file</div>
|
|
884
|
+
<div class="fp-error-sub" style="font-size:13px;color:#64748b;max-width:420px;line-height:1.5;margin-bottom:16px;">${message}</div>
|
|
885
|
+
${hasDownload ? '<button class="fp-error-download-btn" style="padding:8px 16px;background:#3b82f6;color:#ffffff;border:none;border-radius:6px;cursor:pointer;font-weight:500;font-size:13px;transition:background 0.2s;">Download Original File</button>' : ""}
|
|
758
886
|
`;
|
|
887
|
+
if (hasDownload && this.currentBuffer) {
|
|
888
|
+
const btn = errorEl.querySelector(".fp-error-download-btn");
|
|
889
|
+
if (btn) {
|
|
890
|
+
btn.addEventListener("click", () => {
|
|
891
|
+
downloadFile(this.currentBuffer, this.currentMetadata?.name || "download", this.currentMetadata?.mimeType);
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
}
|
|
759
895
|
this.contentEl.appendChild(errorEl);
|
|
760
896
|
}
|
|
761
897
|
};
|
|
@@ -1676,6 +1812,16 @@ var CodePlugin = class {
|
|
|
1676
1812
|
instance.zoomIn?.();
|
|
1677
1813
|
}
|
|
1678
1814
|
},
|
|
1815
|
+
{
|
|
1816
|
+
id: "copy",
|
|
1817
|
+
icon: "copy",
|
|
1818
|
+
label: "Copy Content",
|
|
1819
|
+
type: "button",
|
|
1820
|
+
group: "actions",
|
|
1821
|
+
execute: () => {
|
|
1822
|
+
instance.copy?.();
|
|
1823
|
+
}
|
|
1824
|
+
},
|
|
1679
1825
|
{
|
|
1680
1826
|
id: "download",
|
|
1681
1827
|
icon: "download",
|
|
@@ -1763,6 +1909,9 @@ var CodePlugin = class {
|
|
|
1763
1909
|
},
|
|
1764
1910
|
print: () => {
|
|
1765
1911
|
window.print();
|
|
1912
|
+
},
|
|
1913
|
+
copy: () => {
|
|
1914
|
+
navigator.clipboard?.writeText(text);
|
|
1766
1915
|
}
|
|
1767
1916
|
};
|
|
1768
1917
|
}
|
|
@@ -2013,6 +2162,14 @@ var MarkdownPlugin = class {
|
|
|
2013
2162
|
group: "zoom",
|
|
2014
2163
|
execute: () => instance.fitToPage?.()
|
|
2015
2164
|
},
|
|
2165
|
+
{
|
|
2166
|
+
id: "copy",
|
|
2167
|
+
icon: "copy",
|
|
2168
|
+
label: "Copy Markdown",
|
|
2169
|
+
type: "button",
|
|
2170
|
+
group: "actions",
|
|
2171
|
+
execute: () => instance.copy?.()
|
|
2172
|
+
},
|
|
2016
2173
|
{
|
|
2017
2174
|
id: "download",
|
|
2018
2175
|
icon: "download",
|
|
@@ -2163,6 +2320,9 @@ var MarkdownPlugin = class {
|
|
|
2163
2320
|
},
|
|
2164
2321
|
print: () => {
|
|
2165
2322
|
window.print();
|
|
2323
|
+
},
|
|
2324
|
+
copy: () => {
|
|
2325
|
+
navigator.clipboard?.writeText(text);
|
|
2166
2326
|
}
|
|
2167
2327
|
};
|
|
2168
2328
|
}
|