@file-viewer/core 2.2.2 → 2.2.4
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.en.md +2 -2
- package/README.md +2 -2
- package/dist/browser/controller.d.ts +137 -0
- package/dist/browser/controller.js +967 -0
- package/dist/browser.d.ts +1 -0
- package/dist/browser.js +1 -0
- package/dist/contracts/types.d.ts +5 -4
- package/dist/features/printMaskDesigner.js +9 -4
- package/dist/headless.d.ts +2 -2
- package/dist/headless.js +2 -2
- package/dist/i18n/messages.d.ts +4 -2
- package/dist/i18n/messages.ja.d.ts +7 -0
- package/dist/i18n/messages.ja.js +429 -0
- package/dist/i18n/messages.js +41 -11
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/lifecycle/operations.d.ts +6 -4
- package/dist/lifecycle/operations.js +12 -5
- package/dist/platform/assets.d.ts +8 -5
- package/dist/platform/assets.js +67 -13
- package/dist/rendering/handler.js +12 -5
- package/dist/viewer/state.js +19 -7
- package/package.json +4 -4
|
@@ -0,0 +1,967 @@
|
|
|
1
|
+
import { appendFileViewerStyle, applyFileViewerZoomAvailability, createViewer, isFileViewerShadowRoot, normalizeFileViewerUiDensity, normalizeFileViewerTheme, normalizeFileViewerStyleIsolation, syncFileViewerRenderSurfaceBackground, } from '../index.js';
|
|
2
|
+
import { DEFAULT_FILE_VIEWER_SOURCE_FILENAME, createFileViewerTranslator, getExtension, normalizeFileViewerSourceUrl, hasVisibleFileViewerToolbarActions, isFileViewerZoomButtonDisabled, normalizeFileViewerToolbar, normalizeFilename, readFileViewerBuffer, resolveFileViewerSourceFilename, resolveFileViewerColorScheme, resolveFileViewerToolbarOrder, resolveFileViewerToolbarPosition, resolveVisibleFileViewerToolbar, toggleFileViewerColorScheme, wrapFileViewerFileRef, } from '../index.js';
|
|
3
|
+
const isBrowser = () => typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
4
|
+
const hasSource = (options = {}) => {
|
|
5
|
+
return !!(options.url || options.file || options.buffer);
|
|
6
|
+
};
|
|
7
|
+
const toViewerSourceInput = (options = {}) => ({
|
|
8
|
+
url: options.url,
|
|
9
|
+
file: options.file,
|
|
10
|
+
buffer: options.buffer,
|
|
11
|
+
filename: options.filename || options.name,
|
|
12
|
+
name: options.name,
|
|
13
|
+
type: options.type,
|
|
14
|
+
size: options.size,
|
|
15
|
+
});
|
|
16
|
+
const canUseFetch = () => typeof fetch === 'function';
|
|
17
|
+
const defaultFetchFile = async ({ url, signal }) => {
|
|
18
|
+
if (!canUseFetch()) {
|
|
19
|
+
throw new Error('fetch is not available in the current environment.');
|
|
20
|
+
}
|
|
21
|
+
const requestUrl = normalizeFileViewerSourceUrl(url) || url;
|
|
22
|
+
const response = await fetch(requestUrl, { signal });
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
throw new Error(`Failed to fetch file: ${response.status} ${response.statusText}`);
|
|
25
|
+
}
|
|
26
|
+
return response.blob();
|
|
27
|
+
};
|
|
28
|
+
const resolveViewerSourceFilename = (source) => {
|
|
29
|
+
return normalizeFilename(source.filename || source.name || resolveFileViewerSourceFilename({
|
|
30
|
+
file: source.file,
|
|
31
|
+
url: source.url,
|
|
32
|
+
fallback: DEFAULT_FILE_VIEWER_SOURCE_FILENAME,
|
|
33
|
+
}), source.type ? `preview.${source.type}` : DEFAULT_FILE_VIEWER_SOURCE_FILENAME);
|
|
34
|
+
};
|
|
35
|
+
const resolveViewerLoadSource = async (source, options = {}) => {
|
|
36
|
+
var _a, _b, _c;
|
|
37
|
+
const filename = resolveViewerSourceFilename(source);
|
|
38
|
+
const type = source.type || getExtension(filename);
|
|
39
|
+
if (source.buffer) {
|
|
40
|
+
return {
|
|
41
|
+
buffer: source.buffer,
|
|
42
|
+
filename,
|
|
43
|
+
type,
|
|
44
|
+
size: (_a = source.size) !== null && _a !== void 0 ? _a : source.buffer.byteLength,
|
|
45
|
+
url: source.url,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (source.file) {
|
|
49
|
+
const file = wrapFileViewerFileRef(source.file, filename);
|
|
50
|
+
return {
|
|
51
|
+
file,
|
|
52
|
+
buffer: await readFileViewerBuffer(file),
|
|
53
|
+
filename: file.name || filename,
|
|
54
|
+
type: type || getExtension(file.name),
|
|
55
|
+
size: (_b = source.size) !== null && _b !== void 0 ? _b : file.size,
|
|
56
|
+
url: source.url,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (source.url) {
|
|
60
|
+
const fileRef = await (options.fetchFile || defaultFetchFile)({
|
|
61
|
+
url: source.url,
|
|
62
|
+
signal: options.signal,
|
|
63
|
+
source,
|
|
64
|
+
});
|
|
65
|
+
if (!fileRef) {
|
|
66
|
+
throw new Error('Downloaded file is empty.');
|
|
67
|
+
}
|
|
68
|
+
const file = wrapFileViewerFileRef(fileRef, filename);
|
|
69
|
+
return {
|
|
70
|
+
file,
|
|
71
|
+
buffer: await readFileViewerBuffer(file),
|
|
72
|
+
filename: file.name || filename,
|
|
73
|
+
type: type || getExtension(file.name),
|
|
74
|
+
size: (_c = source.size) !== null && _c !== void 0 ? _c : file.size,
|
|
75
|
+
url: source.url,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
filename,
|
|
80
|
+
type,
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
export const createViewerControllerHandle = (getController, dispose) => ({
|
|
84
|
+
load(options) {
|
|
85
|
+
var _a, _b;
|
|
86
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.load(options)) !== null && _b !== void 0 ? _b : Promise.resolve();
|
|
87
|
+
},
|
|
88
|
+
update(options) {
|
|
89
|
+
var _a, _b;
|
|
90
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.update(options)) !== null && _b !== void 0 ? _b : Promise.resolve();
|
|
91
|
+
},
|
|
92
|
+
reload() {
|
|
93
|
+
var _a, _b;
|
|
94
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.reload()) !== null && _b !== void 0 ? _b : Promise.resolve();
|
|
95
|
+
},
|
|
96
|
+
destroy() {
|
|
97
|
+
dispose();
|
|
98
|
+
},
|
|
99
|
+
getController,
|
|
100
|
+
getApi() {
|
|
101
|
+
var _a, _b;
|
|
102
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.getApi()) !== null && _b !== void 0 ? _b : null;
|
|
103
|
+
},
|
|
104
|
+
downloadOriginalFile() {
|
|
105
|
+
var _a, _b;
|
|
106
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.downloadOriginalFile()) !== null && _b !== void 0 ? _b : Promise.resolve();
|
|
107
|
+
},
|
|
108
|
+
printRenderedHtml(options) {
|
|
109
|
+
var _a, _b;
|
|
110
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.printRenderedHtml(options)) !== null && _b !== void 0 ? _b : Promise.resolve();
|
|
111
|
+
},
|
|
112
|
+
printWithMask(options) {
|
|
113
|
+
var _a, _b;
|
|
114
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.printWithMask(options)) !== null && _b !== void 0 ? _b : Promise.resolve();
|
|
115
|
+
},
|
|
116
|
+
exportRenderedHtml() {
|
|
117
|
+
var _a, _b;
|
|
118
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.exportRenderedHtml()) !== null && _b !== void 0 ? _b : Promise.resolve();
|
|
119
|
+
},
|
|
120
|
+
zoomIn() {
|
|
121
|
+
var _a, _b;
|
|
122
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.zoomIn()) !== null && _b !== void 0 ? _b : Promise.resolve(null);
|
|
123
|
+
},
|
|
124
|
+
zoomOut() {
|
|
125
|
+
var _a, _b;
|
|
126
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.zoomOut()) !== null && _b !== void 0 ? _b : Promise.resolve(null);
|
|
127
|
+
},
|
|
128
|
+
resetZoom() {
|
|
129
|
+
var _a, _b;
|
|
130
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.resetZoom()) !== null && _b !== void 0 ? _b : Promise.resolve(null);
|
|
131
|
+
},
|
|
132
|
+
fitToView(fit) {
|
|
133
|
+
var _a, _b;
|
|
134
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.fitToView(fit)) !== null && _b !== void 0 ? _b : Promise.resolve(null);
|
|
135
|
+
},
|
|
136
|
+
getViewState() {
|
|
137
|
+
var _a, _b;
|
|
138
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.getViewState()) !== null && _b !== void 0 ? _b : null;
|
|
139
|
+
},
|
|
140
|
+
applyViewState(state, options) {
|
|
141
|
+
var _a, _b;
|
|
142
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.applyViewState(state, options)) !== null && _b !== void 0 ? _b : Promise.resolve(null);
|
|
143
|
+
},
|
|
144
|
+
searchDocument(query) {
|
|
145
|
+
var _a, _b;
|
|
146
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.searchDocument(query)) !== null && _b !== void 0 ? _b : Promise.resolve(null);
|
|
147
|
+
},
|
|
148
|
+
clearDocumentSearch() {
|
|
149
|
+
var _a, _b;
|
|
150
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.clearDocumentSearch()) !== null && _b !== void 0 ? _b : Promise.resolve(null);
|
|
151
|
+
},
|
|
152
|
+
nextSearchResult() {
|
|
153
|
+
var _a, _b;
|
|
154
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.nextSearchResult()) !== null && _b !== void 0 ? _b : Promise.resolve(null);
|
|
155
|
+
},
|
|
156
|
+
previousSearchResult() {
|
|
157
|
+
var _a, _b;
|
|
158
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.previousSearchResult()) !== null && _b !== void 0 ? _b : Promise.resolve(null);
|
|
159
|
+
},
|
|
160
|
+
collectDocumentAnchors() {
|
|
161
|
+
var _a, _b;
|
|
162
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.collectDocumentAnchors()) !== null && _b !== void 0 ? _b : Promise.resolve([]);
|
|
163
|
+
},
|
|
164
|
+
scrollToAnchor(anchor) {
|
|
165
|
+
var _a, _b;
|
|
166
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.scrollToAnchor(anchor)) !== null && _b !== void 0 ? _b : Promise.resolve(false);
|
|
167
|
+
},
|
|
168
|
+
scrollToLine(line) {
|
|
169
|
+
var _a, _b;
|
|
170
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.scrollToLine(line)) !== null && _b !== void 0 ? _b : Promise.resolve(false);
|
|
171
|
+
},
|
|
172
|
+
getDocumentTextChunks() {
|
|
173
|
+
var _a, _b;
|
|
174
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.getDocumentTextChunks()) !== null && _b !== void 0 ? _b : [];
|
|
175
|
+
},
|
|
176
|
+
getOperationAvailability() {
|
|
177
|
+
var _a, _b;
|
|
178
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.getOperationAvailability()) !== null && _b !== void 0 ? _b : null;
|
|
179
|
+
},
|
|
180
|
+
getZoomState() {
|
|
181
|
+
var _a, _b;
|
|
182
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.getZoomState()) !== null && _b !== void 0 ? _b : null;
|
|
183
|
+
},
|
|
184
|
+
getSearchState() {
|
|
185
|
+
var _a, _b;
|
|
186
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.getSearchState()) !== null && _b !== void 0 ? _b : null;
|
|
187
|
+
},
|
|
188
|
+
getState() {
|
|
189
|
+
var _a, _b;
|
|
190
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.getState()) !== null && _b !== void 0 ? _b : null;
|
|
191
|
+
},
|
|
192
|
+
subscribe(listener) {
|
|
193
|
+
var _a, _b;
|
|
194
|
+
return (_b = (_a = getController()) === null || _a === void 0 ? void 0 : _a.subscribe(listener)) !== null && _b !== void 0 ? _b : (() => { });
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
const callApi = async (api, action, fallback) => {
|
|
198
|
+
if (!api) {
|
|
199
|
+
return fallback;
|
|
200
|
+
}
|
|
201
|
+
return action(api);
|
|
202
|
+
};
|
|
203
|
+
const isAbortError = (error) => {
|
|
204
|
+
return Boolean(error && typeof error === 'object' && error.name === 'AbortError');
|
|
205
|
+
};
|
|
206
|
+
const DEFAULT_TOOLBAR_AVAILABILITY = {
|
|
207
|
+
download: false,
|
|
208
|
+
print: false,
|
|
209
|
+
exportHtml: false,
|
|
210
|
+
zoom: false,
|
|
211
|
+
zoomIn: false,
|
|
212
|
+
zoomOut: false,
|
|
213
|
+
zoomReset: false,
|
|
214
|
+
};
|
|
215
|
+
const DEFAULT_TOOLBAR_ZOOM_STATE = {
|
|
216
|
+
scale: 1,
|
|
217
|
+
label: '100%',
|
|
218
|
+
canZoomIn: false,
|
|
219
|
+
canZoomOut: false,
|
|
220
|
+
canReset: false,
|
|
221
|
+
};
|
|
222
|
+
// A ShadowRoot cannot be detached. Track the exact roots created on viewer
|
|
223
|
+
// hosts so a later light-DOM remount can expose its children through a slot,
|
|
224
|
+
// without mistaking and clearing a ShadowRoot owned by the host application.
|
|
225
|
+
const ownedViewerShadowRoots = new WeakMap();
|
|
226
|
+
const WEB_VIEWER_STYLE = `
|
|
227
|
+
:host,.file-viewer-web-shell{display:block;width:100%;height:100%;min-width:0;min-height:0;contain:content;--file-viewer-bg:transparent;--file-viewer-content-bg:transparent;--file-viewer-text:#172033;--file-viewer-muted:#607282;--file-viewer-font:14px/1.45 system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;--file-viewer-border:rgba(20,35,53,.08);--file-viewer-toolbar-bg:rgba(255,255,255,.92);--file-viewer-toolbar-border:rgba(20,35,53,.06);--file-viewer-toolbar-shadow:0 18px 44px rgba(15,23,42,.16);--file-viewer-toolbar-radius:999px;--file-viewer-toolbar-gap:6px;--file-viewer-toolbar-min-height:45px;--file-viewer-toolbar-padding:6px 10px;--file-viewer-toolbar-floating-min-height:42px;--file-viewer-toolbar-floating-padding:6px;--file-viewer-toolbar-floating-offset:16px;--file-viewer-group-bg:rgba(20,35,53,.035);--file-viewer-group-border:rgba(20,35,53,.08);--file-viewer-group-gap:2px;--file-viewer-group-padding:2px;--file-viewer-button-color:#40546a;--file-viewer-button-hover-bg:rgba(33,163,102,.1);--file-viewer-button-hover-color:#16774c;--file-viewer-button-disabled-color:#aab5c0;--file-viewer-button-radius:8px;--file-viewer-button-min-width:42px;--file-viewer-button-height:30px;--file-viewer-button-padding:0 10px;--file-viewer-icon-button-size:30px;--file-viewer-zoom-meter-min-width:48px;--file-viewer-zoom-meter-padding:0 8px;--file-viewer-floating-button-min-width:48px;--file-viewer-floating-button-height:32px;--file-viewer-floating-icon-button-size:32px;--file-viewer-floating-zoom-meter-min-width:54px;--file-viewer-search-input-height:30px;--file-viewer-search-input-padding:0 10px;--file-viewer-search-button-min-width:32px;--file-viewer-search-button-padding:0 8px;--file-viewer-search-count-min-width:42px;--file-viewer-floating-search-input-height:32px;--file-viewer-focus-ring:rgba(31,157,103,.22);--file-viewer-z-toolbar:20;--file-viewer-z-floating-toolbar:30}
|
|
228
|
+
:host([theme='dark']),.file-viewer-web-shell[data-viewer-theme='dark']{--file-viewer-bg:#0f1720;--file-viewer-content-bg:#111b24;--file-viewer-text:#e5eef8;--file-viewer-muted:#cbd5e1;--file-viewer-border:rgba(148,163,184,.18);--file-viewer-toolbar-bg:rgba(15,23,42,.9);--file-viewer-toolbar-border:rgba(148,163,184,.18);--file-viewer-group-bg:rgba(148,163,184,.1);--file-viewer-group-border:rgba(148,163,184,.16);--file-viewer-button-color:#d7dee8;--file-viewer-button-hover-bg:rgba(45,212,191,.14);--file-viewer-button-hover-color:#5eead4;--file-viewer-button-disabled-color:#64748b;--file-viewer-input-bg:rgba(15,23,42,.78);--file-viewer-input-color:#f8fafc}
|
|
229
|
+
.file-viewer-web-shell,.file-viewer-web-shell *,.file-viewer-web-shell *::before,.file-viewer-web-shell *::after{box-sizing:border-box}
|
|
230
|
+
.file-viewer-web-shell{position:relative;width:100%;height:100%;min-height:0;display:flex;flex-direction:column;overflow:hidden;background:var(--file-viewer-render-surface-background,var(--file-viewer-bg));color:var(--file-viewer-text);font:var(--file-viewer-font);letter-spacing:0;box-sizing:border-box;contain:content}
|
|
231
|
+
.file-viewer-web-shell[data-viewer-density="compact"]{--file-viewer-toolbar-gap:3px;--file-viewer-toolbar-min-height:34px;--file-viewer-toolbar-padding:3px 5px;--file-viewer-toolbar-floating-min-height:32px;--file-viewer-toolbar-floating-padding:3px;--file-viewer-toolbar-floating-offset:10px;--file-viewer-group-gap:2px;--file-viewer-group-padding:2px;--file-viewer-button-radius:6px;--file-viewer-button-min-width:34px;--file-viewer-button-height:26px;--file-viewer-button-padding:0 6px;--file-viewer-icon-button-size:26px;--file-viewer-zoom-meter-min-width:42px;--file-viewer-zoom-meter-padding:0 5px;--file-viewer-floating-button-min-width:38px;--file-viewer-floating-button-height:28px;--file-viewer-floating-icon-button-size:28px;--file-viewer-floating-zoom-meter-min-width:46px;--file-viewer-search-input-height:26px;--file-viewer-search-input-padding:0 8px;--file-viewer-search-button-min-width:28px;--file-viewer-search-button-padding:0 6px;--file-viewer-search-count-min-width:36px;--file-viewer-floating-search-input-height:28px}
|
|
232
|
+
.file-viewer-web-content{position:relative;flex:1 1 auto;min-height:0;min-width:0;overflow:auto;overscroll-behavior:contain;background:var(--file-viewer-render-surface-background,var(--file-viewer-content-bg))}
|
|
233
|
+
.file-viewer-web-toolbar{flex:0 0 auto;min-height:var(--file-viewer-toolbar-min-height);display:inline-flex;align-items:center;justify-content:flex-end;gap:var(--file-viewer-toolbar-gap);padding:var(--file-viewer-toolbar-padding);border-bottom:1px solid var(--file-viewer-toolbar-border);background:var(--file-viewer-toolbar-bg);box-sizing:border-box;z-index:var(--file-viewer-z-toolbar)}
|
|
234
|
+
.file-viewer-web-toolbar[hidden]{display:none!important}
|
|
235
|
+
.file-viewer-web-toolbar[data-toolbar-position="top-center"]{justify-content:center}
|
|
236
|
+
.file-viewer-web-toolbar[data-toolbar-position="bottom-right"]{position:absolute;right:calc(var(--file-viewer-toolbar-floating-offset) + env(safe-area-inset-right,0px));bottom:calc(var(--file-viewer-toolbar-floating-offset) + env(safe-area-inset-bottom,0px));min-height:var(--file-viewer-toolbar-floating-min-height);padding:var(--file-viewer-toolbar-floating-padding);border:1px solid var(--file-viewer-border);border-radius:var(--file-viewer-toolbar-radius);background:var(--file-viewer-toolbar-bg);box-shadow:var(--file-viewer-toolbar-shadow);backdrop-filter:blur(16px);z-index:var(--file-viewer-z-floating-toolbar)}
|
|
237
|
+
.file-viewer-web-toolbar-group{display:inline-flex;align-items:center;gap:var(--file-viewer-group-gap);padding:var(--file-viewer-group-padding);border:1px solid var(--file-viewer-group-border);border-radius:var(--file-viewer-toolbar-radius);background:var(--file-viewer-group-bg)}
|
|
238
|
+
.file-viewer-web-toolbar button{min-width:var(--file-viewer-button-min-width);height:var(--file-viewer-button-height);padding:var(--file-viewer-button-padding);border:0;border-radius:var(--file-viewer-button-radius);background:transparent;color:var(--file-viewer-button-color);font:inherit;font-size:12px;font-weight:800;line-height:1;letter-spacing:0;white-space:nowrap;cursor:pointer}
|
|
239
|
+
.file-viewer-web-toolbar button:hover:not(:disabled){background:var(--file-viewer-button-hover-bg);color:var(--file-viewer-button-hover-color)}
|
|
240
|
+
.file-viewer-web-toolbar button:disabled{color:var(--file-viewer-button-disabled-color);cursor:not-allowed}
|
|
241
|
+
.file-viewer-web-toolbar .file-viewer-web-icon-button{width:var(--file-viewer-icon-button-size);min-width:var(--file-viewer-icon-button-size);padding:0;display:inline-flex;align-items:center;justify-content:center}
|
|
242
|
+
.file-viewer-web-theme-button svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
|
|
243
|
+
.file-viewer-web-toolbar .file-viewer-web-zoom-meter{min-width:var(--file-viewer-zoom-meter-min-width);height:var(--file-viewer-button-height);padding:var(--file-viewer-zoom-meter-padding);display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;color:var(--file-viewer-button-color)}
|
|
244
|
+
.file-viewer-web-toolbar .file-viewer-web-zoom-meter--readonly{font-size:12px;font-weight:800;line-height:1;white-space:nowrap}
|
|
245
|
+
.file-viewer-web-print-menu{position:relative;display:inline-flex}
|
|
246
|
+
.file-viewer-web-print-menu > button{min-width:var(--file-viewer-button-min-width);height:var(--file-viewer-button-height);padding:var(--file-viewer-button-padding);border:0;border-radius:var(--file-viewer-button-radius);background:transparent;color:var(--file-viewer-button-color);font:inherit;font-size:12px;font-weight:800;line-height:1;letter-spacing:0;white-space:nowrap;cursor:pointer}
|
|
247
|
+
.file-viewer-web-print-menu > button:hover:not(:disabled){background:var(--file-viewer-button-hover-bg);color:var(--file-viewer-button-hover-color)}
|
|
248
|
+
.file-viewer-web-print-menu > button:disabled{color:var(--file-viewer-button-disabled-color);cursor:not-allowed}
|
|
249
|
+
.file-viewer-web-print-menu-panel{position:absolute;top:calc(100% + 4px);right:0;z-index:40;min-width:118px;padding:4px;border:1px solid var(--file-viewer-group-border);border-radius:10px;background:var(--file-viewer-toolbar-bg);box-shadow:var(--file-viewer-toolbar-shadow);display:none;flex-direction:column;gap:2px}
|
|
250
|
+
.file-viewer-web-print-menu[data-open="true"] .file-viewer-web-print-menu-panel{display:flex}
|
|
251
|
+
.file-viewer-web-print-menu-panel button{width:100%;min-width:0;justify-content:flex-start;text-align:left;border-radius:8px}
|
|
252
|
+
.file-viewer-web-toolbar[data-toolbar-position="bottom-right"] .file-viewer-web-print-menu-panel{top:auto;bottom:calc(100% + 6px);z-index:50}
|
|
253
|
+
.file-viewer-web-search{gap:4px}
|
|
254
|
+
.file-viewer-web-search input{width:clamp(128px,18vw,220px);height:var(--file-viewer-search-input-height);box-sizing:border-box;border:0;border-radius:var(--file-viewer-toolbar-radius);padding:var(--file-viewer-search-input-padding);background:var(--file-viewer-input-bg);color:var(--file-viewer-input-color);font:inherit;font-size:12px;line-height:var(--file-viewer-search-input-height);letter-spacing:0;outline:0}
|
|
255
|
+
.file-viewer-web-search input:focus{box-shadow:0 0 0 2px var(--file-viewer-focus-ring)}
|
|
256
|
+
.file-viewer-web-search button{min-width:var(--file-viewer-search-button-min-width);height:var(--file-viewer-search-input-height);padding:var(--file-viewer-search-button-padding);border-radius:999px}
|
|
257
|
+
.file-viewer-web-search-count{min-width:var(--file-viewer-search-count-min-width);text-align:center;color:var(--file-viewer-muted);font-size:12px;font-weight:800;line-height:var(--file-viewer-search-input-height);white-space:nowrap}
|
|
258
|
+
.file-viewer-web-toolbar[data-toolbar-position="bottom-right"] button{min-width:var(--file-viewer-floating-button-min-width);height:var(--file-viewer-floating-button-height);border-radius:999px}
|
|
259
|
+
.file-viewer-web-toolbar[data-toolbar-position="bottom-right"] .file-viewer-web-icon-button{width:var(--file-viewer-floating-icon-button-size);min-width:var(--file-viewer-floating-icon-button-size)}
|
|
260
|
+
.file-viewer-web-toolbar[data-toolbar-position="bottom-right"] .file-viewer-web-zoom-meter{min-width:var(--file-viewer-floating-zoom-meter-min-width);height:var(--file-viewer-floating-button-height)}
|
|
261
|
+
.file-viewer-web-toolbar[data-toolbar-position="bottom-right"] .file-viewer-web-search button{min-width:var(--file-viewer-search-button-min-width);height:var(--file-viewer-floating-search-input-height)}
|
|
262
|
+
.file-viewer-web-toolbar[data-toolbar-position="bottom-right"] .file-viewer-web-search input{height:var(--file-viewer-floating-search-input-height);line-height:var(--file-viewer-floating-search-input-height);width:clamp(120px,18vw,190px)}
|
|
263
|
+
.file-viewer-web-shell[data-viewer-theme='dark']{color-scheme:dark;--file-viewer-bg:#0f1720;--file-viewer-content-bg:#111b24;--file-viewer-text:#e5eef8;--file-viewer-muted:#cbd5e1;--file-viewer-border:rgba(148,163,184,.18);--file-viewer-toolbar-bg:rgba(15,23,42,.9);--file-viewer-toolbar-border:rgba(148,163,184,.18);--file-viewer-group-bg:rgba(148,163,184,.1);--file-viewer-group-border:rgba(148,163,184,.16);--file-viewer-button-color:#d7dee8;--file-viewer-button-hover-bg:rgba(45,212,191,.14);--file-viewer-button-hover-color:#5eead4;--file-viewer-button-disabled-color:#64748b;--file-viewer-input-bg:rgba(15,23,42,.78);--file-viewer-input-color:#f8fafc}
|
|
264
|
+
@media (prefers-color-scheme:dark){.file-viewer-web-shell[data-viewer-theme='system']{color-scheme:dark;--file-viewer-bg:#0f1720;--file-viewer-content-bg:#111b24;--file-viewer-text:#e5eef8;--file-viewer-muted:#cbd5e1;--file-viewer-border:rgba(148,163,184,.18);--file-viewer-toolbar-bg:rgba(15,23,42,.9);--file-viewer-toolbar-border:rgba(148,163,184,.18);--file-viewer-group-bg:rgba(148,163,184,.1);--file-viewer-group-border:rgba(148,163,184,.16);--file-viewer-button-color:#d7dee8;--file-viewer-button-hover-bg:rgba(45,212,191,.14);--file-viewer-button-hover-color:#5eead4;--file-viewer-button-disabled-color:#64748b;--file-viewer-input-bg:rgba(15,23,42,.78);--file-viewer-input-color:#f8fafc}}
|
|
265
|
+
@media (max-width:640px){.file-viewer-web-toolbar{max-width:100%;overflow-x:auto;overflow-y:visible}.file-viewer-web-toolbar[data-toolbar-position="bottom-right"]{max-width:calc(100% - 32px);overflow:visible}.file-viewer-web-toolbar[data-toolbar-position="bottom-right"] .file-viewer-web-print-menu-panel{left:50%;right:auto;transform:translateX(-50%);min-width:min(148px,calc(100vw - 32px))}.file-viewer-web-search input{width:120px}}
|
|
266
|
+
`;
|
|
267
|
+
const addPart = (element, ...parts) => {
|
|
268
|
+
const partList = element.part;
|
|
269
|
+
if (partList === null || partList === void 0 ? void 0 : partList.add) {
|
|
270
|
+
partList.add(...parts);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const nextParts = new Set([
|
|
274
|
+
...(element.getAttribute('part') || '').split(/\s+/).filter(Boolean),
|
|
275
|
+
...parts,
|
|
276
|
+
]);
|
|
277
|
+
element.setAttribute('part', [...nextParts].join(' '));
|
|
278
|
+
};
|
|
279
|
+
const createButton = (documentRef, label, className, onClick) => {
|
|
280
|
+
const button = documentRef.createElement('button');
|
|
281
|
+
button.type = 'button';
|
|
282
|
+
button.className = className;
|
|
283
|
+
addPart(button, 'button');
|
|
284
|
+
button.textContent = label;
|
|
285
|
+
button.title = label;
|
|
286
|
+
button.setAttribute('aria-label', label);
|
|
287
|
+
button.addEventListener('click', () => {
|
|
288
|
+
void onClick();
|
|
289
|
+
});
|
|
290
|
+
return button;
|
|
291
|
+
};
|
|
292
|
+
const createReadonlyMeter = (documentRef, label, className) => {
|
|
293
|
+
const meter = documentRef.createElement('span');
|
|
294
|
+
meter.className = `${className} file-viewer-web-zoom-meter--readonly`;
|
|
295
|
+
addPart(meter, 'button');
|
|
296
|
+
meter.textContent = label;
|
|
297
|
+
meter.title = label;
|
|
298
|
+
meter.setAttribute('aria-label', label);
|
|
299
|
+
return meter;
|
|
300
|
+
};
|
|
301
|
+
const setThemeButtonIcon = (button, currentTheme) => {
|
|
302
|
+
button.innerHTML = currentTheme === 'dark'
|
|
303
|
+
? '<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.42 1.42M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.42-1.42M17.66 6.34l1.41-1.41"/></svg>'
|
|
304
|
+
: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79Z"/></svg>';
|
|
305
|
+
};
|
|
306
|
+
export const mountViewer = (container, initialOptions = {}, coreOptions = {}) => {
|
|
307
|
+
var _a, _b, _c, _d, _e;
|
|
308
|
+
if (!isBrowser()) {
|
|
309
|
+
throw new Error('Flyfish File Viewer can only be mounted in a browser DOM environment.');
|
|
310
|
+
}
|
|
311
|
+
const documentRef = container.ownerDocument;
|
|
312
|
+
const initialStyleIsolation = normalizeFileViewerStyleIsolation((_a = initialOptions.options) === null || _a === void 0 ? void 0 : _a.styleIsolation);
|
|
313
|
+
const shouldUseShadowRoot = initialStyleIsolation === 'auto' || initialStyleIsolation === 'shadow';
|
|
314
|
+
const existingHostShadowRoot = container.shadowRoot;
|
|
315
|
+
const ownedHostShadowRoot = ownedViewerShadowRoots.get(container);
|
|
316
|
+
const hasOwnedHostShadowRoot = Boolean(existingHostShadowRoot && ownedHostShadowRoot === existingHostShadowRoot);
|
|
317
|
+
const canAttachShadowRoot = typeof container.attachShadow === 'function' && !container.shadowRoot;
|
|
318
|
+
let mountBoundary = null;
|
|
319
|
+
let renderRoot = container;
|
|
320
|
+
if (shouldUseShadowRoot && hasOwnedHostShadowRoot && existingHostShadowRoot) {
|
|
321
|
+
renderRoot = existingHostShadowRoot;
|
|
322
|
+
}
|
|
323
|
+
else if (shouldUseShadowRoot && canAttachShadowRoot) {
|
|
324
|
+
try {
|
|
325
|
+
// The viewer owns this root even when its host already lives inside a
|
|
326
|
+
// customer's ShadowRoot. Reusing the ancestor would let that component's
|
|
327
|
+
// resets override the toolbar and would make our :host rules mutate the
|
|
328
|
+
// customer's outer custom element.
|
|
329
|
+
renderRoot = container.attachShadow({ mode: 'open', delegatesFocus: true });
|
|
330
|
+
ownedViewerShadowRoots.set(container, renderRoot);
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
// Some HTMLElement subclasses cannot host Shadow DOM, and a closed root
|
|
334
|
+
// is intentionally invisible through `shadowRoot`. Keep the legacy
|
|
335
|
+
// scoped path usable instead of surfacing a raw NotSupportedError.
|
|
336
|
+
renderRoot = container;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
else if (existingHostShadowRoot && !hasOwnedHostShadowRoot) {
|
|
340
|
+
// The application owns this root. Preserve every existing child and mount
|
|
341
|
+
// the viewer in a dedicated boundary. Shadow mode gets a nested root so
|
|
342
|
+
// customer resets in the outer component cannot reach the viewer.
|
|
343
|
+
mountBoundary = documentRef.createElement('div');
|
|
344
|
+
mountBoundary.dataset.fileViewerMountBoundary = 'true';
|
|
345
|
+
existingHostShadowRoot.appendChild(mountBoundary);
|
|
346
|
+
if (shouldUseShadowRoot && typeof mountBoundary.attachShadow === 'function') {
|
|
347
|
+
try {
|
|
348
|
+
renderRoot = mountBoundary.attachShadow({ mode: 'open', delegatesFocus: true });
|
|
349
|
+
}
|
|
350
|
+
catch {
|
|
351
|
+
renderRoot = mountBoundary;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
renderRoot = mountBoundary;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
else if (!shouldUseShadowRoot && hasOwnedHostShadowRoot && existingHostShadowRoot) {
|
|
359
|
+
// Light-DOM children of a shadow host are not painted unless the root has
|
|
360
|
+
// a slot. Keep the immutable owned root, but project the real light-DOM
|
|
361
|
+
// viewer so host selectors and legacy deep overrides work as documented.
|
|
362
|
+
const slot = documentRef.createElement('slot');
|
|
363
|
+
slot.dataset.fileViewerLightDomSlot = 'true';
|
|
364
|
+
existingHostShadowRoot.replaceChildren(slot);
|
|
365
|
+
renderRoot = container;
|
|
366
|
+
}
|
|
367
|
+
renderRoot.replaceChildren();
|
|
368
|
+
const styleHandle = appendFileViewerStyle(renderRoot, WEB_VIEWER_STYLE, {
|
|
369
|
+
// Adopt only into a root owned by the viewer. Adopting into an ancestor
|
|
370
|
+
// ShadowRoot would leak toolbar selectors and apply :host rules to the
|
|
371
|
+
// customer's custom element.
|
|
372
|
+
adoptedStyleSheet: isFileViewerShadowRoot(renderRoot),
|
|
373
|
+
});
|
|
374
|
+
const shell = documentRef.createElement('div');
|
|
375
|
+
shell.className = 'file-viewer-web-shell';
|
|
376
|
+
addPart(shell, 'shell');
|
|
377
|
+
const toolbarEl = documentRef.createElement('div');
|
|
378
|
+
toolbarEl.className = 'file-viewer-web-toolbar';
|
|
379
|
+
addPart(toolbarEl, 'toolbar');
|
|
380
|
+
const contentEl = documentRef.createElement('div');
|
|
381
|
+
contentEl.className = 'file-viewer-web-content';
|
|
382
|
+
addPart(contentEl, 'content');
|
|
383
|
+
contentEl.dataset.viewerScrollContainer = 'true';
|
|
384
|
+
shell.append(toolbarEl, contentEl);
|
|
385
|
+
renderRoot.appendChild(shell);
|
|
386
|
+
let disposed = false;
|
|
387
|
+
let currentOptions = initialOptions;
|
|
388
|
+
const viewerColorSchemeQuery = (_d = (_c = (_b = documentRef.defaultView) === null || _b === void 0 ? void 0 : _b.matchMedia) === null || _c === void 0 ? void 0 : _c.call(_b, '(prefers-color-scheme: dark)')) !== null && _d !== void 0 ? _d : null;
|
|
389
|
+
const resolveCurrentViewerTheme = (theme) => {
|
|
390
|
+
return viewerColorSchemeQuery
|
|
391
|
+
? resolveFileViewerColorScheme(theme, viewerColorSchemeQuery.matches)
|
|
392
|
+
: resolveFileViewerColorScheme(theme);
|
|
393
|
+
};
|
|
394
|
+
let currentSource = hasSource(currentOptions)
|
|
395
|
+
? toViewerSourceInput(currentOptions)
|
|
396
|
+
: null;
|
|
397
|
+
let abortController = null;
|
|
398
|
+
const listeners = new Set();
|
|
399
|
+
const state = {
|
|
400
|
+
loading: false,
|
|
401
|
+
ready: false,
|
|
402
|
+
error: null,
|
|
403
|
+
lastEvent: null,
|
|
404
|
+
lifecycle: null,
|
|
405
|
+
availability: null,
|
|
406
|
+
search: null,
|
|
407
|
+
zoom: null,
|
|
408
|
+
location: null,
|
|
409
|
+
viewState: null,
|
|
410
|
+
};
|
|
411
|
+
const getCurrentExtension = () => {
|
|
412
|
+
var _a;
|
|
413
|
+
if ((_a = state.lifecycle) === null || _a === void 0 ? void 0 : _a.type) {
|
|
414
|
+
return state.lifecycle.type;
|
|
415
|
+
}
|
|
416
|
+
return currentSource ? getExtension(resolveViewerSourceFilename(currentSource)) : '';
|
|
417
|
+
};
|
|
418
|
+
const getToolbarZoomState = () => state.zoom || instance.getZoomState() || DEFAULT_TOOLBAR_ZOOM_STATE;
|
|
419
|
+
const getToolbarAvailability = () => applyFileViewerZoomAvailability(state.availability || instance.getCapabilities() || DEFAULT_TOOLBAR_AVAILABILITY, getToolbarZoomState());
|
|
420
|
+
const snapshotState = () => ({
|
|
421
|
+
...state,
|
|
422
|
+
availability: getToolbarAvailability(),
|
|
423
|
+
search: state.search
|
|
424
|
+
? { ...state.search, matches: [...state.search.matches] }
|
|
425
|
+
: null,
|
|
426
|
+
zoom: state.zoom ? { ...state.zoom } : null,
|
|
427
|
+
location: state.location ? { ...state.location } : null,
|
|
428
|
+
viewState: state.viewState
|
|
429
|
+
? {
|
|
430
|
+
...state.viewState,
|
|
431
|
+
zoom: state.viewState.zoom ? { ...state.viewState.zoom } : undefined,
|
|
432
|
+
scroll: state.viewState.scroll ? { ...state.viewState.scroll } : undefined,
|
|
433
|
+
navigation: state.viewState.navigation ? { ...state.viewState.navigation } : undefined,
|
|
434
|
+
extra: state.viewState.extra ? { ...state.viewState.extra } : undefined,
|
|
435
|
+
}
|
|
436
|
+
: null,
|
|
437
|
+
});
|
|
438
|
+
const syncShellTheme = () => {
|
|
439
|
+
var _a, _b, _c;
|
|
440
|
+
shell.dataset.viewerTheme = normalizeFileViewerTheme((_a = currentOptions.options) === null || _a === void 0 ? void 0 : _a.theme);
|
|
441
|
+
shell.dataset.viewerDensity = normalizeFileViewerUiDensity((_c = (_b = currentOptions.options) === null || _b === void 0 ? void 0 : _b.ui) === null || _c === void 0 ? void 0 : _c.density);
|
|
442
|
+
syncFileViewerRenderSurfaceBackground(shell, currentOptions.options);
|
|
443
|
+
};
|
|
444
|
+
let controller = null;
|
|
445
|
+
let searchDraft = '';
|
|
446
|
+
const isSearchToolbarVisible = (toolbar, options) => {
|
|
447
|
+
var _a;
|
|
448
|
+
if (toolbar.search === false || options.search === false || !state.ready || state.loading || state.error) {
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
if (contentEl.querySelector('.file-viewer-missing-renderer')) {
|
|
452
|
+
return false;
|
|
453
|
+
}
|
|
454
|
+
const renderer = instance.getRenderer(getCurrentExtension());
|
|
455
|
+
return !!((_a = renderer === null || renderer === void 0 ? void 0 : renderer.capabilities) === null || _a === void 0 ? void 0 : _a.search);
|
|
456
|
+
};
|
|
457
|
+
const renderToolbar = () => {
|
|
458
|
+
if (disposed) {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
syncShellTheme();
|
|
462
|
+
const options = currentOptions.options || {};
|
|
463
|
+
const toolbar = normalizeFileViewerToolbar(options);
|
|
464
|
+
const availability = getToolbarAvailability();
|
|
465
|
+
const showSearchToolbar = isSearchToolbarVisible(toolbar, options);
|
|
466
|
+
const visibleToolbar = resolveVisibleFileViewerToolbar(toolbar, availability, showSearchToolbar);
|
|
467
|
+
const showToolbar = hasVisibleFileViewerToolbarActions(visibleToolbar);
|
|
468
|
+
const toolbarPosition = resolveFileViewerToolbarPosition(options, getCurrentExtension());
|
|
469
|
+
const toolbarDisabled = state.loading || !!state.error;
|
|
470
|
+
const zoomState = getToolbarZoomState();
|
|
471
|
+
const t = createFileViewerTranslator(options);
|
|
472
|
+
toolbarEl.hidden = !showToolbar;
|
|
473
|
+
toolbarEl.dataset.toolbarPosition = toolbarPosition;
|
|
474
|
+
toolbarEl.replaceChildren();
|
|
475
|
+
if (!showToolbar) {
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
const appendSearchToolbar = () => {
|
|
479
|
+
var _a, _b;
|
|
480
|
+
if (!showSearchToolbar) {
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
const searchState = state.search;
|
|
484
|
+
const searchTotal = (_a = searchState === null || searchState === void 0 ? void 0 : searchState.total) !== null && _a !== void 0 ? _a : 0;
|
|
485
|
+
const currentIndex = searchTotal > 0 ? ((_b = searchState === null || searchState === void 0 ? void 0 : searchState.currentIndex) !== null && _b !== void 0 ? _b : -1) + 1 : 0;
|
|
486
|
+
const group = documentRef.createElement('form');
|
|
487
|
+
group.className = 'file-viewer-web-toolbar-group file-viewer-web-search';
|
|
488
|
+
addPart(group, 'toolbar-group');
|
|
489
|
+
group.setAttribute('role', 'search');
|
|
490
|
+
group.setAttribute('aria-label', t('toolbar.search'));
|
|
491
|
+
const input = documentRef.createElement('input');
|
|
492
|
+
input.type = 'search';
|
|
493
|
+
addPart(input, 'input');
|
|
494
|
+
input.value = searchDraft;
|
|
495
|
+
input.placeholder = t('toolbar.searchPlaceholder');
|
|
496
|
+
input.title = t('toolbar.searchPlaceholder');
|
|
497
|
+
input.setAttribute('aria-label', t('toolbar.searchPlaceholder'));
|
|
498
|
+
input.disabled = toolbarDisabled;
|
|
499
|
+
input.addEventListener('input', () => {
|
|
500
|
+
searchDraft = input.value;
|
|
501
|
+
});
|
|
502
|
+
const searchButton = documentRef.createElement('button');
|
|
503
|
+
searchButton.type = 'submit';
|
|
504
|
+
addPart(searchButton, 'button');
|
|
505
|
+
searchButton.textContent = t('toolbar.search');
|
|
506
|
+
searchButton.title = t('toolbar.search');
|
|
507
|
+
searchButton.setAttribute('aria-label', t('toolbar.search'));
|
|
508
|
+
searchButton.disabled = toolbarDisabled;
|
|
509
|
+
const previousButton = createButton(documentRef, '<', 'file-viewer-web-icon-button', () => controller === null || controller === void 0 ? void 0 : controller.previousSearchResult());
|
|
510
|
+
previousButton.title = t('toolbar.searchPrevious');
|
|
511
|
+
previousButton.setAttribute('aria-label', t('toolbar.searchPrevious'));
|
|
512
|
+
previousButton.disabled = toolbarDisabled || searchTotal < 1;
|
|
513
|
+
const nextButton = createButton(documentRef, '>', 'file-viewer-web-icon-button', () => controller === null || controller === void 0 ? void 0 : controller.nextSearchResult());
|
|
514
|
+
nextButton.title = t('toolbar.searchNext');
|
|
515
|
+
nextButton.setAttribute('aria-label', t('toolbar.searchNext'));
|
|
516
|
+
nextButton.disabled = toolbarDisabled || searchTotal < 1;
|
|
517
|
+
const clearButton = createButton(documentRef, 'x', 'file-viewer-web-icon-button', async () => {
|
|
518
|
+
searchDraft = '';
|
|
519
|
+
await (controller === null || controller === void 0 ? void 0 : controller.clearDocumentSearch());
|
|
520
|
+
});
|
|
521
|
+
clearButton.title = t('toolbar.searchClear');
|
|
522
|
+
clearButton.setAttribute('aria-label', t('toolbar.searchClear'));
|
|
523
|
+
clearButton.disabled = toolbarDisabled || (!searchDraft && !(searchState === null || searchState === void 0 ? void 0 : searchState.query));
|
|
524
|
+
const count = documentRef.createElement('span');
|
|
525
|
+
count.className = 'file-viewer-web-search-count';
|
|
526
|
+
addPart(count, 'toolbar-status');
|
|
527
|
+
count.textContent = `${currentIndex}/${searchTotal}`;
|
|
528
|
+
count.setAttribute('aria-live', 'polite');
|
|
529
|
+
group.addEventListener('submit', event => {
|
|
530
|
+
event.preventDefault();
|
|
531
|
+
searchDraft = input.value;
|
|
532
|
+
const query = searchDraft.trim();
|
|
533
|
+
void (query ? controller === null || controller === void 0 ? void 0 : controller.searchDocument(query) : controller === null || controller === void 0 ? void 0 : controller.clearDocumentSearch());
|
|
534
|
+
});
|
|
535
|
+
group.append(input, searchButton, previousButton, nextButton, clearButton, count);
|
|
536
|
+
toolbarEl.appendChild(group);
|
|
537
|
+
};
|
|
538
|
+
const appendZoomToolbar = () => {
|
|
539
|
+
if (!visibleToolbar.zoom) {
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
const group = documentRef.createElement('div');
|
|
543
|
+
group.className = 'file-viewer-web-toolbar-group';
|
|
544
|
+
addPart(group, 'toolbar-group');
|
|
545
|
+
group.setAttribute('aria-label', t('toolbar.zoomGroup'));
|
|
546
|
+
if (availability.zoomOut) {
|
|
547
|
+
const button = createButton(documentRef, '-', 'file-viewer-web-icon-button', () => controller === null || controller === void 0 ? void 0 : controller.zoomOut());
|
|
548
|
+
button.title = t('toolbar.zoomOut');
|
|
549
|
+
button.setAttribute('aria-label', t('toolbar.zoomOut'));
|
|
550
|
+
button.disabled = isFileViewerZoomButtonDisabled({
|
|
551
|
+
action: 'canZoomOut',
|
|
552
|
+
availability,
|
|
553
|
+
toolbarDisabled,
|
|
554
|
+
zoomState,
|
|
555
|
+
});
|
|
556
|
+
group.appendChild(button);
|
|
557
|
+
}
|
|
558
|
+
if (availability.zoomReset) {
|
|
559
|
+
const meter = createButton(documentRef, zoomState.label, 'file-viewer-web-zoom-meter', () => controller === null || controller === void 0 ? void 0 : controller.resetZoom());
|
|
560
|
+
meter.title = t('toolbar.zoomReset');
|
|
561
|
+
meter.disabled = isFileViewerZoomButtonDisabled({
|
|
562
|
+
action: 'canReset',
|
|
563
|
+
availability,
|
|
564
|
+
toolbarDisabled,
|
|
565
|
+
zoomState,
|
|
566
|
+
});
|
|
567
|
+
group.appendChild(meter);
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
group.appendChild(createReadonlyMeter(documentRef, zoomState.label, 'file-viewer-web-zoom-meter'));
|
|
571
|
+
}
|
|
572
|
+
if (availability.zoomReset) {
|
|
573
|
+
// Placed before the zoom-in button (not after) so that toggling this
|
|
574
|
+
// button's visibility never shifts the zoom-in button's position: the
|
|
575
|
+
// toolbar group is right-aligned, and both icon buttons share the same
|
|
576
|
+
// width, so inserting "1:1" after "+" would make it land exactly on
|
|
577
|
+
// top of the previous "+" position, turning a repeated zoom-in click
|
|
578
|
+
// into an accidental reset (see GitHub issue #88).
|
|
579
|
+
const button = createButton(documentRef, '1:1', 'file-viewer-web-icon-button', () => controller === null || controller === void 0 ? void 0 : controller.resetZoom());
|
|
580
|
+
button.title = t('toolbar.zoomReset');
|
|
581
|
+
button.setAttribute('aria-label', t('toolbar.zoomReset'));
|
|
582
|
+
button.disabled = isFileViewerZoomButtonDisabled({
|
|
583
|
+
action: 'canReset',
|
|
584
|
+
availability,
|
|
585
|
+
toolbarDisabled,
|
|
586
|
+
zoomState,
|
|
587
|
+
});
|
|
588
|
+
group.appendChild(button);
|
|
589
|
+
}
|
|
590
|
+
if (availability.zoomIn) {
|
|
591
|
+
const button = createButton(documentRef, '+', 'file-viewer-web-icon-button', () => controller === null || controller === void 0 ? void 0 : controller.zoomIn());
|
|
592
|
+
button.title = t('toolbar.zoomIn');
|
|
593
|
+
button.setAttribute('aria-label', t('toolbar.zoomIn'));
|
|
594
|
+
button.disabled = isFileViewerZoomButtonDisabled({
|
|
595
|
+
action: 'canZoomIn',
|
|
596
|
+
availability,
|
|
597
|
+
toolbarDisabled,
|
|
598
|
+
zoomState,
|
|
599
|
+
});
|
|
600
|
+
group.appendChild(button);
|
|
601
|
+
}
|
|
602
|
+
if (group.childElementCount) {
|
|
603
|
+
toolbarEl.appendChild(group);
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
const appendToolbarButton = (visible, label, title, onClick) => {
|
|
607
|
+
if (!visible) {
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
const button = createButton(documentRef, label, '', onClick);
|
|
611
|
+
button.title = title;
|
|
612
|
+
button.disabled = toolbarDisabled;
|
|
613
|
+
toolbarEl.appendChild(button);
|
|
614
|
+
};
|
|
615
|
+
const appendThemeToolbar = () => {
|
|
616
|
+
if (!visibleToolbar.theme) {
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
const currentTheme = resolveCurrentViewerTheme(options.theme);
|
|
620
|
+
const title = currentTheme === 'dark'
|
|
621
|
+
? t('toolbar.themeToLight')
|
|
622
|
+
: t('toolbar.themeToDark');
|
|
623
|
+
const button = createButton(documentRef, '', 'file-viewer-web-icon-button file-viewer-web-theme-button', async () => {
|
|
624
|
+
var _a;
|
|
625
|
+
const previousViewState = instance.getViewState();
|
|
626
|
+
const nextTheme = toggleFileViewerColorScheme((_a = currentOptions.options) === null || _a === void 0 ? void 0 : _a.theme, viewerColorSchemeQuery === null || viewerColorSchemeQuery === void 0 ? void 0 : viewerColorSchemeQuery.matches);
|
|
627
|
+
currentOptions = {
|
|
628
|
+
...currentOptions,
|
|
629
|
+
options: {
|
|
630
|
+
...(currentOptions.options || {}),
|
|
631
|
+
theme: nextTheme,
|
|
632
|
+
},
|
|
633
|
+
};
|
|
634
|
+
instance.updateOptions({ theme: nextTheme });
|
|
635
|
+
applyViewerEvent({ type: 'theme-change', payload: nextTheme });
|
|
636
|
+
if (currentSource) {
|
|
637
|
+
const session = await loadSource(currentSource).catch(() => null);
|
|
638
|
+
if (session && previousViewState) {
|
|
639
|
+
await instance.applyViewState(previousViewState, {
|
|
640
|
+
action: 'restore',
|
|
641
|
+
source: 'api',
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
});
|
|
646
|
+
addPart(button, 'theme-toggle');
|
|
647
|
+
setThemeButtonIcon(button, currentTheme);
|
|
648
|
+
button.title = title;
|
|
649
|
+
button.setAttribute('aria-label', title);
|
|
650
|
+
button.setAttribute('aria-pressed', String(currentTheme === 'dark'));
|
|
651
|
+
button.disabled = toolbarDisabled;
|
|
652
|
+
toolbarEl.appendChild(button);
|
|
653
|
+
};
|
|
654
|
+
resolveFileViewerToolbarOrder(toolbar).forEach(item => {
|
|
655
|
+
if (item === 'search') {
|
|
656
|
+
appendSearchToolbar();
|
|
657
|
+
}
|
|
658
|
+
else if (item === 'zoom') {
|
|
659
|
+
appendZoomToolbar();
|
|
660
|
+
}
|
|
661
|
+
else if (item === 'download') {
|
|
662
|
+
appendToolbarButton(visibleToolbar.download, t('toolbar.download'), t('toolbar.downloadTitle'), () => controller === null || controller === void 0 ? void 0 : controller.downloadOriginalFile());
|
|
663
|
+
}
|
|
664
|
+
else if (item === 'print') {
|
|
665
|
+
if (!visibleToolbar.print) {
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
const menu = documentRef.createElement('div');
|
|
669
|
+
menu.className = 'file-viewer-web-print-menu';
|
|
670
|
+
addPart(menu, 'toolbar-group');
|
|
671
|
+
const trigger = createButton(documentRef, t('toolbar.print'), '', () => {
|
|
672
|
+
menu.dataset.open = menu.dataset.open === 'true' ? 'false' : 'true';
|
|
673
|
+
});
|
|
674
|
+
trigger.title = t('toolbar.printTitle');
|
|
675
|
+
trigger.setAttribute('aria-label', t('toolbar.printTitle'));
|
|
676
|
+
trigger.setAttribute('aria-haspopup', 'menu');
|
|
677
|
+
trigger.disabled = toolbarDisabled;
|
|
678
|
+
const panel = documentRef.createElement('div');
|
|
679
|
+
panel.className = 'file-viewer-web-print-menu-panel';
|
|
680
|
+
panel.setAttribute('role', 'menu');
|
|
681
|
+
const closeMenu = () => {
|
|
682
|
+
menu.dataset.open = 'false';
|
|
683
|
+
};
|
|
684
|
+
const directButton = createButton(documentRef, t('toolbar.printDirect'), '', async () => {
|
|
685
|
+
closeMenu();
|
|
686
|
+
await (controller === null || controller === void 0 ? void 0 : controller.printRenderedHtml());
|
|
687
|
+
});
|
|
688
|
+
directButton.title = t('toolbar.printTitle');
|
|
689
|
+
directButton.setAttribute('role', 'menuitem');
|
|
690
|
+
directButton.disabled = toolbarDisabled;
|
|
691
|
+
const maskButton = createButton(documentRef, t('toolbar.printMask'), '', async () => {
|
|
692
|
+
closeMenu();
|
|
693
|
+
await (controller === null || controller === void 0 ? void 0 : controller.printWithMask());
|
|
694
|
+
});
|
|
695
|
+
maskButton.title = t('toolbar.printMaskTitle');
|
|
696
|
+
maskButton.setAttribute('role', 'menuitem');
|
|
697
|
+
maskButton.disabled = toolbarDisabled;
|
|
698
|
+
panel.append(directButton, maskButton);
|
|
699
|
+
menu.append(trigger, panel);
|
|
700
|
+
menu.addEventListener('focusout', event => {
|
|
701
|
+
const next = event.relatedTarget;
|
|
702
|
+
if (!next || !menu.contains(next)) {
|
|
703
|
+
closeMenu();
|
|
704
|
+
}
|
|
705
|
+
});
|
|
706
|
+
toolbarEl.appendChild(menu);
|
|
707
|
+
}
|
|
708
|
+
else if (item === 'exportHtml') {
|
|
709
|
+
appendToolbarButton(visibleToolbar.exportHtml, t('toolbar.exportHtml'), t('toolbar.exportHtmlTitle'), () => controller === null || controller === void 0 ? void 0 : controller.exportRenderedHtml());
|
|
710
|
+
}
|
|
711
|
+
else if (item === 'theme') {
|
|
712
|
+
appendThemeToolbar();
|
|
713
|
+
}
|
|
714
|
+
});
|
|
715
|
+
};
|
|
716
|
+
let refreshSystemThemeDocument = null;
|
|
717
|
+
const handleViewerColorSchemeChange = () => {
|
|
718
|
+
var _a;
|
|
719
|
+
if (normalizeFileViewerTheme((_a = currentOptions.options) === null || _a === void 0 ? void 0 : _a.theme) === 'system') {
|
|
720
|
+
renderToolbar();
|
|
721
|
+
void (refreshSystemThemeDocument === null || refreshSystemThemeDocument === void 0 ? void 0 : refreshSystemThemeDocument());
|
|
722
|
+
}
|
|
723
|
+
};
|
|
724
|
+
const notifyState = (event) => {
|
|
725
|
+
var _a;
|
|
726
|
+
const snapshot = snapshotState();
|
|
727
|
+
renderToolbar();
|
|
728
|
+
(_a = currentOptions.onStateChange) === null || _a === void 0 ? void 0 : _a.call(currentOptions, snapshot, event);
|
|
729
|
+
listeners.forEach(listener => listener(snapshot, event));
|
|
730
|
+
};
|
|
731
|
+
const applyViewerEvent = (event) => {
|
|
732
|
+
var _a;
|
|
733
|
+
state.lastEvent = event;
|
|
734
|
+
if (event.type === 'load-start') {
|
|
735
|
+
state.loading = true;
|
|
736
|
+
state.ready = false;
|
|
737
|
+
state.error = null;
|
|
738
|
+
state.lifecycle = event.payload;
|
|
739
|
+
state.search = null;
|
|
740
|
+
searchDraft = '';
|
|
741
|
+
}
|
|
742
|
+
else if (event.type === 'load-complete') {
|
|
743
|
+
state.loading = false;
|
|
744
|
+
state.ready = true;
|
|
745
|
+
state.lifecycle = event.payload;
|
|
746
|
+
}
|
|
747
|
+
else if (event.type === 'unload-start') {
|
|
748
|
+
state.loading = true;
|
|
749
|
+
state.ready = false;
|
|
750
|
+
state.lifecycle = event.payload;
|
|
751
|
+
}
|
|
752
|
+
else if (event.type === 'unload-complete') {
|
|
753
|
+
state.loading = false;
|
|
754
|
+
state.ready = false;
|
|
755
|
+
state.lifecycle = event.payload;
|
|
756
|
+
}
|
|
757
|
+
else if (event.type === 'operation-availability-change') {
|
|
758
|
+
state.availability = event.payload;
|
|
759
|
+
}
|
|
760
|
+
else if (event.type === 'search-change') {
|
|
761
|
+
state.search = event.payload;
|
|
762
|
+
searchDraft = event.payload.query;
|
|
763
|
+
}
|
|
764
|
+
else if (event.type === 'location-change') {
|
|
765
|
+
state.location = event.payload;
|
|
766
|
+
}
|
|
767
|
+
else if (event.type === 'zoom-change') {
|
|
768
|
+
state.zoom = event.payload;
|
|
769
|
+
}
|
|
770
|
+
else if (event.type === 'view-state-change') {
|
|
771
|
+
state.viewState = event.payload.state;
|
|
772
|
+
}
|
|
773
|
+
(_a = currentOptions.onEvent) === null || _a === void 0 ? void 0 : _a.call(currentOptions, event);
|
|
774
|
+
notifyState(event);
|
|
775
|
+
};
|
|
776
|
+
const instance = createViewer(contentEl, {
|
|
777
|
+
registry: coreOptions.registry,
|
|
778
|
+
options: currentOptions.options,
|
|
779
|
+
onEvent: applyViewerEvent,
|
|
780
|
+
});
|
|
781
|
+
(_e = viewerColorSchemeQuery === null || viewerColorSchemeQuery === void 0 ? void 0 : viewerColorSchemeQuery.addEventListener) === null || _e === void 0 ? void 0 : _e.call(viewerColorSchemeQuery, 'change', handleViewerColorSchemeChange);
|
|
782
|
+
renderToolbar();
|
|
783
|
+
const cancel = () => {
|
|
784
|
+
abortController === null || abortController === void 0 ? void 0 : abortController.abort();
|
|
785
|
+
abortController = null;
|
|
786
|
+
};
|
|
787
|
+
const loadSource = async (nextSource) => {
|
|
788
|
+
var _a;
|
|
789
|
+
cancel();
|
|
790
|
+
currentSource = nextSource;
|
|
791
|
+
abortController = typeof AbortController !== 'undefined' ? new AbortController() : null;
|
|
792
|
+
const controller = abortController;
|
|
793
|
+
try {
|
|
794
|
+
state.loading = true;
|
|
795
|
+
state.error = null;
|
|
796
|
+
notifyState();
|
|
797
|
+
const resolvedSource = await resolveViewerLoadSource(nextSource, {
|
|
798
|
+
fetchFile: coreOptions.fetchFile,
|
|
799
|
+
signal: controller === null || controller === void 0 ? void 0 : controller.signal,
|
|
800
|
+
});
|
|
801
|
+
if (disposed || (controller === null || controller === void 0 ? void 0 : controller.signal.aborted) || abortController !== controller) {
|
|
802
|
+
return null;
|
|
803
|
+
}
|
|
804
|
+
return await instance.load(resolvedSource);
|
|
805
|
+
}
|
|
806
|
+
catch (error) {
|
|
807
|
+
if (isAbortError(error) && (controller === null || controller === void 0 ? void 0 : controller.signal.aborted)) {
|
|
808
|
+
return null;
|
|
809
|
+
}
|
|
810
|
+
state.loading = false;
|
|
811
|
+
state.ready = false;
|
|
812
|
+
state.error = error;
|
|
813
|
+
notifyState();
|
|
814
|
+
(_a = coreOptions.onError) === null || _a === void 0 ? void 0 : _a.call(coreOptions, error, nextSource);
|
|
815
|
+
throw error;
|
|
816
|
+
}
|
|
817
|
+
finally {
|
|
818
|
+
if (abortController === controller) {
|
|
819
|
+
abortController = null;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
};
|
|
823
|
+
refreshSystemThemeDocument = async () => {
|
|
824
|
+
if (!currentSource) {
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
const previousViewState = instance.getViewState();
|
|
828
|
+
const session = await loadSource(currentSource).catch(() => null);
|
|
829
|
+
if (session && previousViewState) {
|
|
830
|
+
await instance.applyViewState(previousViewState, {
|
|
831
|
+
action: 'restore',
|
|
832
|
+
source: 'api',
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
if (currentSource) {
|
|
837
|
+
void loadSource(currentSource);
|
|
838
|
+
}
|
|
839
|
+
controller = {
|
|
840
|
+
container,
|
|
841
|
+
async load(nextOptions) {
|
|
842
|
+
if (disposed)
|
|
843
|
+
return;
|
|
844
|
+
currentOptions = nextOptions;
|
|
845
|
+
instance.updateOptions(currentOptions.options || {});
|
|
846
|
+
renderToolbar();
|
|
847
|
+
if (hasSource(currentOptions)) {
|
|
848
|
+
await loadSource(toViewerSourceInput(currentOptions));
|
|
849
|
+
}
|
|
850
|
+
},
|
|
851
|
+
async update(nextOptions = {}) {
|
|
852
|
+
var _a;
|
|
853
|
+
if (disposed)
|
|
854
|
+
return;
|
|
855
|
+
currentOptions = {
|
|
856
|
+
...currentOptions,
|
|
857
|
+
...nextOptions,
|
|
858
|
+
options: (_a = nextOptions.options) !== null && _a !== void 0 ? _a : currentOptions.options,
|
|
859
|
+
};
|
|
860
|
+
instance.updateOptions(currentOptions.options || {});
|
|
861
|
+
renderToolbar();
|
|
862
|
+
if (hasSource(currentOptions)) {
|
|
863
|
+
await loadSource(toViewerSourceInput(currentOptions));
|
|
864
|
+
}
|
|
865
|
+
else {
|
|
866
|
+
currentSource = null;
|
|
867
|
+
await instance.load({ filename: DEFAULT_FILE_VIEWER_SOURCE_FILENAME });
|
|
868
|
+
}
|
|
869
|
+
},
|
|
870
|
+
async reload() {
|
|
871
|
+
if (disposed)
|
|
872
|
+
return;
|
|
873
|
+
if (currentSource) {
|
|
874
|
+
await loadSource(currentSource);
|
|
875
|
+
}
|
|
876
|
+
},
|
|
877
|
+
destroy() {
|
|
878
|
+
var _a;
|
|
879
|
+
if (disposed)
|
|
880
|
+
return;
|
|
881
|
+
disposed = true;
|
|
882
|
+
cancel();
|
|
883
|
+
(_a = viewerColorSchemeQuery === null || viewerColorSchemeQuery === void 0 ? void 0 : viewerColorSchemeQuery.removeEventListener) === null || _a === void 0 ? void 0 : _a.call(viewerColorSchemeQuery, 'change', handleViewerColorSchemeChange);
|
|
884
|
+
void instance.destroy('component-unmount');
|
|
885
|
+
styleHandle.remove();
|
|
886
|
+
renderRoot.replaceChildren();
|
|
887
|
+
mountBoundary === null || mountBoundary === void 0 ? void 0 : mountBoundary.remove();
|
|
888
|
+
},
|
|
889
|
+
getApi() {
|
|
890
|
+
return instance;
|
|
891
|
+
},
|
|
892
|
+
downloadOriginalFile() {
|
|
893
|
+
return callApi(instance, api => api.download(), undefined);
|
|
894
|
+
},
|
|
895
|
+
printRenderedHtml(options) {
|
|
896
|
+
return callApi(instance, api => api.print(options), undefined);
|
|
897
|
+
},
|
|
898
|
+
printWithMask(options) {
|
|
899
|
+
return callApi(instance, api => api.printWithMask(options), undefined);
|
|
900
|
+
},
|
|
901
|
+
exportRenderedHtml() {
|
|
902
|
+
return callApi(instance, api => api.exportHtml({ download: true }).then(() => undefined), undefined);
|
|
903
|
+
},
|
|
904
|
+
zoomIn() {
|
|
905
|
+
return callApi(instance, api => api.zoomIn(), null);
|
|
906
|
+
},
|
|
907
|
+
zoomOut() {
|
|
908
|
+
return callApi(instance, api => api.zoomOut(), null);
|
|
909
|
+
},
|
|
910
|
+
resetZoom() {
|
|
911
|
+
return callApi(instance, api => api.resetZoom(), null);
|
|
912
|
+
},
|
|
913
|
+
fitToView(fit) {
|
|
914
|
+
return callApi(instance, api => api.fitToView(fit), null);
|
|
915
|
+
},
|
|
916
|
+
getViewState() {
|
|
917
|
+
return instance.getViewState();
|
|
918
|
+
},
|
|
919
|
+
applyViewState(state, options) {
|
|
920
|
+
return callApi(instance, api => api.applyViewState(state, options), null);
|
|
921
|
+
},
|
|
922
|
+
searchDocument(query) {
|
|
923
|
+
return callApi(instance, api => api.search(query), null);
|
|
924
|
+
},
|
|
925
|
+
clearDocumentSearch() {
|
|
926
|
+
return callApi(instance, api => api.clearSearch(), null);
|
|
927
|
+
},
|
|
928
|
+
nextSearchResult() {
|
|
929
|
+
return callApi(instance, api => api.nextSearchResult(), null);
|
|
930
|
+
},
|
|
931
|
+
previousSearchResult() {
|
|
932
|
+
return callApi(instance, api => api.previousSearchResult(), null);
|
|
933
|
+
},
|
|
934
|
+
collectDocumentAnchors() {
|
|
935
|
+
return callApi(instance, api => api.collectDocumentAnchors(), []);
|
|
936
|
+
},
|
|
937
|
+
scrollToAnchor(anchor) {
|
|
938
|
+
return callApi(instance, api => api.scrollToDocumentAnchor(anchor), false);
|
|
939
|
+
},
|
|
940
|
+
scrollToLine(line) {
|
|
941
|
+
return callApi(instance, api => api.scrollToLine(line), false);
|
|
942
|
+
},
|
|
943
|
+
getDocumentTextChunks() {
|
|
944
|
+
return instance.getDocumentTextChunks();
|
|
945
|
+
},
|
|
946
|
+
getOperationAvailability() {
|
|
947
|
+
return getToolbarAvailability();
|
|
948
|
+
},
|
|
949
|
+
getZoomState() {
|
|
950
|
+
return instance.getZoomState();
|
|
951
|
+
},
|
|
952
|
+
getSearchState() {
|
|
953
|
+
return instance.getSearchState();
|
|
954
|
+
},
|
|
955
|
+
getState() {
|
|
956
|
+
return snapshotState();
|
|
957
|
+
},
|
|
958
|
+
subscribe(listener) {
|
|
959
|
+
listeners.add(listener);
|
|
960
|
+
listener(snapshotState());
|
|
961
|
+
return () => {
|
|
962
|
+
listeners.delete(listener);
|
|
963
|
+
};
|
|
964
|
+
},
|
|
965
|
+
};
|
|
966
|
+
return controller;
|
|
967
|
+
};
|