@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/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# @open-file-viewer/core
|
|
2
|
+
|
|
3
|
+
Framework-agnostic browser file preview core for Open File Viewer.
|
|
4
|
+
|
|
5
|
+
Open File Viewer renders files inside your own DOM container instead of opening a new window. It supports images, PDF, Office documents, audio, video, text/code, archives, email, drawings, CAD, 3D and GIS formats through a plugin-based pipeline.
|
|
6
|
+
|
|
7
|
+
- Website: https://open-file-viewer-workspace.void.app
|
|
8
|
+
- GitHub: https://github.com/xushanpei/open-file-viewer
|
|
9
|
+
- npm: https://www.npmjs.com/package/@open-file-viewer/core
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @open-file-viewer/core
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
PDF preview requires `pdfjs-dist`:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install pdfjs-dist
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import {
|
|
27
|
+
createViewer,
|
|
28
|
+
imagePlugin,
|
|
29
|
+
videoPlugin,
|
|
30
|
+
audioPlugin,
|
|
31
|
+
textPlugin,
|
|
32
|
+
pdfPlugin,
|
|
33
|
+
officePlugin,
|
|
34
|
+
archivePlugin,
|
|
35
|
+
emailPlugin,
|
|
36
|
+
drawingPlugin,
|
|
37
|
+
cadPlugin,
|
|
38
|
+
model3dPlugin,
|
|
39
|
+
gisPlugin,
|
|
40
|
+
fallbackPlugin
|
|
41
|
+
} from "@open-file-viewer/core";
|
|
42
|
+
import "@open-file-viewer/core/style.css";
|
|
43
|
+
import pdfWorkerSrc from "pdfjs-dist/build/pdf.worker.mjs?url";
|
|
44
|
+
|
|
45
|
+
const viewer = createViewer({
|
|
46
|
+
container: "#viewer",
|
|
47
|
+
file: fileOrUrl,
|
|
48
|
+
fileName: "contract.pdf",
|
|
49
|
+
width: "100%",
|
|
50
|
+
height: "70vh",
|
|
51
|
+
fit: "contain",
|
|
52
|
+
toolbar: true,
|
|
53
|
+
theme: "auto",
|
|
54
|
+
plugins: [
|
|
55
|
+
imagePlugin(),
|
|
56
|
+
videoPlugin(),
|
|
57
|
+
audioPlugin(),
|
|
58
|
+
textPlugin(),
|
|
59
|
+
pdfPlugin({ workerSrc: pdfWorkerSrc }),
|
|
60
|
+
officePlugin(),
|
|
61
|
+
archivePlugin(),
|
|
62
|
+
emailPlugin(),
|
|
63
|
+
drawingPlugin(),
|
|
64
|
+
cadPlugin(),
|
|
65
|
+
model3dPlugin(),
|
|
66
|
+
gisPlugin(),
|
|
67
|
+
fallbackPlugin()
|
|
68
|
+
]
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
viewer.resize();
|
|
72
|
+
viewer.destroy();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Supported Inputs
|
|
76
|
+
|
|
77
|
+
`createViewer` accepts local files and remote sources:
|
|
78
|
+
|
|
79
|
+
- `File`
|
|
80
|
+
- `Blob`
|
|
81
|
+
- URL string
|
|
82
|
+
- `ArrayBuffer`
|
|
83
|
+
- multiple files through `files`
|
|
84
|
+
|
|
85
|
+
## Package Notes
|
|
86
|
+
|
|
87
|
+
Import the stylesheet once in your app:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import "@open-file-viewer/core/style.css";
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
React and Vue adapters are available as separate packages:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npm install @open-file-viewer/react
|
|
97
|
+
npm install @open-file-viewer/vue
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Toolbar Customization
|
|
101
|
+
|
|
102
|
+
The toolbar can be configured from simple feature toggles to a fully custom renderer:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
createViewer({
|
|
106
|
+
container: "#viewer",
|
|
107
|
+
file,
|
|
108
|
+
toolbar: {
|
|
109
|
+
labels: {
|
|
110
|
+
download: "下载",
|
|
111
|
+
fullscreen: "全屏",
|
|
112
|
+
search: "搜索"
|
|
113
|
+
},
|
|
114
|
+
order: ["search", "download", "approve", "fullscreen"],
|
|
115
|
+
actions: [
|
|
116
|
+
{
|
|
117
|
+
id: "approve",
|
|
118
|
+
label: "审批",
|
|
119
|
+
onClick(ctx) {
|
|
120
|
+
openApprovalDialog(ctx.file);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
},
|
|
125
|
+
plugins
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Use `toolbar.render(ctx)` when you need to replace the toolbar completely. The context exposes file metadata, queue navigation, preview commands, download, fullscreen, print and search helpers.
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -735,6 +735,7 @@ function createViewer(options) {
|
|
|
735
735
|
file,
|
|
736
736
|
size: getElementSize(viewport),
|
|
737
737
|
options: normalizedOptions,
|
|
738
|
+
toolbar: toolbar?.getContext(),
|
|
738
739
|
setLoading,
|
|
739
740
|
setError
|
|
740
741
|
});
|
|
@@ -908,18 +909,32 @@ function createToolbar(toolbar, viewport, queue) {
|
|
|
908
909
|
element.setAttribute("role", "toolbar");
|
|
909
910
|
element.setAttribute("aria-label", "File preview toolbar");
|
|
910
911
|
let file;
|
|
912
|
+
let currentIndex = 0;
|
|
913
|
+
let currentLength = queue.getLength();
|
|
911
914
|
let queueLabel;
|
|
912
915
|
let previousButton;
|
|
913
916
|
let nextButton;
|
|
914
917
|
const commandButtons = [];
|
|
918
|
+
const customButtons = [];
|
|
915
919
|
const disposers = [];
|
|
916
920
|
const search = createSearchController(viewport);
|
|
917
921
|
let searchInput;
|
|
918
922
|
let searchCount;
|
|
919
|
-
|
|
923
|
+
let canRunCommand = (_command) => false;
|
|
924
|
+
const getContext = () => createToolbarContext({
|
|
925
|
+
file,
|
|
926
|
+
index: currentIndex,
|
|
927
|
+
length: currentLength,
|
|
928
|
+
viewport,
|
|
929
|
+
queue,
|
|
930
|
+
element,
|
|
931
|
+
search,
|
|
932
|
+
canCommand: canRunCommand
|
|
933
|
+
});
|
|
934
|
+
const addButton = (label, title, action, className, icon) => {
|
|
920
935
|
const button = document.createElement("button");
|
|
921
936
|
button.type = "button";
|
|
922
|
-
button
|
|
937
|
+
setToolbarButtonContent(button, label, icon);
|
|
923
938
|
button.title = title;
|
|
924
939
|
button.setAttribute("aria-label", title);
|
|
925
940
|
if (className) {
|
|
@@ -930,68 +945,117 @@ function createToolbar(toolbar, viewport, queue) {
|
|
|
930
945
|
disposers.push(() => button.removeEventListener("click", action));
|
|
931
946
|
return button;
|
|
932
947
|
};
|
|
933
|
-
const
|
|
934
|
-
const button = document.createElement("button");
|
|
935
|
-
button.type = "button";
|
|
936
|
-
button.textContent = label;
|
|
937
|
-
button.title = title;
|
|
938
|
-
button.setAttribute("aria-label", title);
|
|
939
|
-
const listener = () => {
|
|
940
|
-
void action();
|
|
941
|
-
};
|
|
942
|
-
button.addEventListener("click", listener);
|
|
943
|
-
element.append(button);
|
|
944
|
-
disposers.push(() => button.removeEventListener("click", listener));
|
|
945
|
-
return button;
|
|
946
|
-
};
|
|
947
|
-
if (queue.getLength() > 1) {
|
|
948
|
-
previousButton = addQueueButton("Prev", "Previous file", queue.previous);
|
|
949
|
-
nextButton = addQueueButton("Next", "Next file", queue.next);
|
|
950
|
-
queueLabel = document.createElement("span");
|
|
951
|
-
queueLabel.className = "ofv-toolbar-queue";
|
|
952
|
-
element.append(queueLabel);
|
|
953
|
-
}
|
|
954
|
-
const addCommandButton = (label, title, command) => {
|
|
948
|
+
const addCommandButton = (id, label, title, command) => {
|
|
955
949
|
const button = addButton(label, title, () => {
|
|
956
950
|
queue.command(command);
|
|
957
|
-
});
|
|
951
|
+
}, void 0, options.icons?.[id]);
|
|
958
952
|
button.disabled = true;
|
|
959
953
|
commandButtons.push({ button, command });
|
|
960
954
|
};
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
if (options.rotate) {
|
|
967
|
-
addCommandButton("Rotate", "Rotate right", "rotate-right");
|
|
968
|
-
}
|
|
969
|
-
if (options.download !== false) {
|
|
970
|
-
addButton("Download", "Download file", () => {
|
|
971
|
-
if (file) {
|
|
972
|
-
downloadFile(file);
|
|
955
|
+
const renderDefaultAction = (id) => {
|
|
956
|
+
if (!isBuiltInToolbarAction(id)) {
|
|
957
|
+
const customAction = options.actions?.find((action) => action.id === id);
|
|
958
|
+
if (customAction) {
|
|
959
|
+
renderCustomAction(customAction);
|
|
973
960
|
}
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
if (id === "previous" && queue.getLength() > 1) {
|
|
964
|
+
previousButton = addButton(
|
|
965
|
+
getToolbarLabel(options, "previous"),
|
|
966
|
+
getToolbarTitle(options, "previous"),
|
|
967
|
+
() => void queue.previous(),
|
|
968
|
+
void 0,
|
|
969
|
+
options.icons?.previous
|
|
970
|
+
);
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
if (id === "next" && queue.getLength() > 1) {
|
|
974
|
+
nextButton = addButton(
|
|
975
|
+
getToolbarLabel(options, "next"),
|
|
976
|
+
getToolbarTitle(options, "next"),
|
|
977
|
+
() => void queue.next(),
|
|
978
|
+
void 0,
|
|
979
|
+
options.icons?.next
|
|
980
|
+
);
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
if (id === "queue" && queue.getLength() > 1) {
|
|
984
|
+
queueLabel = document.createElement("span");
|
|
985
|
+
queueLabel.className = "ofv-toolbar-queue";
|
|
986
|
+
element.append(queueLabel);
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
if (id === "zoom-out" && options.zoom) {
|
|
990
|
+
addCommandButton(id, getToolbarLabel(options, id), getToolbarTitle(options, id), "zoom-out");
|
|
991
|
+
return;
|
|
992
|
+
}
|
|
993
|
+
if (id === "zoom-in" && options.zoom) {
|
|
994
|
+
addCommandButton(id, getToolbarLabel(options, id), getToolbarTitle(options, id), "zoom-in");
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
if (id === "zoom-reset" && options.zoom) {
|
|
998
|
+
addCommandButton(id, getToolbarLabel(options, id), getToolbarTitle(options, id), "zoom-reset");
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
if (id === "rotate-right" && options.rotate) {
|
|
1002
|
+
addCommandButton(id, getToolbarLabel(options, id), getToolbarTitle(options, id), "rotate-right");
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
if (id === "download" && options.download !== false) {
|
|
1006
|
+
addButton(
|
|
1007
|
+
getToolbarLabel(options, id),
|
|
1008
|
+
getToolbarTitle(options, id),
|
|
1009
|
+
() => getContext().download(),
|
|
1010
|
+
void 0,
|
|
1011
|
+
options.icons?.download
|
|
1012
|
+
);
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
if (id === "fullscreen" && options.fullscreen !== false) {
|
|
1016
|
+
addButton(
|
|
1017
|
+
getToolbarLabel(options, id),
|
|
1018
|
+
getToolbarTitle(options, id),
|
|
1019
|
+
() => getContext().fullscreen(),
|
|
1020
|
+
void 0,
|
|
1021
|
+
options.icons?.fullscreen
|
|
1022
|
+
);
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
if (id === "print" && options.print) {
|
|
1026
|
+
addButton(
|
|
1027
|
+
getToolbarLabel(options, id),
|
|
1028
|
+
getToolbarTitle(options, id),
|
|
1029
|
+
() => getContext().print(),
|
|
1030
|
+
void 0,
|
|
1031
|
+
options.icons?.print
|
|
1032
|
+
);
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
1035
|
+
if (id === "search" && options.search !== false) {
|
|
1036
|
+
renderSearchControl();
|
|
1037
|
+
return;
|
|
1038
|
+
}
|
|
1039
|
+
};
|
|
1040
|
+
const renderCustomAction = (action) => {
|
|
1041
|
+
const button = addButton(
|
|
1042
|
+
action.label,
|
|
1043
|
+
action.title || action.label,
|
|
1044
|
+
() => void action.onClick(getContext()),
|
|
1045
|
+
action.className,
|
|
1046
|
+
action.icon
|
|
1047
|
+
);
|
|
1048
|
+
button.dataset.ofvToolbarAction = action.id;
|
|
1049
|
+
customButtons.push({ button, action });
|
|
1050
|
+
};
|
|
1051
|
+
const renderSearchControl = () => {
|
|
988
1052
|
const searchGroup = document.createElement("div");
|
|
989
1053
|
searchGroup.className = "ofv-toolbar-search";
|
|
990
|
-
searchGroup.title =
|
|
1054
|
+
searchGroup.title = getToolbarTitle(options, "search");
|
|
991
1055
|
const nextSearchInput = document.createElement("input");
|
|
992
1056
|
nextSearchInput.type = "search";
|
|
993
|
-
nextSearchInput.placeholder = "
|
|
994
|
-
nextSearchInput.setAttribute("aria-label",
|
|
1057
|
+
nextSearchInput.placeholder = getToolbarLabel(options, "search");
|
|
1058
|
+
nextSearchInput.setAttribute("aria-label", getToolbarTitle(options, "search"));
|
|
995
1059
|
const nextSearchCount = document.createElement("span");
|
|
996
1060
|
nextSearchCount.className = "ofv-toolbar-search-count";
|
|
997
1061
|
searchInput = nextSearchInput;
|
|
@@ -1004,18 +1068,53 @@ function createToolbar(toolbar, viewport, queue) {
|
|
|
1004
1068
|
searchGroup.append(nextSearchInput, nextSearchCount);
|
|
1005
1069
|
element.append(searchGroup);
|
|
1006
1070
|
disposers.push(() => nextSearchInput.removeEventListener("input", runSearch));
|
|
1007
|
-
}
|
|
1071
|
+
};
|
|
1072
|
+
const renderToolbar = () => {
|
|
1073
|
+
if (options.render) {
|
|
1074
|
+
element.replaceChildren();
|
|
1075
|
+
const customElement = options.render(getContext());
|
|
1076
|
+
if (customElement) {
|
|
1077
|
+
element.append(customElement);
|
|
1078
|
+
}
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
getToolbarOrder(options, queue.getLength()).forEach(renderDefaultAction);
|
|
1082
|
+
getImplicitCustomActions(options).forEach(renderCustomAction);
|
|
1083
|
+
};
|
|
1084
|
+
renderToolbar();
|
|
1085
|
+
const updateCustomButtons = () => {
|
|
1086
|
+
const context = getContext();
|
|
1087
|
+
for (const { button, action } of customButtons) {
|
|
1088
|
+
button.disabled = evaluateToolbarFlag(action.disabled, context);
|
|
1089
|
+
button.hidden = evaluateToolbarFlag(action.hidden, context);
|
|
1090
|
+
}
|
|
1091
|
+
};
|
|
1092
|
+
const resetSearch = () => {
|
|
1093
|
+
search.clear();
|
|
1094
|
+
if (searchInput) {
|
|
1095
|
+
searchInput.value = "";
|
|
1096
|
+
}
|
|
1097
|
+
if (searchCount) {
|
|
1098
|
+
searchCount.textContent = "";
|
|
1099
|
+
}
|
|
1100
|
+
};
|
|
1101
|
+
const refreshCustomRender = () => {
|
|
1102
|
+
if (!options.render) {
|
|
1103
|
+
return;
|
|
1104
|
+
}
|
|
1105
|
+
element.replaceChildren();
|
|
1106
|
+
const customElement = options.render(getContext());
|
|
1107
|
+
if (customElement) {
|
|
1108
|
+
element.append(customElement);
|
|
1109
|
+
}
|
|
1110
|
+
};
|
|
1008
1111
|
return {
|
|
1009
1112
|
element,
|
|
1010
1113
|
update(nextFile, index, length) {
|
|
1011
1114
|
file = nextFile;
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
}
|
|
1016
|
-
if (searchCount) {
|
|
1017
|
-
searchCount.textContent = "";
|
|
1018
|
-
}
|
|
1115
|
+
currentIndex = index;
|
|
1116
|
+
currentLength = length;
|
|
1117
|
+
resetSearch();
|
|
1019
1118
|
commandButtons.forEach(({ button }) => {
|
|
1020
1119
|
button.disabled = true;
|
|
1021
1120
|
});
|
|
@@ -1028,20 +1127,158 @@ function createToolbar(toolbar, viewport, queue) {
|
|
|
1028
1127
|
if (nextButton) {
|
|
1029
1128
|
nextButton.disabled = index >= length - 1;
|
|
1030
1129
|
}
|
|
1130
|
+
updateCustomButtons();
|
|
1131
|
+
refreshCustomRender();
|
|
1031
1132
|
},
|
|
1032
1133
|
setCommandSupport(isSupported) {
|
|
1134
|
+
canRunCommand = isSupported;
|
|
1033
1135
|
commandButtons.forEach(({ button, command }) => {
|
|
1034
1136
|
button.disabled = !isSupported(command);
|
|
1035
1137
|
});
|
|
1138
|
+
updateCustomButtons();
|
|
1139
|
+
refreshCustomRender();
|
|
1036
1140
|
},
|
|
1141
|
+
getContext,
|
|
1037
1142
|
destroy() {
|
|
1038
1143
|
search.clear();
|
|
1039
1144
|
for (const dispose of disposers) {
|
|
1040
1145
|
dispose();
|
|
1041
1146
|
}
|
|
1147
|
+
element.replaceChildren();
|
|
1042
1148
|
}
|
|
1043
1149
|
};
|
|
1044
1150
|
}
|
|
1151
|
+
function createToolbarContext({
|
|
1152
|
+
file,
|
|
1153
|
+
index,
|
|
1154
|
+
length,
|
|
1155
|
+
viewport,
|
|
1156
|
+
queue,
|
|
1157
|
+
element,
|
|
1158
|
+
search,
|
|
1159
|
+
canCommand
|
|
1160
|
+
}) {
|
|
1161
|
+
return {
|
|
1162
|
+
file,
|
|
1163
|
+
index,
|
|
1164
|
+
length,
|
|
1165
|
+
viewport,
|
|
1166
|
+
canPrevious: index > 0,
|
|
1167
|
+
canNext: index < length - 1,
|
|
1168
|
+
async previous() {
|
|
1169
|
+
await queue.previous();
|
|
1170
|
+
},
|
|
1171
|
+
async next() {
|
|
1172
|
+
await queue.next();
|
|
1173
|
+
},
|
|
1174
|
+
command: queue.command,
|
|
1175
|
+
canCommand,
|
|
1176
|
+
download() {
|
|
1177
|
+
if (file) {
|
|
1178
|
+
downloadFile(file);
|
|
1179
|
+
}
|
|
1180
|
+
},
|
|
1181
|
+
fullscreen() {
|
|
1182
|
+
void element.parentElement?.requestFullscreen?.();
|
|
1183
|
+
},
|
|
1184
|
+
print() {
|
|
1185
|
+
printPreview(viewport);
|
|
1186
|
+
},
|
|
1187
|
+
search: search.search,
|
|
1188
|
+
clearSearch: search.clear
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
var defaultToolbarLabels = {
|
|
1192
|
+
previous: "Prev",
|
|
1193
|
+
next: "Next",
|
|
1194
|
+
queue: "",
|
|
1195
|
+
"zoom-out": "-",
|
|
1196
|
+
"zoom-in": "+",
|
|
1197
|
+
"zoom-reset": "100%",
|
|
1198
|
+
"rotate-right": "Rotate",
|
|
1199
|
+
download: "Download",
|
|
1200
|
+
fullscreen: "Fullscreen",
|
|
1201
|
+
print: "Print",
|
|
1202
|
+
search: "Search"
|
|
1203
|
+
};
|
|
1204
|
+
var defaultToolbarTitles = {
|
|
1205
|
+
previous: "Previous file",
|
|
1206
|
+
next: "Next file",
|
|
1207
|
+
queue: "Current file position",
|
|
1208
|
+
"zoom-out": "Zoom out",
|
|
1209
|
+
"zoom-in": "Zoom in",
|
|
1210
|
+
"zoom-reset": "Reset zoom",
|
|
1211
|
+
"rotate-right": "Rotate right",
|
|
1212
|
+
download: "Download file",
|
|
1213
|
+
fullscreen: "Open preview fullscreen",
|
|
1214
|
+
print: "Print preview",
|
|
1215
|
+
search: "Search preview text"
|
|
1216
|
+
};
|
|
1217
|
+
function getToolbarLabel(options, id) {
|
|
1218
|
+
return options.labels?.[id] ?? defaultToolbarLabels[id];
|
|
1219
|
+
}
|
|
1220
|
+
function getToolbarTitle(options, id) {
|
|
1221
|
+
return options.titles?.[id] ?? options.labels?.[id] ?? defaultToolbarTitles[id];
|
|
1222
|
+
}
|
|
1223
|
+
function getToolbarOrder(options, queueLength) {
|
|
1224
|
+
if (options.order) {
|
|
1225
|
+
return options.order;
|
|
1226
|
+
}
|
|
1227
|
+
const actions = [];
|
|
1228
|
+
if (queueLength > 1) {
|
|
1229
|
+
actions.push("previous", "next", "queue");
|
|
1230
|
+
}
|
|
1231
|
+
if (options.zoom) {
|
|
1232
|
+
actions.push("zoom-out", "zoom-in", "zoom-reset");
|
|
1233
|
+
}
|
|
1234
|
+
if (options.rotate) {
|
|
1235
|
+
actions.push("rotate-right");
|
|
1236
|
+
}
|
|
1237
|
+
if (options.download !== false) {
|
|
1238
|
+
actions.push("download");
|
|
1239
|
+
}
|
|
1240
|
+
if (options.fullscreen !== false) {
|
|
1241
|
+
actions.push("fullscreen");
|
|
1242
|
+
}
|
|
1243
|
+
if (options.print) {
|
|
1244
|
+
actions.push("print");
|
|
1245
|
+
}
|
|
1246
|
+
if (options.search !== false) {
|
|
1247
|
+
actions.push("search");
|
|
1248
|
+
}
|
|
1249
|
+
return actions;
|
|
1250
|
+
}
|
|
1251
|
+
function getImplicitCustomActions(options) {
|
|
1252
|
+
if (options.order || !options.actions) {
|
|
1253
|
+
return [];
|
|
1254
|
+
}
|
|
1255
|
+
return [...options.actions].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
1256
|
+
}
|
|
1257
|
+
function evaluateToolbarFlag(value, context) {
|
|
1258
|
+
return typeof value === "function" ? value(context) : Boolean(value);
|
|
1259
|
+
}
|
|
1260
|
+
function setToolbarButtonContent(button, label, icon) {
|
|
1261
|
+
button.replaceChildren();
|
|
1262
|
+
if (!icon) {
|
|
1263
|
+
button.textContent = label;
|
|
1264
|
+
return;
|
|
1265
|
+
}
|
|
1266
|
+
const iconElement = document.createElement("span");
|
|
1267
|
+
iconElement.className = "ofv-toolbar-icon";
|
|
1268
|
+
iconElement.setAttribute("aria-hidden", "true");
|
|
1269
|
+
if (typeof icon === "string") {
|
|
1270
|
+
iconElement.innerHTML = icon;
|
|
1271
|
+
} else {
|
|
1272
|
+
iconElement.append(icon.cloneNode(true));
|
|
1273
|
+
}
|
|
1274
|
+
const labelElement = document.createElement("span");
|
|
1275
|
+
labelElement.className = "ofv-toolbar-label";
|
|
1276
|
+
labelElement.textContent = label;
|
|
1277
|
+
button.append(iconElement, labelElement);
|
|
1278
|
+
}
|
|
1279
|
+
function isBuiltInToolbarAction(id) {
|
|
1280
|
+
return id in defaultToolbarLabels;
|
|
1281
|
+
}
|
|
1045
1282
|
function createSearchController(root) {
|
|
1046
1283
|
const markerClass = "ofv-search-match";
|
|
1047
1284
|
const clear = () => {
|