jupyterlab_advanced_image_viewer_extension 1.1.4 → 1.1.6
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 +1 -1
- package/lib/index.js +48 -20
- package/package.json +2 -1
- package/src/index.ts +55 -20
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ The viewer toolbar adds zoom in / out / fit controls and a `help` link that list
|
|
|
23
23
|
- **Arrow-key navigation** - Left and Right open the previous and next image in the same folder, in the order the file browser lists them, advancing within one viewer instead of opening new tabs
|
|
24
24
|
- **Copy to clipboard** - right-click a raster image (PNG/JPG/…) and choose "Copy to Clipboard" to copy it as PNG to the system clipboard
|
|
25
25
|
- **Refresh** - a toolbar refresh button reloads the image from disk, the same control the HTML viewer provides
|
|
26
|
-
- **WebP support** - `.webp` files open in the image viewer with every feature above; stock JupyterLab
|
|
26
|
+
- **WebP and AVIF support** - `.webp` and `.avif` files open in the image viewer with every feature above; stock JupyterLab does not open them and shows a File Load Error
|
|
27
27
|
|
|
28
28
|
## Requirements
|
|
29
29
|
|
package/lib/index.js
CHANGED
|
@@ -3,8 +3,10 @@ import { PathExt } from '@jupyterlab/coreutils';
|
|
|
3
3
|
import { IDefaultFileBrowser } from '@jupyterlab/filebrowser';
|
|
4
4
|
import { IImageTracker } from '@jupyterlab/imageviewer';
|
|
5
5
|
import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
6
|
-
import {
|
|
6
|
+
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
|
|
7
|
+
import { imageIcon, refreshIcon } from '@jupyterlab/ui-components';
|
|
7
8
|
import { Widget } from '@lumino/widgets';
|
|
9
|
+
// eslint-disable-next-line jupyter/prefer-lazy-imports -- activation attaches the controller to restored image tabs at once
|
|
8
10
|
import { ViewerController } from './controller';
|
|
9
11
|
const PLUGIN_ID = 'jupyterlab_advanced_image_viewer_extension:plugin';
|
|
10
12
|
const CommandIDs = {
|
|
@@ -22,11 +24,20 @@ const IMAGE_EXTS = new Set([
|
|
|
22
24
|
'.gif',
|
|
23
25
|
'.bmp',
|
|
24
26
|
'.svg',
|
|
25
|
-
'.webp'
|
|
27
|
+
'.webp',
|
|
28
|
+
'.avif'
|
|
26
29
|
]);
|
|
27
30
|
// Raster formats that can be drawn to a canvas and copied as PNG. SVG is
|
|
28
31
|
// excluded - the drawio/SVG extension already adds its own "Copy as PNG".
|
|
29
|
-
const RASTER_EXTS = new Set([
|
|
32
|
+
const RASTER_EXTS = new Set([
|
|
33
|
+
'.png',
|
|
34
|
+
'.jpg',
|
|
35
|
+
'.jpeg',
|
|
36
|
+
'.gif',
|
|
37
|
+
'.bmp',
|
|
38
|
+
'.webp',
|
|
39
|
+
'.avif'
|
|
40
|
+
]);
|
|
30
41
|
const defaults = {
|
|
31
42
|
navEnabled: true,
|
|
32
43
|
zoomStep: 0.1
|
|
@@ -36,9 +47,10 @@ const plugin = {
|
|
|
36
47
|
description: 'Advanced image viewer: cursor-anchored wheel zoom, drag-to-pan, fit-to-screen reset, and arrow-key folder navigation.',
|
|
37
48
|
autoStart: true,
|
|
38
49
|
requires: [IImageTracker],
|
|
39
|
-
optional: [ISettingRegistry, IDefaultFileBrowser],
|
|
40
|
-
activate: (app, tracker, settingRegistry, fileBrowser) => {
|
|
50
|
+
optional: [ISettingRegistry, IDefaultFileBrowser, ITranslator],
|
|
51
|
+
activate: (app, tracker, settingRegistry, fileBrowser, translator) => {
|
|
41
52
|
console.log('JupyterLab extension jupyterlab_advanced_image_viewer_extension is activated!');
|
|
53
|
+
const trans = (translator !== null && translator !== void 0 ? translator : nullTranslator).load('jupyterlab_advanced_image_viewer_extension');
|
|
42
54
|
const controllers = new WeakMap();
|
|
43
55
|
const state = { ...defaults };
|
|
44
56
|
let keyBindings = [];
|
|
@@ -71,9 +83,9 @@ const plugin = {
|
|
|
71
83
|
'</ul>'
|
|
72
84
|
].join('');
|
|
73
85
|
void showDialog({
|
|
74
|
-
title: 'Advanced Image Viewer',
|
|
86
|
+
title: trans.__('Advanced Image Viewer'),
|
|
75
87
|
body,
|
|
76
|
-
buttons: [Dialog.okButton({ label: 'Close' })]
|
|
88
|
+
buttons: [Dialog.okButton({ label: trans.__('Close') })]
|
|
77
89
|
});
|
|
78
90
|
};
|
|
79
91
|
const attach = (widget) => {
|
|
@@ -97,7 +109,7 @@ const plugin = {
|
|
|
97
109
|
// edited, so there is nothing here to discard.
|
|
98
110
|
widget.toolbar.addItem('advanced-refresh', new ToolbarButton({
|
|
99
111
|
icon: refreshIcon,
|
|
100
|
-
tooltip: 'Reload image from disk',
|
|
112
|
+
tooltip: trans.__('Reload image from disk'),
|
|
101
113
|
noFocusOnClick: true,
|
|
102
114
|
onClick: async () => {
|
|
103
115
|
await widget.context.revert();
|
|
@@ -106,28 +118,28 @@ const plugin = {
|
|
|
106
118
|
}));
|
|
107
119
|
widget.toolbar.addItem('advanced-zoom-out', new ToolbarButton({
|
|
108
120
|
label: '-',
|
|
109
|
-
tooltip: 'Zoom out',
|
|
121
|
+
tooltip: trans.__('Zoom out'),
|
|
110
122
|
noFocusOnClick: true,
|
|
111
123
|
onClick: () => app.commands.execute(CommandIDs.zoomOut)
|
|
112
124
|
}));
|
|
113
125
|
widget.toolbar.addItem('advanced-zoom-in', new ToolbarButton({
|
|
114
126
|
label: '+',
|
|
115
|
-
tooltip: 'Zoom in',
|
|
127
|
+
tooltip: trans.__('Zoom in'),
|
|
116
128
|
noFocusOnClick: true,
|
|
117
129
|
onClick: () => app.commands.execute(CommandIDs.zoomIn)
|
|
118
130
|
}));
|
|
119
131
|
widget.toolbar.addItem('advanced-reset-fit', new ToolbarButton({
|
|
120
|
-
label: 'Fit',
|
|
121
|
-
tooltip: 'Reset to fit',
|
|
132
|
+
label: trans.__('Fit'),
|
|
133
|
+
tooltip: trans.__('Reset to fit'),
|
|
122
134
|
noFocusOnClick: true,
|
|
123
135
|
onClick: () => app.commands.execute(CommandIDs.resetFit)
|
|
124
136
|
}));
|
|
125
137
|
widget.toolbar.addItem('advanced-spacer', Toolbar.createSpacerItem());
|
|
126
138
|
const helpLink = new Widget({ node: document.createElement('a') });
|
|
127
139
|
const helpAnchor = helpLink.node;
|
|
128
|
-
helpAnchor.textContent = 'help';
|
|
140
|
+
helpAnchor.textContent = trans.__('help');
|
|
129
141
|
helpAnchor.href = '#';
|
|
130
|
-
helpAnchor.title = 'Keybindings and help';
|
|
142
|
+
helpAnchor.title = trans.__('Keybindings and help');
|
|
131
143
|
helpAnchor.className = 'jp-AdvancedImageViewer-help-link';
|
|
132
144
|
helpAnchor.addEventListener('click', event => {
|
|
133
145
|
event.preventDefault();
|
|
@@ -148,18 +160,31 @@ const plugin = {
|
|
|
148
160
|
if (webp) {
|
|
149
161
|
app.docRegistry.addFileType(webp, ['Image']);
|
|
150
162
|
}
|
|
163
|
+
// JupyterLab registers no 'avif' file type at all, so add one with the
|
|
164
|
+
// same shape as its other image types, bound to the same factory.
|
|
165
|
+
app.docRegistry.addFileType({
|
|
166
|
+
name: 'avif',
|
|
167
|
+
displayName: 'Image',
|
|
168
|
+
mimeTypes: ['image/avif'],
|
|
169
|
+
extensions: ['.avif'],
|
|
170
|
+
icon: imageIcon,
|
|
171
|
+
fileFormat: 'base64'
|
|
172
|
+
}, ['Image']);
|
|
151
173
|
app.commands.addCommand(CommandIDs.zoomIn, {
|
|
152
|
-
label: 'Zoom In (Advanced Image Viewer)',
|
|
174
|
+
label: trans.__('Zoom In (Advanced Image Viewer)'),
|
|
175
|
+
describedBy: { args: { type: 'object', properties: {} } },
|
|
153
176
|
isEnabled: () => currentController() !== null,
|
|
154
177
|
execute: () => { var _a; return (_a = currentController()) === null || _a === void 0 ? void 0 : _a.zoomIn(); }
|
|
155
178
|
});
|
|
156
179
|
app.commands.addCommand(CommandIDs.zoomOut, {
|
|
157
|
-
label: 'Zoom Out (Advanced Image Viewer)',
|
|
180
|
+
label: trans.__('Zoom Out (Advanced Image Viewer)'),
|
|
181
|
+
describedBy: { args: { type: 'object', properties: {} } },
|
|
158
182
|
isEnabled: () => currentController() !== null,
|
|
159
183
|
execute: () => { var _a; return (_a = currentController()) === null || _a === void 0 ? void 0 : _a.zoomOut(); }
|
|
160
184
|
});
|
|
161
185
|
app.commands.addCommand(CommandIDs.resetFit, {
|
|
162
|
-
label: 'Reset to Fit (Advanced Image Viewer)',
|
|
186
|
+
label: trans.__('Reset to Fit (Advanced Image Viewer)'),
|
|
187
|
+
describedBy: { args: { type: 'object', properties: {} } },
|
|
163
188
|
isEnabled: () => currentController() !== null,
|
|
164
189
|
execute: () => { var _a; return (_a = currentController()) === null || _a === void 0 ? void 0 : _a.reset(); }
|
|
165
190
|
});
|
|
@@ -175,7 +200,8 @@ const plugin = {
|
|
|
175
200
|
return (_a = tracker.find(widget => widget.content.node === node)) !== null && _a !== void 0 ? _a : null;
|
|
176
201
|
};
|
|
177
202
|
app.commands.addCommand(CommandIDs.copyClipboard, {
|
|
178
|
-
label: 'Copy to Clipboard',
|
|
203
|
+
label: trans.__('Copy to Clipboard'),
|
|
204
|
+
describedBy: { args: { type: 'object', properties: {} } },
|
|
179
205
|
// Raster only - SVG already has "Copy as PNG" from the drawio extension.
|
|
180
206
|
isVisible: () => {
|
|
181
207
|
const widget = contextImageWidget();
|
|
@@ -281,12 +307,14 @@ const plugin = {
|
|
|
281
307
|
}
|
|
282
308
|
};
|
|
283
309
|
app.commands.addCommand(CommandIDs.previous, {
|
|
284
|
-
label: 'Previous Image In Folder',
|
|
310
|
+
label: trans.__('Previous Image In Folder'),
|
|
311
|
+
describedBy: { args: { type: 'object', properties: {} } },
|
|
285
312
|
isEnabled: () => state.navEnabled && tracker.currentWidget !== null,
|
|
286
313
|
execute: () => navigate(-1)
|
|
287
314
|
});
|
|
288
315
|
app.commands.addCommand(CommandIDs.next, {
|
|
289
|
-
label: 'Next Image In Folder',
|
|
316
|
+
label: trans.__('Next Image In Folder'),
|
|
317
|
+
describedBy: { args: { type: 'object', properties: {} } },
|
|
290
318
|
isEnabled: () => state.navEnabled && tracker.currentWidget !== null,
|
|
291
319
|
execute: () => navigate(1)
|
|
292
320
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jupyterlab_advanced_image_viewer_extension",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.6",
|
|
4
4
|
"description": "JupyterLab extension for advanced image viewing: fit-to-screen, cursor-anchored wheel zoom, drag-to-pan, and Left/Right arrow keys to move to the previous and next image in a folder",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"@jupyterlab/filebrowser": "^4.6.0",
|
|
64
64
|
"@jupyterlab/imageviewer": "^4.6.0",
|
|
65
65
|
"@jupyterlab/settingregistry": "^4.6.0",
|
|
66
|
+
"@jupyterlab/translation": "^4.6.0",
|
|
66
67
|
"@jupyterlab/ui-components": "^4.6.0",
|
|
67
68
|
"@lumino/disposable": "^2.1.0",
|
|
68
69
|
"@lumino/widgets": "^2.9.0"
|
package/src/index.ts
CHANGED
|
@@ -20,12 +20,15 @@ import { IImageTracker, ImageViewer } from '@jupyterlab/imageviewer';
|
|
|
20
20
|
|
|
21
21
|
import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
22
22
|
|
|
23
|
-
import {
|
|
23
|
+
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
|
|
24
|
+
|
|
25
|
+
import { imageIcon, refreshIcon } from '@jupyterlab/ui-components';
|
|
24
26
|
|
|
25
27
|
import { IDisposable } from '@lumino/disposable';
|
|
26
28
|
|
|
27
29
|
import { Widget } from '@lumino/widgets';
|
|
28
30
|
|
|
31
|
+
// eslint-disable-next-line jupyter/prefer-lazy-imports -- activation attaches the controller to restored image tabs at once
|
|
29
32
|
import { ViewerController } from './controller';
|
|
30
33
|
|
|
31
34
|
const PLUGIN_ID = 'jupyterlab_advanced_image_viewer_extension:plugin';
|
|
@@ -46,12 +49,21 @@ const IMAGE_EXTS = new Set([
|
|
|
46
49
|
'.gif',
|
|
47
50
|
'.bmp',
|
|
48
51
|
'.svg',
|
|
49
|
-
'.webp'
|
|
52
|
+
'.webp',
|
|
53
|
+
'.avif'
|
|
50
54
|
]);
|
|
51
55
|
|
|
52
56
|
// Raster formats that can be drawn to a canvas and copied as PNG. SVG is
|
|
53
57
|
// excluded - the drawio/SVG extension already adds its own "Copy as PNG".
|
|
54
|
-
const RASTER_EXTS = new Set([
|
|
58
|
+
const RASTER_EXTS = new Set([
|
|
59
|
+
'.png',
|
|
60
|
+
'.jpg',
|
|
61
|
+
'.jpeg',
|
|
62
|
+
'.gif',
|
|
63
|
+
'.bmp',
|
|
64
|
+
'.webp',
|
|
65
|
+
'.avif'
|
|
66
|
+
]);
|
|
55
67
|
|
|
56
68
|
interface ISettingsState {
|
|
57
69
|
navEnabled: boolean;
|
|
@@ -69,16 +81,20 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
69
81
|
'Advanced image viewer: cursor-anchored wheel zoom, drag-to-pan, fit-to-screen reset, and arrow-key folder navigation.',
|
|
70
82
|
autoStart: true,
|
|
71
83
|
requires: [IImageTracker],
|
|
72
|
-
optional: [ISettingRegistry, IDefaultFileBrowser],
|
|
84
|
+
optional: [ISettingRegistry, IDefaultFileBrowser, ITranslator],
|
|
73
85
|
activate: (
|
|
74
86
|
app: JupyterFrontEnd,
|
|
75
87
|
tracker: IImageTracker,
|
|
76
88
|
settingRegistry: ISettingRegistry | null,
|
|
77
|
-
fileBrowser: IDefaultFileBrowser | null
|
|
89
|
+
fileBrowser: IDefaultFileBrowser | null,
|
|
90
|
+
translator: ITranslator | null
|
|
78
91
|
): void => {
|
|
79
92
|
console.log(
|
|
80
93
|
'JupyterLab extension jupyterlab_advanced_image_viewer_extension is activated!'
|
|
81
94
|
);
|
|
95
|
+
const trans = (translator ?? nullTranslator).load(
|
|
96
|
+
'jupyterlab_advanced_image_viewer_extension'
|
|
97
|
+
);
|
|
82
98
|
const controllers = new WeakMap<ImageViewer, ViewerController>();
|
|
83
99
|
const state: ISettingsState = { ...defaults };
|
|
84
100
|
let keyBindings: IDisposable[] = [];
|
|
@@ -112,9 +128,9 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
112
128
|
'</ul>'
|
|
113
129
|
].join('');
|
|
114
130
|
void showDialog({
|
|
115
|
-
title: 'Advanced Image Viewer',
|
|
131
|
+
title: trans.__('Advanced Image Viewer'),
|
|
116
132
|
body,
|
|
117
|
-
buttons: [Dialog.okButton({ label: 'Close' })]
|
|
133
|
+
buttons: [Dialog.okButton({ label: trans.__('Close') })]
|
|
118
134
|
});
|
|
119
135
|
};
|
|
120
136
|
|
|
@@ -146,7 +162,7 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
146
162
|
'advanced-refresh',
|
|
147
163
|
new ToolbarButton({
|
|
148
164
|
icon: refreshIcon,
|
|
149
|
-
tooltip: 'Reload image from disk',
|
|
165
|
+
tooltip: trans.__('Reload image from disk'),
|
|
150
166
|
noFocusOnClick: true,
|
|
151
167
|
onClick: async () => {
|
|
152
168
|
await widget.context.revert();
|
|
@@ -158,7 +174,7 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
158
174
|
'advanced-zoom-out',
|
|
159
175
|
new ToolbarButton({
|
|
160
176
|
label: '-',
|
|
161
|
-
tooltip: 'Zoom out',
|
|
177
|
+
tooltip: trans.__('Zoom out'),
|
|
162
178
|
noFocusOnClick: true,
|
|
163
179
|
onClick: () => app.commands.execute(CommandIDs.zoomOut)
|
|
164
180
|
})
|
|
@@ -167,7 +183,7 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
167
183
|
'advanced-zoom-in',
|
|
168
184
|
new ToolbarButton({
|
|
169
185
|
label: '+',
|
|
170
|
-
tooltip: 'Zoom in',
|
|
186
|
+
tooltip: trans.__('Zoom in'),
|
|
171
187
|
noFocusOnClick: true,
|
|
172
188
|
onClick: () => app.commands.execute(CommandIDs.zoomIn)
|
|
173
189
|
})
|
|
@@ -175,8 +191,8 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
175
191
|
widget.toolbar.addItem(
|
|
176
192
|
'advanced-reset-fit',
|
|
177
193
|
new ToolbarButton({
|
|
178
|
-
label: 'Fit',
|
|
179
|
-
tooltip: 'Reset to fit',
|
|
194
|
+
label: trans.__('Fit'),
|
|
195
|
+
tooltip: trans.__('Reset to fit'),
|
|
180
196
|
noFocusOnClick: true,
|
|
181
197
|
onClick: () => app.commands.execute(CommandIDs.resetFit)
|
|
182
198
|
})
|
|
@@ -184,9 +200,9 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
184
200
|
widget.toolbar.addItem('advanced-spacer', Toolbar.createSpacerItem());
|
|
185
201
|
const helpLink = new Widget({ node: document.createElement('a') });
|
|
186
202
|
const helpAnchor = helpLink.node as HTMLAnchorElement;
|
|
187
|
-
helpAnchor.textContent = 'help';
|
|
203
|
+
helpAnchor.textContent = trans.__('help');
|
|
188
204
|
helpAnchor.href = '#';
|
|
189
|
-
helpAnchor.title = 'Keybindings and help';
|
|
205
|
+
helpAnchor.title = trans.__('Keybindings and help');
|
|
190
206
|
helpAnchor.className = 'jp-AdvancedImageViewer-help-link';
|
|
191
207
|
helpAnchor.addEventListener('click', event => {
|
|
192
208
|
event.preventDefault();
|
|
@@ -209,19 +225,35 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
209
225
|
if (webp) {
|
|
210
226
|
app.docRegistry.addFileType(webp, ['Image']);
|
|
211
227
|
}
|
|
228
|
+
// JupyterLab registers no 'avif' file type at all, so add one with the
|
|
229
|
+
// same shape as its other image types, bound to the same factory.
|
|
230
|
+
app.docRegistry.addFileType(
|
|
231
|
+
{
|
|
232
|
+
name: 'avif',
|
|
233
|
+
displayName: 'Image',
|
|
234
|
+
mimeTypes: ['image/avif'],
|
|
235
|
+
extensions: ['.avif'],
|
|
236
|
+
icon: imageIcon,
|
|
237
|
+
fileFormat: 'base64'
|
|
238
|
+
},
|
|
239
|
+
['Image']
|
|
240
|
+
);
|
|
212
241
|
|
|
213
242
|
app.commands.addCommand(CommandIDs.zoomIn, {
|
|
214
|
-
label: 'Zoom In (Advanced Image Viewer)',
|
|
243
|
+
label: trans.__('Zoom In (Advanced Image Viewer)'),
|
|
244
|
+
describedBy: { args: { type: 'object', properties: {} } },
|
|
215
245
|
isEnabled: () => currentController() !== null,
|
|
216
246
|
execute: () => currentController()?.zoomIn()
|
|
217
247
|
});
|
|
218
248
|
app.commands.addCommand(CommandIDs.zoomOut, {
|
|
219
|
-
label: 'Zoom Out (Advanced Image Viewer)',
|
|
249
|
+
label: trans.__('Zoom Out (Advanced Image Viewer)'),
|
|
250
|
+
describedBy: { args: { type: 'object', properties: {} } },
|
|
220
251
|
isEnabled: () => currentController() !== null,
|
|
221
252
|
execute: () => currentController()?.zoomOut()
|
|
222
253
|
});
|
|
223
254
|
app.commands.addCommand(CommandIDs.resetFit, {
|
|
224
|
-
label: 'Reset to Fit (Advanced Image Viewer)',
|
|
255
|
+
label: trans.__('Reset to Fit (Advanced Image Viewer)'),
|
|
256
|
+
describedBy: { args: { type: 'object', properties: {} } },
|
|
225
257
|
isEnabled: () => currentController() !== null,
|
|
226
258
|
execute: () => currentController()?.reset()
|
|
227
259
|
});
|
|
@@ -240,7 +272,8 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
240
272
|
};
|
|
241
273
|
|
|
242
274
|
app.commands.addCommand(CommandIDs.copyClipboard, {
|
|
243
|
-
label: 'Copy to Clipboard',
|
|
275
|
+
label: trans.__('Copy to Clipboard'),
|
|
276
|
+
describedBy: { args: { type: 'object', properties: {} } },
|
|
244
277
|
// Raster only - SVG already has "Copy as PNG" from the drawio extension.
|
|
245
278
|
isVisible: () => {
|
|
246
279
|
const widget = contextImageWidget();
|
|
@@ -359,12 +392,14 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
359
392
|
};
|
|
360
393
|
|
|
361
394
|
app.commands.addCommand(CommandIDs.previous, {
|
|
362
|
-
label: 'Previous Image In Folder',
|
|
395
|
+
label: trans.__('Previous Image In Folder'),
|
|
396
|
+
describedBy: { args: { type: 'object', properties: {} } },
|
|
363
397
|
isEnabled: () => state.navEnabled && tracker.currentWidget !== null,
|
|
364
398
|
execute: () => navigate(-1)
|
|
365
399
|
});
|
|
366
400
|
app.commands.addCommand(CommandIDs.next, {
|
|
367
|
-
label: 'Next Image In Folder',
|
|
401
|
+
label: trans.__('Next Image In Folder'),
|
|
402
|
+
describedBy: { args: { type: 'object', properties: {} } },
|
|
368
403
|
isEnabled: () => state.navEnabled && tracker.currentWidget !== null,
|
|
369
404
|
execute: () => navigate(1)
|
|
370
405
|
});
|