@open-file-viewer/core 0.1.0 → 0.1.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 +133 -0
- package/dist/index.cjs +299 -62
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -1
- package/dist/index.d.ts +38 -1
- package/dist/index.js +299 -62
- package/dist/index.js.map +1 -1
- package/dist/style.css +29 -0
- package/package.json +4 -2
package/dist/index.d.cts
CHANGED
|
@@ -4,6 +4,8 @@ type PreviewSource = File | Blob | string | ArrayBuffer;
|
|
|
4
4
|
type PreviewFit = "contain" | "cover" | "width" | "height" | "actual" | "scale-down";
|
|
5
5
|
type PreviewFallback = "inline" | "download" | "custom";
|
|
6
6
|
type PreviewTheme = "light" | "dark" | "auto";
|
|
7
|
+
type PreviewToolbarBuiltInAction = "previous" | "next" | "queue" | "zoom-out" | "zoom-in" | "zoom-reset" | "rotate-right" | "download" | "fullscreen" | "print" | "search";
|
|
8
|
+
type PreviewToolbarActionId = PreviewToolbarBuiltInAction | (string & {});
|
|
7
9
|
interface PreviewFile {
|
|
8
10
|
source: PreviewSource;
|
|
9
11
|
name: string;
|
|
@@ -29,6 +31,40 @@ interface PreviewToolbarOptions {
|
|
|
29
31
|
fullscreen?: boolean;
|
|
30
32
|
print?: boolean;
|
|
31
33
|
search?: boolean;
|
|
34
|
+
order?: PreviewToolbarActionId[];
|
|
35
|
+
labels?: Partial<Record<PreviewToolbarBuiltInAction, string>>;
|
|
36
|
+
titles?: Partial<Record<PreviewToolbarBuiltInAction, string>>;
|
|
37
|
+
icons?: Partial<Record<PreviewToolbarBuiltInAction, string | HTMLElement | SVGElement>>;
|
|
38
|
+
actions?: PreviewToolbarCustomAction[];
|
|
39
|
+
render?: (ctx: PreviewToolbarRenderContext) => HTMLElement | void;
|
|
40
|
+
}
|
|
41
|
+
interface PreviewToolbarCustomAction {
|
|
42
|
+
id: string;
|
|
43
|
+
label: string;
|
|
44
|
+
title?: string;
|
|
45
|
+
icon?: string | HTMLElement | SVGElement;
|
|
46
|
+
order?: number;
|
|
47
|
+
disabled?: boolean | ((ctx: PreviewToolbarRenderContext) => boolean);
|
|
48
|
+
hidden?: boolean | ((ctx: PreviewToolbarRenderContext) => boolean);
|
|
49
|
+
className?: string;
|
|
50
|
+
onClick: (ctx: PreviewToolbarRenderContext) => void | Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
interface PreviewToolbarRenderContext {
|
|
53
|
+
file?: PreviewFile;
|
|
54
|
+
index: number;
|
|
55
|
+
length: number;
|
|
56
|
+
viewport: HTMLElement;
|
|
57
|
+
canPrevious: boolean;
|
|
58
|
+
canNext: boolean;
|
|
59
|
+
previous: () => Promise<void>;
|
|
60
|
+
next: () => Promise<void>;
|
|
61
|
+
command: (command: PreviewCommand) => void | boolean | undefined;
|
|
62
|
+
canCommand: (command: PreviewCommand) => boolean;
|
|
63
|
+
download: () => void;
|
|
64
|
+
fullscreen: () => void;
|
|
65
|
+
print: () => void;
|
|
66
|
+
search: (query: string) => number;
|
|
67
|
+
clearSearch: () => void;
|
|
32
68
|
}
|
|
33
69
|
interface PreviewOptions {
|
|
34
70
|
container: HTMLElement | string;
|
|
@@ -56,6 +92,7 @@ interface PreviewContext {
|
|
|
56
92
|
file: PreviewFile;
|
|
57
93
|
size: PreviewSize;
|
|
58
94
|
options: Required<Pick<PreviewOptions, "fit" | "fallback">> & PreviewOptions;
|
|
95
|
+
toolbar?: PreviewToolbarRenderContext;
|
|
59
96
|
setLoading: (loading: boolean) => void;
|
|
60
97
|
setError: (error: Error | string) => void;
|
|
61
98
|
}
|
|
@@ -122,4 +159,4 @@ declare function assetPlugin(): PreviewPlugin;
|
|
|
122
159
|
|
|
123
160
|
declare function fallbackPlugin(): PreviewPlugin;
|
|
124
161
|
|
|
125
|
-
export { type FileViewer, type PreviewCommand, type PreviewContext, type PreviewFallback, type PreviewFile, type PreviewFit, type PreviewInstance, type PreviewItem, type PreviewOptions, type PreviewPlugin, type PreviewSize, type PreviewSource, type PreviewTheme, type PreviewToolbarOptions, archivePlugin, assetPlugin, audioPlugin, cadPlugin, createViewer, drawingPlugin, emailPlugin, epubPlugin, fallbackPlugin, gisPlugin, imagePlugin, model3dPlugin, ofdPlugin, officePlugin, pdfPlugin, textPlugin, videoPlugin, xpsPlugin };
|
|
162
|
+
export { type FileViewer, type PreviewCommand, type PreviewContext, type PreviewFallback, type PreviewFile, type PreviewFit, type PreviewInstance, type PreviewItem, type PreviewOptions, type PreviewPlugin, type PreviewSize, type PreviewSource, type PreviewTheme, type PreviewToolbarActionId, type PreviewToolbarBuiltInAction, type PreviewToolbarCustomAction, type PreviewToolbarOptions, type PreviewToolbarRenderContext, archivePlugin, assetPlugin, audioPlugin, cadPlugin, createViewer, drawingPlugin, emailPlugin, epubPlugin, fallbackPlugin, gisPlugin, imagePlugin, model3dPlugin, ofdPlugin, officePlugin, pdfPlugin, textPlugin, videoPlugin, xpsPlugin };
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ type PreviewSource = File | Blob | string | ArrayBuffer;
|
|
|
4
4
|
type PreviewFit = "contain" | "cover" | "width" | "height" | "actual" | "scale-down";
|
|
5
5
|
type PreviewFallback = "inline" | "download" | "custom";
|
|
6
6
|
type PreviewTheme = "light" | "dark" | "auto";
|
|
7
|
+
type PreviewToolbarBuiltInAction = "previous" | "next" | "queue" | "zoom-out" | "zoom-in" | "zoom-reset" | "rotate-right" | "download" | "fullscreen" | "print" | "search";
|
|
8
|
+
type PreviewToolbarActionId = PreviewToolbarBuiltInAction | (string & {});
|
|
7
9
|
interface PreviewFile {
|
|
8
10
|
source: PreviewSource;
|
|
9
11
|
name: string;
|
|
@@ -29,6 +31,40 @@ interface PreviewToolbarOptions {
|
|
|
29
31
|
fullscreen?: boolean;
|
|
30
32
|
print?: boolean;
|
|
31
33
|
search?: boolean;
|
|
34
|
+
order?: PreviewToolbarActionId[];
|
|
35
|
+
labels?: Partial<Record<PreviewToolbarBuiltInAction, string>>;
|
|
36
|
+
titles?: Partial<Record<PreviewToolbarBuiltInAction, string>>;
|
|
37
|
+
icons?: Partial<Record<PreviewToolbarBuiltInAction, string | HTMLElement | SVGElement>>;
|
|
38
|
+
actions?: PreviewToolbarCustomAction[];
|
|
39
|
+
render?: (ctx: PreviewToolbarRenderContext) => HTMLElement | void;
|
|
40
|
+
}
|
|
41
|
+
interface PreviewToolbarCustomAction {
|
|
42
|
+
id: string;
|
|
43
|
+
label: string;
|
|
44
|
+
title?: string;
|
|
45
|
+
icon?: string | HTMLElement | SVGElement;
|
|
46
|
+
order?: number;
|
|
47
|
+
disabled?: boolean | ((ctx: PreviewToolbarRenderContext) => boolean);
|
|
48
|
+
hidden?: boolean | ((ctx: PreviewToolbarRenderContext) => boolean);
|
|
49
|
+
className?: string;
|
|
50
|
+
onClick: (ctx: PreviewToolbarRenderContext) => void | Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
interface PreviewToolbarRenderContext {
|
|
53
|
+
file?: PreviewFile;
|
|
54
|
+
index: number;
|
|
55
|
+
length: number;
|
|
56
|
+
viewport: HTMLElement;
|
|
57
|
+
canPrevious: boolean;
|
|
58
|
+
canNext: boolean;
|
|
59
|
+
previous: () => Promise<void>;
|
|
60
|
+
next: () => Promise<void>;
|
|
61
|
+
command: (command: PreviewCommand) => void | boolean | undefined;
|
|
62
|
+
canCommand: (command: PreviewCommand) => boolean;
|
|
63
|
+
download: () => void;
|
|
64
|
+
fullscreen: () => void;
|
|
65
|
+
print: () => void;
|
|
66
|
+
search: (query: string) => number;
|
|
67
|
+
clearSearch: () => void;
|
|
32
68
|
}
|
|
33
69
|
interface PreviewOptions {
|
|
34
70
|
container: HTMLElement | string;
|
|
@@ -56,6 +92,7 @@ interface PreviewContext {
|
|
|
56
92
|
file: PreviewFile;
|
|
57
93
|
size: PreviewSize;
|
|
58
94
|
options: Required<Pick<PreviewOptions, "fit" | "fallback">> & PreviewOptions;
|
|
95
|
+
toolbar?: PreviewToolbarRenderContext;
|
|
59
96
|
setLoading: (loading: boolean) => void;
|
|
60
97
|
setError: (error: Error | string) => void;
|
|
61
98
|
}
|
|
@@ -122,4 +159,4 @@ declare function assetPlugin(): PreviewPlugin;
|
|
|
122
159
|
|
|
123
160
|
declare function fallbackPlugin(): PreviewPlugin;
|
|
124
161
|
|
|
125
|
-
export { type FileViewer, type PreviewCommand, type PreviewContext, type PreviewFallback, type PreviewFile, type PreviewFit, type PreviewInstance, type PreviewItem, type PreviewOptions, type PreviewPlugin, type PreviewSize, type PreviewSource, type PreviewTheme, type PreviewToolbarOptions, archivePlugin, assetPlugin, audioPlugin, cadPlugin, createViewer, drawingPlugin, emailPlugin, epubPlugin, fallbackPlugin, gisPlugin, imagePlugin, model3dPlugin, ofdPlugin, officePlugin, pdfPlugin, textPlugin, videoPlugin, xpsPlugin };
|
|
162
|
+
export { type FileViewer, type PreviewCommand, type PreviewContext, type PreviewFallback, type PreviewFile, type PreviewFit, type PreviewInstance, type PreviewItem, type PreviewOptions, type PreviewPlugin, type PreviewSize, type PreviewSource, type PreviewTheme, type PreviewToolbarActionId, type PreviewToolbarBuiltInAction, type PreviewToolbarCustomAction, type PreviewToolbarOptions, type PreviewToolbarRenderContext, archivePlugin, assetPlugin, audioPlugin, cadPlugin, createViewer, drawingPlugin, emailPlugin, epubPlugin, fallbackPlugin, gisPlugin, imagePlugin, model3dPlugin, ofdPlugin, officePlugin, pdfPlugin, textPlugin, videoPlugin, xpsPlugin };
|
package/dist/index.js
CHANGED
|
@@ -682,6 +682,7 @@ function createViewer(options) {
|
|
|
682
682
|
file,
|
|
683
683
|
size: getElementSize(viewport),
|
|
684
684
|
options: normalizedOptions,
|
|
685
|
+
toolbar: toolbar?.getContext(),
|
|
685
686
|
setLoading,
|
|
686
687
|
setError
|
|
687
688
|
});
|
|
@@ -855,18 +856,32 @@ function createToolbar(toolbar, viewport, queue) {
|
|
|
855
856
|
element.setAttribute("role", "toolbar");
|
|
856
857
|
element.setAttribute("aria-label", "File preview toolbar");
|
|
857
858
|
let file;
|
|
859
|
+
let currentIndex = 0;
|
|
860
|
+
let currentLength = queue.getLength();
|
|
858
861
|
let queueLabel;
|
|
859
862
|
let previousButton;
|
|
860
863
|
let nextButton;
|
|
861
864
|
const commandButtons = [];
|
|
865
|
+
const customButtons = [];
|
|
862
866
|
const disposers = [];
|
|
863
867
|
const search = createSearchController(viewport);
|
|
864
868
|
let searchInput;
|
|
865
869
|
let searchCount;
|
|
866
|
-
|
|
870
|
+
let canRunCommand = (_command) => false;
|
|
871
|
+
const getContext = () => createToolbarContext({
|
|
872
|
+
file,
|
|
873
|
+
index: currentIndex,
|
|
874
|
+
length: currentLength,
|
|
875
|
+
viewport,
|
|
876
|
+
queue,
|
|
877
|
+
element,
|
|
878
|
+
search,
|
|
879
|
+
canCommand: canRunCommand
|
|
880
|
+
});
|
|
881
|
+
const addButton = (label, title, action, className, icon) => {
|
|
867
882
|
const button = document.createElement("button");
|
|
868
883
|
button.type = "button";
|
|
869
|
-
button
|
|
884
|
+
setToolbarButtonContent(button, label, icon);
|
|
870
885
|
button.title = title;
|
|
871
886
|
button.setAttribute("aria-label", title);
|
|
872
887
|
if (className) {
|
|
@@ -877,68 +892,117 @@ function createToolbar(toolbar, viewport, queue) {
|
|
|
877
892
|
disposers.push(() => button.removeEventListener("click", action));
|
|
878
893
|
return button;
|
|
879
894
|
};
|
|
880
|
-
const
|
|
881
|
-
const button = document.createElement("button");
|
|
882
|
-
button.type = "button";
|
|
883
|
-
button.textContent = label;
|
|
884
|
-
button.title = title;
|
|
885
|
-
button.setAttribute("aria-label", title);
|
|
886
|
-
const listener = () => {
|
|
887
|
-
void action();
|
|
888
|
-
};
|
|
889
|
-
button.addEventListener("click", listener);
|
|
890
|
-
element.append(button);
|
|
891
|
-
disposers.push(() => button.removeEventListener("click", listener));
|
|
892
|
-
return button;
|
|
893
|
-
};
|
|
894
|
-
if (queue.getLength() > 1) {
|
|
895
|
-
previousButton = addQueueButton("Prev", "Previous file", queue.previous);
|
|
896
|
-
nextButton = addQueueButton("Next", "Next file", queue.next);
|
|
897
|
-
queueLabel = document.createElement("span");
|
|
898
|
-
queueLabel.className = "ofv-toolbar-queue";
|
|
899
|
-
element.append(queueLabel);
|
|
900
|
-
}
|
|
901
|
-
const addCommandButton = (label, title, command) => {
|
|
895
|
+
const addCommandButton = (id, label, title, command) => {
|
|
902
896
|
const button = addButton(label, title, () => {
|
|
903
897
|
queue.command(command);
|
|
904
|
-
});
|
|
898
|
+
}, void 0, options.icons?.[id]);
|
|
905
899
|
button.disabled = true;
|
|
906
900
|
commandButtons.push({ button, command });
|
|
907
901
|
};
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
if (options.rotate) {
|
|
914
|
-
addCommandButton("Rotate", "Rotate right", "rotate-right");
|
|
915
|
-
}
|
|
916
|
-
if (options.download !== false) {
|
|
917
|
-
addButton("Download", "Download file", () => {
|
|
918
|
-
if (file) {
|
|
919
|
-
downloadFile(file);
|
|
902
|
+
const renderDefaultAction = (id) => {
|
|
903
|
+
if (!isBuiltInToolbarAction(id)) {
|
|
904
|
+
const customAction = options.actions?.find((action) => action.id === id);
|
|
905
|
+
if (customAction) {
|
|
906
|
+
renderCustomAction(customAction);
|
|
920
907
|
}
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
if (id === "previous" && queue.getLength() > 1) {
|
|
911
|
+
previousButton = addButton(
|
|
912
|
+
getToolbarLabel(options, "previous"),
|
|
913
|
+
getToolbarTitle(options, "previous"),
|
|
914
|
+
() => void queue.previous(),
|
|
915
|
+
void 0,
|
|
916
|
+
options.icons?.previous
|
|
917
|
+
);
|
|
918
|
+
return;
|
|
919
|
+
}
|
|
920
|
+
if (id === "next" && queue.getLength() > 1) {
|
|
921
|
+
nextButton = addButton(
|
|
922
|
+
getToolbarLabel(options, "next"),
|
|
923
|
+
getToolbarTitle(options, "next"),
|
|
924
|
+
() => void queue.next(),
|
|
925
|
+
void 0,
|
|
926
|
+
options.icons?.next
|
|
927
|
+
);
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
if (id === "queue" && queue.getLength() > 1) {
|
|
931
|
+
queueLabel = document.createElement("span");
|
|
932
|
+
queueLabel.className = "ofv-toolbar-queue";
|
|
933
|
+
element.append(queueLabel);
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
if (id === "zoom-out" && options.zoom) {
|
|
937
|
+
addCommandButton(id, getToolbarLabel(options, id), getToolbarTitle(options, id), "zoom-out");
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
if (id === "zoom-in" && options.zoom) {
|
|
941
|
+
addCommandButton(id, getToolbarLabel(options, id), getToolbarTitle(options, id), "zoom-in");
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
if (id === "zoom-reset" && options.zoom) {
|
|
945
|
+
addCommandButton(id, getToolbarLabel(options, id), getToolbarTitle(options, id), "zoom-reset");
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
if (id === "rotate-right" && options.rotate) {
|
|
949
|
+
addCommandButton(id, getToolbarLabel(options, id), getToolbarTitle(options, id), "rotate-right");
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
if (id === "download" && options.download !== false) {
|
|
953
|
+
addButton(
|
|
954
|
+
getToolbarLabel(options, id),
|
|
955
|
+
getToolbarTitle(options, id),
|
|
956
|
+
() => getContext().download(),
|
|
957
|
+
void 0,
|
|
958
|
+
options.icons?.download
|
|
959
|
+
);
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
if (id === "fullscreen" && options.fullscreen !== false) {
|
|
963
|
+
addButton(
|
|
964
|
+
getToolbarLabel(options, id),
|
|
965
|
+
getToolbarTitle(options, id),
|
|
966
|
+
() => getContext().fullscreen(),
|
|
967
|
+
void 0,
|
|
968
|
+
options.icons?.fullscreen
|
|
969
|
+
);
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
if (id === "print" && options.print) {
|
|
973
|
+
addButton(
|
|
974
|
+
getToolbarLabel(options, id),
|
|
975
|
+
getToolbarTitle(options, id),
|
|
976
|
+
() => getContext().print(),
|
|
977
|
+
void 0,
|
|
978
|
+
options.icons?.print
|
|
979
|
+
);
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
if (id === "search" && options.search !== false) {
|
|
983
|
+
renderSearchControl();
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
};
|
|
987
|
+
const renderCustomAction = (action) => {
|
|
988
|
+
const button = addButton(
|
|
989
|
+
action.label,
|
|
990
|
+
action.title || action.label,
|
|
991
|
+
() => void action.onClick(getContext()),
|
|
992
|
+
action.className,
|
|
993
|
+
action.icon
|
|
994
|
+
);
|
|
995
|
+
button.dataset.ofvToolbarAction = action.id;
|
|
996
|
+
customButtons.push({ button, action });
|
|
997
|
+
};
|
|
998
|
+
const renderSearchControl = () => {
|
|
935
999
|
const searchGroup = document.createElement("div");
|
|
936
1000
|
searchGroup.className = "ofv-toolbar-search";
|
|
937
|
-
searchGroup.title =
|
|
1001
|
+
searchGroup.title = getToolbarTitle(options, "search");
|
|
938
1002
|
const nextSearchInput = document.createElement("input");
|
|
939
1003
|
nextSearchInput.type = "search";
|
|
940
|
-
nextSearchInput.placeholder = "
|
|
941
|
-
nextSearchInput.setAttribute("aria-label",
|
|
1004
|
+
nextSearchInput.placeholder = getToolbarLabel(options, "search");
|
|
1005
|
+
nextSearchInput.setAttribute("aria-label", getToolbarTitle(options, "search"));
|
|
942
1006
|
const nextSearchCount = document.createElement("span");
|
|
943
1007
|
nextSearchCount.className = "ofv-toolbar-search-count";
|
|
944
1008
|
searchInput = nextSearchInput;
|
|
@@ -951,18 +1015,53 @@ function createToolbar(toolbar, viewport, queue) {
|
|
|
951
1015
|
searchGroup.append(nextSearchInput, nextSearchCount);
|
|
952
1016
|
element.append(searchGroup);
|
|
953
1017
|
disposers.push(() => nextSearchInput.removeEventListener("input", runSearch));
|
|
954
|
-
}
|
|
1018
|
+
};
|
|
1019
|
+
const renderToolbar = () => {
|
|
1020
|
+
if (options.render) {
|
|
1021
|
+
element.replaceChildren();
|
|
1022
|
+
const customElement = options.render(getContext());
|
|
1023
|
+
if (customElement) {
|
|
1024
|
+
element.append(customElement);
|
|
1025
|
+
}
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
getToolbarOrder(options, queue.getLength()).forEach(renderDefaultAction);
|
|
1029
|
+
getImplicitCustomActions(options).forEach(renderCustomAction);
|
|
1030
|
+
};
|
|
1031
|
+
renderToolbar();
|
|
1032
|
+
const updateCustomButtons = () => {
|
|
1033
|
+
const context = getContext();
|
|
1034
|
+
for (const { button, action } of customButtons) {
|
|
1035
|
+
button.disabled = evaluateToolbarFlag(action.disabled, context);
|
|
1036
|
+
button.hidden = evaluateToolbarFlag(action.hidden, context);
|
|
1037
|
+
}
|
|
1038
|
+
};
|
|
1039
|
+
const resetSearch = () => {
|
|
1040
|
+
search.clear();
|
|
1041
|
+
if (searchInput) {
|
|
1042
|
+
searchInput.value = "";
|
|
1043
|
+
}
|
|
1044
|
+
if (searchCount) {
|
|
1045
|
+
searchCount.textContent = "";
|
|
1046
|
+
}
|
|
1047
|
+
};
|
|
1048
|
+
const refreshCustomRender = () => {
|
|
1049
|
+
if (!options.render) {
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
element.replaceChildren();
|
|
1053
|
+
const customElement = options.render(getContext());
|
|
1054
|
+
if (customElement) {
|
|
1055
|
+
element.append(customElement);
|
|
1056
|
+
}
|
|
1057
|
+
};
|
|
955
1058
|
return {
|
|
956
1059
|
element,
|
|
957
1060
|
update(nextFile, index, length) {
|
|
958
1061
|
file = nextFile;
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
}
|
|
963
|
-
if (searchCount) {
|
|
964
|
-
searchCount.textContent = "";
|
|
965
|
-
}
|
|
1062
|
+
currentIndex = index;
|
|
1063
|
+
currentLength = length;
|
|
1064
|
+
resetSearch();
|
|
966
1065
|
commandButtons.forEach(({ button }) => {
|
|
967
1066
|
button.disabled = true;
|
|
968
1067
|
});
|
|
@@ -975,20 +1074,158 @@ function createToolbar(toolbar, viewport, queue) {
|
|
|
975
1074
|
if (nextButton) {
|
|
976
1075
|
nextButton.disabled = index >= length - 1;
|
|
977
1076
|
}
|
|
1077
|
+
updateCustomButtons();
|
|
1078
|
+
refreshCustomRender();
|
|
978
1079
|
},
|
|
979
1080
|
setCommandSupport(isSupported) {
|
|
1081
|
+
canRunCommand = isSupported;
|
|
980
1082
|
commandButtons.forEach(({ button, command }) => {
|
|
981
1083
|
button.disabled = !isSupported(command);
|
|
982
1084
|
});
|
|
1085
|
+
updateCustomButtons();
|
|
1086
|
+
refreshCustomRender();
|
|
983
1087
|
},
|
|
1088
|
+
getContext,
|
|
984
1089
|
destroy() {
|
|
985
1090
|
search.clear();
|
|
986
1091
|
for (const dispose of disposers) {
|
|
987
1092
|
dispose();
|
|
988
1093
|
}
|
|
1094
|
+
element.replaceChildren();
|
|
989
1095
|
}
|
|
990
1096
|
};
|
|
991
1097
|
}
|
|
1098
|
+
function createToolbarContext({
|
|
1099
|
+
file,
|
|
1100
|
+
index,
|
|
1101
|
+
length,
|
|
1102
|
+
viewport,
|
|
1103
|
+
queue,
|
|
1104
|
+
element,
|
|
1105
|
+
search,
|
|
1106
|
+
canCommand
|
|
1107
|
+
}) {
|
|
1108
|
+
return {
|
|
1109
|
+
file,
|
|
1110
|
+
index,
|
|
1111
|
+
length,
|
|
1112
|
+
viewport,
|
|
1113
|
+
canPrevious: index > 0,
|
|
1114
|
+
canNext: index < length - 1,
|
|
1115
|
+
async previous() {
|
|
1116
|
+
await queue.previous();
|
|
1117
|
+
},
|
|
1118
|
+
async next() {
|
|
1119
|
+
await queue.next();
|
|
1120
|
+
},
|
|
1121
|
+
command: queue.command,
|
|
1122
|
+
canCommand,
|
|
1123
|
+
download() {
|
|
1124
|
+
if (file) {
|
|
1125
|
+
downloadFile(file);
|
|
1126
|
+
}
|
|
1127
|
+
},
|
|
1128
|
+
fullscreen() {
|
|
1129
|
+
void element.parentElement?.requestFullscreen?.();
|
|
1130
|
+
},
|
|
1131
|
+
print() {
|
|
1132
|
+
printPreview(viewport);
|
|
1133
|
+
},
|
|
1134
|
+
search: search.search,
|
|
1135
|
+
clearSearch: search.clear
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
var defaultToolbarLabels = {
|
|
1139
|
+
previous: "Prev",
|
|
1140
|
+
next: "Next",
|
|
1141
|
+
queue: "",
|
|
1142
|
+
"zoom-out": "-",
|
|
1143
|
+
"zoom-in": "+",
|
|
1144
|
+
"zoom-reset": "100%",
|
|
1145
|
+
"rotate-right": "Rotate",
|
|
1146
|
+
download: "Download",
|
|
1147
|
+
fullscreen: "Fullscreen",
|
|
1148
|
+
print: "Print",
|
|
1149
|
+
search: "Search"
|
|
1150
|
+
};
|
|
1151
|
+
var defaultToolbarTitles = {
|
|
1152
|
+
previous: "Previous file",
|
|
1153
|
+
next: "Next file",
|
|
1154
|
+
queue: "Current file position",
|
|
1155
|
+
"zoom-out": "Zoom out",
|
|
1156
|
+
"zoom-in": "Zoom in",
|
|
1157
|
+
"zoom-reset": "Reset zoom",
|
|
1158
|
+
"rotate-right": "Rotate right",
|
|
1159
|
+
download: "Download file",
|
|
1160
|
+
fullscreen: "Open preview fullscreen",
|
|
1161
|
+
print: "Print preview",
|
|
1162
|
+
search: "Search preview text"
|
|
1163
|
+
};
|
|
1164
|
+
function getToolbarLabel(options, id) {
|
|
1165
|
+
return options.labels?.[id] ?? defaultToolbarLabels[id];
|
|
1166
|
+
}
|
|
1167
|
+
function getToolbarTitle(options, id) {
|
|
1168
|
+
return options.titles?.[id] ?? options.labels?.[id] ?? defaultToolbarTitles[id];
|
|
1169
|
+
}
|
|
1170
|
+
function getToolbarOrder(options, queueLength) {
|
|
1171
|
+
if (options.order) {
|
|
1172
|
+
return options.order;
|
|
1173
|
+
}
|
|
1174
|
+
const actions = [];
|
|
1175
|
+
if (queueLength > 1) {
|
|
1176
|
+
actions.push("previous", "next", "queue");
|
|
1177
|
+
}
|
|
1178
|
+
if (options.zoom) {
|
|
1179
|
+
actions.push("zoom-out", "zoom-in", "zoom-reset");
|
|
1180
|
+
}
|
|
1181
|
+
if (options.rotate) {
|
|
1182
|
+
actions.push("rotate-right");
|
|
1183
|
+
}
|
|
1184
|
+
if (options.download !== false) {
|
|
1185
|
+
actions.push("download");
|
|
1186
|
+
}
|
|
1187
|
+
if (options.fullscreen !== false) {
|
|
1188
|
+
actions.push("fullscreen");
|
|
1189
|
+
}
|
|
1190
|
+
if (options.print) {
|
|
1191
|
+
actions.push("print");
|
|
1192
|
+
}
|
|
1193
|
+
if (options.search !== false) {
|
|
1194
|
+
actions.push("search");
|
|
1195
|
+
}
|
|
1196
|
+
return actions;
|
|
1197
|
+
}
|
|
1198
|
+
function getImplicitCustomActions(options) {
|
|
1199
|
+
if (options.order || !options.actions) {
|
|
1200
|
+
return [];
|
|
1201
|
+
}
|
|
1202
|
+
return [...options.actions].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
1203
|
+
}
|
|
1204
|
+
function evaluateToolbarFlag(value, context) {
|
|
1205
|
+
return typeof value === "function" ? value(context) : Boolean(value);
|
|
1206
|
+
}
|
|
1207
|
+
function setToolbarButtonContent(button, label, icon) {
|
|
1208
|
+
button.replaceChildren();
|
|
1209
|
+
if (!icon) {
|
|
1210
|
+
button.textContent = label;
|
|
1211
|
+
return;
|
|
1212
|
+
}
|
|
1213
|
+
const iconElement = document.createElement("span");
|
|
1214
|
+
iconElement.className = "ofv-toolbar-icon";
|
|
1215
|
+
iconElement.setAttribute("aria-hidden", "true");
|
|
1216
|
+
if (typeof icon === "string") {
|
|
1217
|
+
iconElement.innerHTML = icon;
|
|
1218
|
+
} else {
|
|
1219
|
+
iconElement.append(icon.cloneNode(true));
|
|
1220
|
+
}
|
|
1221
|
+
const labelElement = document.createElement("span");
|
|
1222
|
+
labelElement.className = "ofv-toolbar-label";
|
|
1223
|
+
labelElement.textContent = label;
|
|
1224
|
+
button.append(iconElement, labelElement);
|
|
1225
|
+
}
|
|
1226
|
+
function isBuiltInToolbarAction(id) {
|
|
1227
|
+
return id in defaultToolbarLabels;
|
|
1228
|
+
}
|
|
992
1229
|
function createSearchController(root) {
|
|
993
1230
|
const markerClass = "ofv-search-match";
|
|
994
1231
|
const clear = () => {
|