@jupytergis/base 0.13.2 → 0.14.0
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/lib/commands/BaseCommandIDs.d.ts +14 -13
- package/lib/commands/BaseCommandIDs.js +14 -14
- package/lib/commands/index.js +528 -130
- package/lib/commands/operationCommands.d.ts +22 -0
- package/lib/commands/operationCommands.js +305 -0
- package/lib/constants.js +11 -9
- package/lib/dialogs/ProcessingFormDialog.d.ts +1 -1
- package/lib/dialogs/ProcessingFormDialog.js +2 -2
- package/lib/dialogs/layerBrowserDialog.d.ts +2 -0
- package/lib/dialogs/layerBrowserDialog.js +12 -5
- package/lib/dialogs/layerCreationFormDialog.d.ts +7 -0
- package/lib/dialogs/layerCreationFormDialog.js +10 -2
- package/lib/dialogs/symbology/components/color_ramp/ColorRampControls.d.ts +2 -1
- package/lib/dialogs/symbology/components/color_ramp/ColorRampControls.js +21 -19
- package/lib/dialogs/symbology/components/color_ramp/ColorRampSelector.d.ts +3 -1
- package/lib/dialogs/symbology/components/color_ramp/ColorRampSelector.js +13 -5
- package/lib/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.js +6 -4
- package/lib/dialogs/symbology/vector_layer/types/Categorized.js +7 -11
- package/lib/dialogs/symbology/vector_layer/types/Graduated.js +7 -10
- package/lib/dialogs/symbology/vector_layer/types/Heatmap.js +7 -8
- package/lib/formbuilder/creationform.d.ts +8 -8
- package/lib/formbuilder/creationform.js +130 -85
- package/lib/formbuilder/editform.d.ts +1 -7
- package/lib/formbuilder/editform.js +64 -52
- package/lib/formbuilder/formselectors.d.ts +5 -4
- package/lib/formbuilder/index.d.ts +1 -1
- package/lib/formbuilder/index.js +1 -1
- package/lib/formbuilder/objectform/SchemaForm.d.ts +36 -0
- package/lib/formbuilder/objectform/SchemaForm.js +77 -0
- package/lib/formbuilder/objectform/StoryEditorForm.d.ts +3 -9
- package/lib/formbuilder/objectform/StoryEditorForm.js +20 -14
- package/lib/formbuilder/objectform/components/LayerSelect.js +3 -8
- package/lib/formbuilder/objectform/components/SegmentFormSymbology.js +23 -10
- package/lib/formbuilder/objectform/components/SourcePropertiesField.d.ts +7 -0
- package/lib/formbuilder/objectform/components/SourcePropertiesField.js +29 -0
- package/lib/formbuilder/objectform/components/StorySegmentReset.js +1 -1
- package/lib/formbuilder/objectform/fileselectorwidget.js +1 -1
- package/lib/formbuilder/objectform/layer/heatmapLayerForm.d.ts +3 -12
- package/lib/formbuilder/objectform/layer/heatmapLayerForm.js +87 -55
- package/lib/formbuilder/objectform/layer/hillshadeLayerForm.d.ts +3 -8
- package/lib/formbuilder/objectform/layer/hillshadeLayerForm.js +36 -10
- package/lib/formbuilder/objectform/layer/layerform.d.ts +7 -9
- package/lib/formbuilder/objectform/layer/layerform.js +33 -20
- package/lib/formbuilder/objectform/layer/storySegmentLayerForm.d.ts +3 -5
- package/lib/formbuilder/objectform/layer/storySegmentLayerForm.js +73 -29
- package/lib/formbuilder/objectform/layer/vectorlayerform.d.ts +3 -14
- package/lib/formbuilder/objectform/layer/vectorlayerform.js +36 -29
- package/lib/formbuilder/objectform/layer/webGlLayerForm.d.ts +3 -10
- package/lib/formbuilder/objectform/layer/webGlLayerForm.js +37 -13
- package/lib/formbuilder/objectform/process/dissolveProcessForm.d.ts +8 -18
- package/lib/formbuilder/objectform/process/dissolveProcessForm.js +68 -56
- package/lib/formbuilder/objectform/processingForm.d.ts +12 -0
- package/lib/formbuilder/objectform/processingForm.js +33 -0
- package/lib/formbuilder/objectform/schemaUtils.d.ts +16 -0
- package/lib/formbuilder/objectform/schemaUtils.js +59 -0
- package/lib/formbuilder/objectform/source/geojsonsource.d.ts +3 -19
- package/lib/formbuilder/objectform/source/geojsonsource.js +94 -53
- package/lib/formbuilder/objectform/source/geotiffsource.d.ts +3 -20
- package/lib/formbuilder/objectform/source/geotiffsource.js +73 -74
- package/lib/formbuilder/objectform/source/pathbasedsource.d.ts +3 -19
- package/lib/formbuilder/objectform/source/pathbasedsource.js +76 -75
- package/lib/formbuilder/objectform/source/sourceform.d.ts +7 -8
- package/lib/formbuilder/objectform/source/sourceform.js +28 -11
- package/lib/formbuilder/objectform/source/tilesourceform.d.ts +3 -7
- package/lib/formbuilder/objectform/source/tilesourceform.js +63 -53
- package/lib/formbuilder/objectform/useSchemaFormState.d.ts +48 -0
- package/lib/formbuilder/objectform/useSchemaFormState.js +35 -0
- package/lib/index.d.ts +0 -1
- package/lib/index.js +0 -1
- package/lib/keybindings.json +10 -10
- package/lib/mainview/mainView.d.ts +11 -7
- package/lib/mainview/mainView.js +63 -36
- package/lib/mainview/mainviewmodel.js +2 -2
- package/lib/menus.js +8 -8
- package/lib/panelview/components/layers.js +5 -2
- package/lib/panelview/objectproperties.js +2 -2
- package/lib/panelview/rightpanel.js +17 -2
- package/lib/panelview/story-maps/SpectaPanel.d.ts +15 -0
- package/lib/panelview/story-maps/SpectaPanel.js +35 -0
- package/lib/panelview/story-maps/StoryViewerPanel.d.ts +24 -9
- package/lib/panelview/story-maps/StoryViewerPanel.js +22 -268
- package/lib/panelview/story-maps/{PreviewModeSwitch.js → components/PreviewModeSwitch.js} +1 -1
- package/lib/panelview/story-maps/components/SpectaDesktopView.d.ts +21 -0
- package/lib/panelview/story-maps/components/SpectaDesktopView.js +49 -0
- package/lib/panelview/story-maps/components/SpectaMobileView.d.ts +17 -0
- package/lib/panelview/story-maps/{MobileSpectaPanel.js → components/SpectaMobileView.js} +8 -22
- package/lib/panelview/story-maps/{StoryNavBar.d.ts → components/StoryNavBar.d.ts} +1 -1
- package/lib/panelview/story-maps/{StoryNavBar.js → components/StoryNavBar.js} +2 -4
- package/lib/panelview/story-maps/hooks/useStoryMap.d.ts +39 -0
- package/lib/panelview/story-maps/hooks/useStoryMap.js +252 -0
- package/lib/processing/index.d.ts +2 -2
- package/lib/processing/index.js +62 -35
- package/lib/processing/processingCommands.d.ts +1 -1
- package/lib/processing/processingCommands.js +26 -6
- package/lib/shared/components/Collapsible.d.ts +6 -0
- package/lib/shared/components/Collapsible.js +26 -0
- package/lib/statusbar/SpectaPresentationProgressBar.d.ts +7 -0
- package/lib/statusbar/SpectaPresentationProgressBar.js +40 -0
- package/lib/toolbar/widget.js +4 -2
- package/lib/tools.d.ts +6 -0
- package/lib/tools.js +9 -0
- package/lib/types.d.ts +29 -2
- package/lib/widget.js +14 -2
- package/package.json +2 -4
- package/style/base.css +23 -1
- package/style/dialog.css +5 -0
- package/style/leftPanel.css +14 -37
- package/style/shared/button.css +0 -10
- package/style/shared/switch.css +8 -7
- package/style/spectaProgressBar.css +144 -0
- package/style/storyPanel.css +33 -0
- package/style/symbologyDialog.css +2 -2
- package/lib/formbuilder/objectform/baseform.d.ts +0 -91
- package/lib/formbuilder/objectform/baseform.js +0 -231
- package/lib/panelview/story-maps/MobileSpectaPanel.d.ts +0 -7
- /package/lib/panelview/story-maps/{PreviewModeSwitch.d.ts → components/PreviewModeSwitch.d.ts} +0 -0
package/lib/commands/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { UUID } from '@lumino/coreutils';
|
|
2
2
|
import { fromLonLat } from 'ol/proj';
|
|
3
3
|
import { CommandIDs, icons } from '../constants';
|
|
4
4
|
import { ProcessingFormDialog } from '../dialogs/ProcessingFormDialog';
|
|
@@ -12,6 +12,7 @@ import { addProcessingCommands } from '../processing/processingCommands';
|
|
|
12
12
|
import { getGeoJSONDataFromLayerSource, downloadFile } from '../tools';
|
|
13
13
|
import { SYMBOLOGY_VALID_LAYER_TYPES } from '../types';
|
|
14
14
|
import { JupyterGISDocumentWidget } from '../widget';
|
|
15
|
+
import { addLayerCreationCommands } from './operationCommands';
|
|
15
16
|
const POINT_SELECTION_TOOL_CLASS = 'jGIS-point-selection-tool';
|
|
16
17
|
function loadKeybindings(commands, keybindings) {
|
|
17
18
|
keybindings.forEach(binding => {
|
|
@@ -29,6 +30,7 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
29
30
|
var _a;
|
|
30
31
|
const trans = translator.load('jupyterlab');
|
|
31
32
|
const { commands } = app;
|
|
33
|
+
addLayerCreationCommands({ tracker, commands, trans });
|
|
32
34
|
/**
|
|
33
35
|
* Wraps a command definition to automatically disable it in Specta mode
|
|
34
36
|
*/
|
|
@@ -54,7 +56,17 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
54
56
|
commands.addCommand = (id, options) => {
|
|
55
57
|
return originalAddCommand(id, createSpectaAwareCommand(options));
|
|
56
58
|
};
|
|
57
|
-
commands.addCommand(CommandIDs.symbology, Object.assign({ label: trans.__('Edit Symbology'),
|
|
59
|
+
commands.addCommand(CommandIDs.symbology, Object.assign({ label: trans.__('Edit Symbology'), caption: 'Open the symbology editor for the currently selected layer.', describedBy: {
|
|
60
|
+
args: {
|
|
61
|
+
type: 'object',
|
|
62
|
+
properties: {
|
|
63
|
+
selected: {
|
|
64
|
+
type: 'object',
|
|
65
|
+
description: 'Currently selected layer(s) in the map view',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
}, isEnabled: () => {
|
|
58
70
|
var _a, _b;
|
|
59
71
|
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
60
72
|
const localState = model === null || model === void 0 ? void 0 : model.sharedModel.awareness.getLocalState();
|
|
@@ -74,27 +86,65 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
74
86
|
const isValidLayer = SYMBOLOGY_VALID_LAYER_TYPES.includes(layer.type);
|
|
75
87
|
return isValidLayer;
|
|
76
88
|
}, execute: Private.createSymbologyDialog(tracker, state) }, icons.get(CommandIDs.symbology)));
|
|
77
|
-
commands.addCommand(CommandIDs.redo, Object.assign({ label: trans.__('Redo'),
|
|
89
|
+
commands.addCommand(CommandIDs.redo, Object.assign({ label: trans.__('Redo'), caption: 'Redo the last undone operation in the specified JupyterGIS document. If filePath is omitted, use the active document.', describedBy: {
|
|
90
|
+
args: {
|
|
91
|
+
type: 'object',
|
|
92
|
+
properties: {
|
|
93
|
+
filePath: {
|
|
94
|
+
type: 'string',
|
|
95
|
+
description: 'Optional .jGIS file path. If omitted, uses active widget.',
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
}, isEnabled: () => {
|
|
78
100
|
return tracker.currentWidget
|
|
79
101
|
? tracker.currentWidget.model.sharedModel.editable
|
|
80
102
|
: false;
|
|
81
|
-
}, execute: () => {
|
|
82
|
-
const
|
|
103
|
+
}, execute: (args) => {
|
|
104
|
+
const filePath = args === null || args === void 0 ? void 0 : args.filePath;
|
|
105
|
+
const current = filePath
|
|
106
|
+
? tracker.find(w => w.model.filePath === filePath)
|
|
107
|
+
: tracker.currentWidget;
|
|
83
108
|
if (current) {
|
|
84
109
|
return current.model.sharedModel.redo();
|
|
85
110
|
}
|
|
86
111
|
} }, (_a = icons.get(CommandIDs.redo)) === null || _a === void 0 ? void 0 : _a.icon));
|
|
87
|
-
commands.addCommand(CommandIDs.undo, Object.assign({ label: trans.__('Undo'),
|
|
112
|
+
commands.addCommand(CommandIDs.undo, Object.assign({ label: trans.__('Undo'), caption: 'Undo the last operation in the specified JupyterGIS document. If filePath is omitted, use the active document.', describedBy: {
|
|
113
|
+
args: {
|
|
114
|
+
type: 'object',
|
|
115
|
+
required: [],
|
|
116
|
+
properties: {
|
|
117
|
+
filePath: {
|
|
118
|
+
type: 'string',
|
|
119
|
+
description: 'Optional .jGIS file path. If omitted, uses active widget.',
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
}, isEnabled: () => {
|
|
88
124
|
return tracker.currentWidget
|
|
89
125
|
? tracker.currentWidget.model.sharedModel.editable
|
|
90
126
|
: false;
|
|
91
|
-
}, execute: () => {
|
|
92
|
-
const
|
|
127
|
+
}, execute: (args) => {
|
|
128
|
+
const filePath = args === null || args === void 0 ? void 0 : args.filePath;
|
|
129
|
+
const current = filePath
|
|
130
|
+
? tracker.find(w => w.model.filePath === filePath)
|
|
131
|
+
: tracker.currentWidget;
|
|
93
132
|
if (current) {
|
|
94
133
|
return current.model.sharedModel.undo();
|
|
95
134
|
}
|
|
96
135
|
} }, icons.get(CommandIDs.undo)));
|
|
97
|
-
commands.addCommand(CommandIDs.identify, Object.assign({ label: trans.__('Identify'),
|
|
136
|
+
commands.addCommand(CommandIDs.identify, Object.assign({ label: trans.__('Identify'), caption: 'Toggle identify mode for the selected vector-compatible layer in the specified JupyterGIS document.', describedBy: {
|
|
137
|
+
args: {
|
|
138
|
+
type: 'object',
|
|
139
|
+
required: [],
|
|
140
|
+
properties: {
|
|
141
|
+
filePath: {
|
|
142
|
+
type: 'string',
|
|
143
|
+
description: 'Optional .jGIS file path. If omitted, uses active widget.',
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
}, isToggled: () => {
|
|
98
148
|
const current = tracker.currentWidget;
|
|
99
149
|
if (!current) {
|
|
100
150
|
return false;
|
|
@@ -131,7 +181,10 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
131
181
|
'VectorTileLayer',
|
|
132
182
|
].includes(selectedLayer.type);
|
|
133
183
|
}, execute: args => {
|
|
134
|
-
const
|
|
184
|
+
const filePath = args === null || args === void 0 ? void 0 : args.filePath;
|
|
185
|
+
const current = filePath
|
|
186
|
+
? tracker.find(w => w.model.filePath === filePath)
|
|
187
|
+
: tracker.currentWidget;
|
|
135
188
|
if (!current) {
|
|
136
189
|
return;
|
|
137
190
|
}
|
|
@@ -149,7 +202,17 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
149
202
|
current.model.toggleMode('identifying');
|
|
150
203
|
commands.notifyCommandChanged(CommandIDs.identify);
|
|
151
204
|
} }, icons.get(CommandIDs.identify)));
|
|
152
|
-
commands.addCommand(CommandIDs.temporalController, Object.assign({ label: trans.__('Temporal Controller'),
|
|
205
|
+
commands.addCommand(CommandIDs.temporalController, Object.assign({ label: trans.__('Temporal Controller'), caption: 'Toggle the temporal controller for the selected vector or heatmap layer in the specified JupyterGIS document.', describedBy: {
|
|
206
|
+
args: {
|
|
207
|
+
type: 'object',
|
|
208
|
+
properties: {
|
|
209
|
+
filePath: {
|
|
210
|
+
type: 'string',
|
|
211
|
+
description: 'Optional path to the .jGIS file',
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
}, isToggled: () => {
|
|
153
216
|
var _a;
|
|
154
217
|
return ((_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model.isTemporalControllerActive) || false;
|
|
155
218
|
}, isEnabled: () => {
|
|
@@ -177,8 +240,11 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
177
240
|
return false;
|
|
178
241
|
}
|
|
179
242
|
return true;
|
|
180
|
-
}, execute: () => {
|
|
181
|
-
const
|
|
243
|
+
}, execute: (args) => {
|
|
244
|
+
const filePath = args === null || args === void 0 ? void 0 : args.filePath;
|
|
245
|
+
const current = filePath
|
|
246
|
+
? tracker.find(w => w.model.filePath === filePath)
|
|
247
|
+
: tracker.currentWidget;
|
|
182
248
|
if (!current) {
|
|
183
249
|
return;
|
|
184
250
|
}
|
|
@@ -188,7 +254,12 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
188
254
|
/**
|
|
189
255
|
* SOURCES and LAYERS creation commands.
|
|
190
256
|
*/
|
|
191
|
-
commands.addCommand(CommandIDs.openLayerBrowser, Object.assign({ label: trans.__('Open Layer Browser'),
|
|
257
|
+
commands.addCommand(CommandIDs.openLayerBrowser, Object.assign({ label: trans.__('Open Layer Browser'), caption: 'Open the layer browser dialog to browse and add available layers to the current JupyterGIS document.', describedBy: {
|
|
258
|
+
args: {
|
|
259
|
+
type: 'object',
|
|
260
|
+
properties: {},
|
|
261
|
+
},
|
|
262
|
+
}, isEnabled: () => {
|
|
192
263
|
return tracker.currentWidget
|
|
193
264
|
? tracker.currentWidget.model.sharedModel.editable
|
|
194
265
|
: false;
|
|
@@ -196,7 +267,12 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
196
267
|
/**
|
|
197
268
|
* Source and layers
|
|
198
269
|
*/
|
|
199
|
-
commands.addCommand(CommandIDs.
|
|
270
|
+
commands.addCommand(CommandIDs.openNewRasterDialog, Object.assign({ label: trans.__('Open New Raster Tile Layer Creation Dialog'), caption: 'Open a dialog to create a new raster tile layer and source in the current JupyterGIS document.', describedBy: {
|
|
271
|
+
args: {
|
|
272
|
+
type: 'object',
|
|
273
|
+
properties: {},
|
|
274
|
+
},
|
|
275
|
+
}, isEnabled: () => {
|
|
200
276
|
return tracker.currentWidget
|
|
201
277
|
? tracker.currentWidget.model.sharedModel.editable
|
|
202
278
|
: false;
|
|
@@ -206,15 +282,16 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
206
282
|
title: 'Create Raster Tile Layer',
|
|
207
283
|
createLayer: true,
|
|
208
284
|
createSource: true,
|
|
209
|
-
sourceData: {
|
|
210
|
-
minZoom: 0,
|
|
211
|
-
maxZoom: 24,
|
|
212
|
-
},
|
|
213
285
|
layerData: { name: 'Custom Raster Tile Layer' },
|
|
214
286
|
sourceType: 'RasterSource',
|
|
215
287
|
layerType: 'RasterLayer',
|
|
216
|
-
}) }, icons.get(CommandIDs.
|
|
217
|
-
commands.addCommand(CommandIDs.
|
|
288
|
+
}) }, icons.get(CommandIDs.openNewRasterDialog)));
|
|
289
|
+
commands.addCommand(CommandIDs.openNewVectorTileDialog, Object.assign({ label: trans.__('Open New Vector Tile Layer Creation Dialog'), caption: 'Open a dialog to create a new vector tile layer and source in the current JupyterGIS document.', describedBy: {
|
|
290
|
+
args: {
|
|
291
|
+
type: 'object',
|
|
292
|
+
properties: {},
|
|
293
|
+
},
|
|
294
|
+
}, isEnabled: () => {
|
|
218
295
|
return tracker.currentWidget
|
|
219
296
|
? tracker.currentWidget.model.sharedModel.editable
|
|
220
297
|
: false;
|
|
@@ -224,12 +301,16 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
224
301
|
title: 'Create Vector Tile Layer',
|
|
225
302
|
createLayer: true,
|
|
226
303
|
createSource: true,
|
|
227
|
-
sourceData: { minZoom: 0, maxZoom: 24 },
|
|
228
304
|
layerData: { name: 'Custom Vector Tile Layer' },
|
|
229
305
|
sourceType: 'VectorTileSource',
|
|
230
306
|
layerType: 'VectorTileLayer',
|
|
231
|
-
}) }, icons.get(CommandIDs.
|
|
232
|
-
commands.addCommand(CommandIDs.
|
|
307
|
+
}) }, icons.get(CommandIDs.openNewVectorTileDialog)));
|
|
308
|
+
commands.addCommand(CommandIDs.openNewGeoParquetDialog, Object.assign({ label: trans.__('Open New GeoParquet Layer Creation Dialog'), caption: 'Open a dialog to create a new GeoParquet layer and source in the current JupyterGIS document.', describedBy: {
|
|
309
|
+
args: {
|
|
310
|
+
type: 'object',
|
|
311
|
+
properties: {},
|
|
312
|
+
},
|
|
313
|
+
}, isEnabled: () => {
|
|
233
314
|
return tracker.currentWidget
|
|
234
315
|
? tracker.currentWidget.model.sharedModel.editable
|
|
235
316
|
: false;
|
|
@@ -243,8 +324,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
243
324
|
layerData: { name: 'Custom GeoParquet Layer' },
|
|
244
325
|
sourceType: 'GeoParquetSource',
|
|
245
326
|
layerType: 'VectorLayer',
|
|
246
|
-
}) }, icons.get(CommandIDs.
|
|
247
|
-
commands.addCommand(CommandIDs.
|
|
327
|
+
}) }, icons.get(CommandIDs.openNewGeoParquetDialog)));
|
|
328
|
+
commands.addCommand(CommandIDs.openNewGeoJSONDialog, Object.assign({ label: trans.__('Open New GeoJSON Layer Creation Dialog'), caption: 'Open a dialog to create a new GeoJSON layer and source in the current JupyterGIS document.', describedBy: {
|
|
329
|
+
args: {
|
|
330
|
+
type: 'object',
|
|
331
|
+
properties: {},
|
|
332
|
+
},
|
|
333
|
+
}, isEnabled: () => {
|
|
248
334
|
return tracker.currentWidget
|
|
249
335
|
? tracker.currentWidget.model.sharedModel.editable
|
|
250
336
|
: false;
|
|
@@ -257,10 +343,15 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
257
343
|
layerData: { name: 'Custom GeoJSON Layer' },
|
|
258
344
|
sourceType: 'GeoJSONSource',
|
|
259
345
|
layerType: 'VectorLayer',
|
|
260
|
-
}) }, icons.get(CommandIDs.
|
|
346
|
+
}) }, icons.get(CommandIDs.openNewGeoJSONDialog)));
|
|
261
347
|
//Add processing commands
|
|
262
|
-
addProcessingCommands(app, commands, tracker, trans, formSchemaRegistry);
|
|
263
|
-
commands.addCommand(CommandIDs.
|
|
348
|
+
addProcessingCommands(app, commands, tracker, trans, formSchemaRegistry, Object.fromEntries(formSchemaRegistry.getSchemas()));
|
|
349
|
+
commands.addCommand(CommandIDs.openNewHillshadeDialog, Object.assign({ label: trans.__('Open New Hillshade Layer Creation Dialog'), caption: 'Open a dialog to create a new hillshade layer and source in the current JupyterGIS document.', describedBy: {
|
|
350
|
+
args: {
|
|
351
|
+
type: 'object',
|
|
352
|
+
properties: {},
|
|
353
|
+
},
|
|
354
|
+
}, isEnabled: () => {
|
|
264
355
|
return tracker.currentWidget
|
|
265
356
|
? tracker.currentWidget.model.sharedModel.editable
|
|
266
357
|
: false;
|
|
@@ -273,8 +364,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
273
364
|
layerData: { name: 'Custom Hillshade Layer' },
|
|
274
365
|
sourceType: 'RasterDemSource',
|
|
275
366
|
layerType: 'HillshadeLayer',
|
|
276
|
-
}) }, icons.get(CommandIDs.
|
|
277
|
-
commands.addCommand(CommandIDs.
|
|
367
|
+
}) }, icons.get(CommandIDs.openNewHillshadeDialog)));
|
|
368
|
+
commands.addCommand(CommandIDs.openNewImageDialog, Object.assign({ label: trans.__('Open New Image Layer Creation Dialog'), caption: 'Open a dialog to create a new image layer and source in the current JupyterGIS document.', describedBy: {
|
|
369
|
+
args: {
|
|
370
|
+
type: 'object',
|
|
371
|
+
properties: {},
|
|
372
|
+
},
|
|
373
|
+
}, isEnabled: () => {
|
|
278
374
|
return tracker.currentWidget
|
|
279
375
|
? tracker.currentWidget.model.sharedModel.editable
|
|
280
376
|
: false;
|
|
@@ -297,8 +393,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
297
393
|
layerData: { name: 'Custom Image Layer' },
|
|
298
394
|
sourceType: 'ImageSource',
|
|
299
395
|
layerType: 'ImageLayer',
|
|
300
|
-
}) }, icons.get(CommandIDs.
|
|
301
|
-
commands.addCommand(CommandIDs.
|
|
396
|
+
}) }, icons.get(CommandIDs.openNewImageDialog)));
|
|
397
|
+
commands.addCommand(CommandIDs.openNewVideoDialog, Object.assign({ label: trans.__('Open New Video Layer Creation Dialog'), caption: 'Open a dialog to create a new video layer and source in the current JupyterGIS document.', describedBy: {
|
|
398
|
+
args: {
|
|
399
|
+
type: 'object',
|
|
400
|
+
properties: {},
|
|
401
|
+
},
|
|
402
|
+
}, isEnabled: () => {
|
|
302
403
|
return tracker.currentWidget
|
|
303
404
|
? tracker.currentWidget.model.sharedModel.editable
|
|
304
405
|
: false;
|
|
@@ -324,8 +425,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
324
425
|
layerData: { name: 'Custom Video Layer' },
|
|
325
426
|
sourceType: 'VideoSource',
|
|
326
427
|
layerType: 'RasterLayer',
|
|
327
|
-
}) }, icons.get(CommandIDs.
|
|
328
|
-
commands.addCommand(CommandIDs.
|
|
428
|
+
}) }, icons.get(CommandIDs.openNewVideoDialog)));
|
|
429
|
+
commands.addCommand(CommandIDs.openNewGeoTiffDialog, Object.assign({ label: trans.__('Open New GeoTiff Layer Creation Dialog'), caption: 'Open a dialog to create a new GeoTiff layer and source in the current JupyterGIS document.', describedBy: {
|
|
430
|
+
args: {
|
|
431
|
+
type: 'object',
|
|
432
|
+
properties: {},
|
|
433
|
+
},
|
|
434
|
+
}, isEnabled: () => {
|
|
329
435
|
return tracker.currentWidget
|
|
330
436
|
? tracker.currentWidget.model.sharedModel.editable
|
|
331
437
|
: false;
|
|
@@ -342,8 +448,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
342
448
|
layerData: { name: 'Custom GeoTiff Layer' },
|
|
343
449
|
sourceType: 'GeoTiffSource',
|
|
344
450
|
layerType: 'WebGlLayer',
|
|
345
|
-
}) }, icons.get(CommandIDs.
|
|
346
|
-
commands.addCommand(CommandIDs.
|
|
451
|
+
}) }, icons.get(CommandIDs.openNewGeoTiffDialog)));
|
|
452
|
+
commands.addCommand(CommandIDs.openNewShapefileDialog, Object.assign({ label: trans.__('Open New Shapefile Layer Creation Dialog'), caption: 'Open a dialog to create a new shapefile layer and source in the current JupyterGIS document.', describedBy: {
|
|
453
|
+
args: {
|
|
454
|
+
type: 'object',
|
|
455
|
+
properties: {},
|
|
456
|
+
},
|
|
457
|
+
}, isEnabled: () => {
|
|
347
458
|
return tracker.currentWidget
|
|
348
459
|
? tracker.currentWidget.model.sharedModel.editable
|
|
349
460
|
: false;
|
|
@@ -357,19 +468,16 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
357
468
|
layerData: { name: 'Custom Shapefile Layer' },
|
|
358
469
|
sourceType: 'ShapefileSource',
|
|
359
470
|
layerType: 'VectorLayer',
|
|
360
|
-
}) }, icons.get(CommandIDs.
|
|
471
|
+
}) }, icons.get(CommandIDs.openNewShapefileDialog)));
|
|
361
472
|
/**
|
|
362
473
|
* LAYERS and LAYER GROUP actions.
|
|
363
474
|
*/
|
|
364
|
-
commands.addCommand(CommandIDs.renameSelected, {
|
|
365
|
-
label: trans.__('Rename'),
|
|
366
|
-
isEnabled: () => {
|
|
475
|
+
commands.addCommand(CommandIDs.renameSelected, Object.assign({ label: trans.__('Rename'), isEnabled: () => {
|
|
367
476
|
var _a, _b, _c;
|
|
368
477
|
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
369
478
|
const selected = (_c = (_b = model === null || model === void 0 ? void 0 : model.localState) === null || _b === void 0 ? void 0 : _b.selected) === null || _c === void 0 ? void 0 : _c.value;
|
|
370
479
|
return !!selected && Object.keys(selected).length === 1;
|
|
371
|
-
},
|
|
372
|
-
execute: async () => {
|
|
480
|
+
}, execute: async () => {
|
|
373
481
|
var _a, _b, _c;
|
|
374
482
|
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
375
483
|
const selected = (_c = (_b = model === null || model === void 0 ? void 0 : model.localState) === null || _b === void 0 ? void 0 : _b.selected) === null || _c === void 0 ? void 0 : _c.value;
|
|
@@ -377,17 +485,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
377
485
|
return;
|
|
378
486
|
}
|
|
379
487
|
await Private.renameSelectedItem(model);
|
|
380
|
-
},
|
|
381
|
-
|
|
382
|
-
commands.addCommand(CommandIDs.removeSelected, {
|
|
383
|
-
label: trans.__('Remove'),
|
|
384
|
-
isEnabled: () => {
|
|
488
|
+
} }, icons.get(CommandIDs.renameSelected)));
|
|
489
|
+
commands.addCommand(CommandIDs.removeSelected, Object.assign({ label: trans.__('Remove'), isEnabled: () => {
|
|
385
490
|
var _a, _b, _c;
|
|
386
491
|
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
387
492
|
const selected = (_c = (_b = model === null || model === void 0 ? void 0 : model.localState) === null || _b === void 0 ? void 0 : _b.selected) === null || _c === void 0 ? void 0 : _c.value;
|
|
388
493
|
return !!selected && Object.keys(selected).length > 0;
|
|
389
|
-
},
|
|
390
|
-
execute: async () => {
|
|
494
|
+
}, execute: async () => {
|
|
391
495
|
var _a, _b, _c;
|
|
392
496
|
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
393
497
|
const selected = (_c = (_b = model === null || model === void 0 ? void 0 : model.localState) === null || _b === void 0 ? void 0 : _b.selected) === null || _c === void 0 ? void 0 : _c.value;
|
|
@@ -395,27 +499,117 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
395
499
|
return;
|
|
396
500
|
}
|
|
397
501
|
await Private.removeSelectedItems(model);
|
|
502
|
+
} }, icons.get(CommandIDs.removeSelected)));
|
|
503
|
+
commands.addCommand(CommandIDs.duplicateSelected, {
|
|
504
|
+
label: trans.__('Duplicate'),
|
|
505
|
+
isEnabled: () => {
|
|
506
|
+
var _a, _b, _c;
|
|
507
|
+
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
508
|
+
const selected = (_c = (_b = model === null || model === void 0 ? void 0 : model.localState) === null || _b === void 0 ? void 0 : _b.selected) === null || _c === void 0 ? void 0 : _c.value;
|
|
509
|
+
if (!selected) {
|
|
510
|
+
return false;
|
|
511
|
+
}
|
|
512
|
+
return Object.values(selected).some(item => item.type === 'layer');
|
|
398
513
|
},
|
|
399
|
-
|
|
400
|
-
commands.addCommand(CommandIDs.moveLayersToGroup, {
|
|
401
|
-
label: args => args['label'] ? args['label'] : trans.__('Move to Root'),
|
|
402
|
-
execute: args => {
|
|
514
|
+
execute: () => {
|
|
403
515
|
var _a, _b, _c;
|
|
404
516
|
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
405
|
-
const
|
|
406
|
-
|
|
517
|
+
const selected = (_c = (_b = model === null || model === void 0 ? void 0 : model.localState) === null || _b === void 0 ? void 0 : _b.selected) === null || _c === void 0 ? void 0 : _c.value;
|
|
518
|
+
if (!model || !selected) {
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
for (const [layerId, selectedItem] of Object.entries(selected)) {
|
|
522
|
+
if (selectedItem.type !== 'layer') {
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
const layer = model.getLayer(layerId);
|
|
526
|
+
if (!layer) {
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
const clonedLayer = Object.assign(Object.assign({}, layer), { name: Private.generateCopyName(layer.name, model) });
|
|
530
|
+
model.addLayer(UUID.uuid4(), clonedLayer);
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
});
|
|
534
|
+
commands.addCommand(CommandIDs.moveSelectedToGroup, {
|
|
535
|
+
label: args => args['label']
|
|
536
|
+
? args['label']
|
|
537
|
+
: trans.__('Move Selection to Root Group'),
|
|
538
|
+
caption: 'Group layers together in a new group with name "groupName" for the JupyterGIS document "filepath"',
|
|
539
|
+
describedBy: {
|
|
540
|
+
args: {
|
|
541
|
+
type: 'object',
|
|
542
|
+
properties: {
|
|
543
|
+
label: { type: 'string' },
|
|
544
|
+
filePath: { type: 'string' },
|
|
545
|
+
layerIds: {
|
|
546
|
+
type: 'array',
|
|
547
|
+
items: { type: 'string' },
|
|
548
|
+
},
|
|
549
|
+
groupName: { type: 'string' },
|
|
550
|
+
},
|
|
551
|
+
},
|
|
552
|
+
},
|
|
553
|
+
execute: (args) => {
|
|
554
|
+
var _a, _b, _c, _d;
|
|
555
|
+
const { filePath, layerIds, groupName } = args !== null && args !== void 0 ? args : {};
|
|
556
|
+
// Resolve model based on filePath or current widget
|
|
557
|
+
const model = filePath
|
|
558
|
+
? (_a = tracker.find(w => w.model.filePath === filePath)) === null || _a === void 0 ? void 0 : _a.model
|
|
559
|
+
: (_b = tracker.currentWidget) === null || _b === void 0 ? void 0 : _b.model;
|
|
560
|
+
if (!model || !model.sharedModel.editable) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
if (filePath && layerIds && groupName !== undefined) {
|
|
564
|
+
model.moveItemsToGroup(layerIds, groupName);
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
const selectedLayers = (_d = (_c = model.localState) === null || _c === void 0 ? void 0 : _c.selected) === null || _d === void 0 ? void 0 : _d.value;
|
|
407
568
|
if (!selectedLayers) {
|
|
408
569
|
return;
|
|
409
570
|
}
|
|
410
|
-
|
|
571
|
+
const targetGroup = args === null || args === void 0 ? void 0 : args.label;
|
|
572
|
+
model.moveItemsToGroup(Object.keys(selectedLayers), targetGroup);
|
|
411
573
|
},
|
|
412
574
|
});
|
|
413
|
-
commands.addCommand(CommandIDs.
|
|
414
|
-
label: trans.__('Move
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
575
|
+
commands.addCommand(CommandIDs.moveSelectedToNewGroup, {
|
|
576
|
+
label: trans.__('Move Selection to New Group'),
|
|
577
|
+
caption: 'Move selected layers to a new group in the current JupyterGIS document.',
|
|
578
|
+
describedBy: {
|
|
579
|
+
args: {
|
|
580
|
+
type: 'object',
|
|
581
|
+
properties: {
|
|
582
|
+
filePath: { type: 'string' },
|
|
583
|
+
groupName: { type: 'string' },
|
|
584
|
+
layerIds: {
|
|
585
|
+
type: 'array',
|
|
586
|
+
items: { type: 'string' },
|
|
587
|
+
},
|
|
588
|
+
},
|
|
589
|
+
},
|
|
590
|
+
},
|
|
591
|
+
execute: async (args) => {
|
|
592
|
+
var _a, _b, _c, _d;
|
|
593
|
+
const { filePath, groupName, layerIds } = args !== null && args !== void 0 ? args : {};
|
|
594
|
+
const model = filePath
|
|
595
|
+
? (_a = tracker.find(w => w.model.filePath === filePath)) === null || _a === void 0 ? void 0 : _a.model
|
|
596
|
+
: (_b = tracker.currentWidget) === null || _b === void 0 ? void 0 : _b.model;
|
|
597
|
+
if (!model || !model.sharedModel.editable) {
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
if (filePath && groupName && layerIds) {
|
|
601
|
+
const layerMap = {};
|
|
602
|
+
layerIds.forEach(id => {
|
|
603
|
+
layerMap[id] = { type: 'layer', selectedNodeId: id };
|
|
604
|
+
});
|
|
605
|
+
const newGroup = {
|
|
606
|
+
name: groupName,
|
|
607
|
+
layers: layerIds,
|
|
608
|
+
};
|
|
609
|
+
model.addNewLayerGroup(layerMap, newGroup);
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
const selectedLayers = (_d = (_c = model.localState) === null || _c === void 0 ? void 0 : _c.selected) === null || _d === void 0 ? void 0 : _d.value;
|
|
419
613
|
if (!selectedLayers) {
|
|
420
614
|
return;
|
|
421
615
|
}
|
|
@@ -464,28 +658,16 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
464
658
|
model.addNewLayerGroup(selectedLayers, newLayerGroup);
|
|
465
659
|
},
|
|
466
660
|
});
|
|
467
|
-
/**
|
|
468
|
-
* Source actions
|
|
469
|
-
*/
|
|
470
|
-
commands.addCommand(CommandIDs.renameSource, {
|
|
471
|
-
label: trans.__('Rename Source'),
|
|
472
|
-
execute: async () => {
|
|
473
|
-
var _a;
|
|
474
|
-
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
475
|
-
await Private.renameSelectedItem(model);
|
|
476
|
-
},
|
|
477
|
-
});
|
|
478
|
-
commands.addCommand(CommandIDs.removeSource, {
|
|
479
|
-
label: trans.__('Remove Source'),
|
|
480
|
-
execute: () => {
|
|
481
|
-
var _a;
|
|
482
|
-
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
483
|
-
Private.removeSelectedSources(model);
|
|
484
|
-
},
|
|
485
|
-
});
|
|
486
661
|
// Console commands
|
|
487
662
|
commands.addCommand(CommandIDs.toggleConsole, {
|
|
488
663
|
label: trans.__('Toggle console'),
|
|
664
|
+
caption: 'Toggle the console in the current JupyterGIS document.',
|
|
665
|
+
describedBy: {
|
|
666
|
+
args: {
|
|
667
|
+
type: 'object',
|
|
668
|
+
properties: {},
|
|
669
|
+
},
|
|
670
|
+
},
|
|
489
671
|
isVisible: () => tracker.currentWidget instanceof JupyterGISDocumentWidget,
|
|
490
672
|
isEnabled: () => {
|
|
491
673
|
return tracker.currentWidget
|
|
@@ -508,6 +690,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
508
690
|
});
|
|
509
691
|
commands.addCommand(CommandIDs.executeConsole, {
|
|
510
692
|
label: trans.__('Execute console'),
|
|
693
|
+
caption: 'Execute the console in the current JupyterGIS document.',
|
|
694
|
+
describedBy: {
|
|
695
|
+
args: {
|
|
696
|
+
type: 'object',
|
|
697
|
+
properties: {},
|
|
698
|
+
},
|
|
699
|
+
},
|
|
511
700
|
isVisible: () => tracker.currentWidget instanceof JupyterGISDocumentWidget,
|
|
512
701
|
isEnabled: () => {
|
|
513
702
|
return tracker.currentWidget
|
|
@@ -518,6 +707,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
518
707
|
});
|
|
519
708
|
commands.addCommand(CommandIDs.removeConsole, {
|
|
520
709
|
label: trans.__('Remove console'),
|
|
710
|
+
caption: 'Remove the console from the current JupyterGIS document.',
|
|
711
|
+
describedBy: {
|
|
712
|
+
args: {
|
|
713
|
+
type: 'object',
|
|
714
|
+
properties: {},
|
|
715
|
+
},
|
|
716
|
+
},
|
|
521
717
|
isVisible: () => tracker.currentWidget instanceof JupyterGISDocumentWidget,
|
|
522
718
|
isEnabled: () => {
|
|
523
719
|
return tracker.currentWidget
|
|
@@ -528,6 +724,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
528
724
|
});
|
|
529
725
|
commands.addCommand(CommandIDs.invokeCompleter, {
|
|
530
726
|
label: trans.__('Display the completion helper.'),
|
|
727
|
+
caption: 'Display the completion helper in the current JupyterGIS document.',
|
|
728
|
+
describedBy: {
|
|
729
|
+
args: {
|
|
730
|
+
type: 'object',
|
|
731
|
+
properties: {},
|
|
732
|
+
},
|
|
733
|
+
},
|
|
531
734
|
isVisible: () => tracker.currentWidget instanceof JupyterGISDocumentWidget,
|
|
532
735
|
execute: () => {
|
|
533
736
|
var _a;
|
|
@@ -545,6 +748,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
545
748
|
});
|
|
546
749
|
commands.addCommand(CommandIDs.selectCompleter, {
|
|
547
750
|
label: trans.__('Select the completion suggestion.'),
|
|
751
|
+
caption: 'Select the completion suggestion in the current JupyterGIS document.',
|
|
752
|
+
describedBy: {
|
|
753
|
+
args: {
|
|
754
|
+
type: 'object',
|
|
755
|
+
properties: {},
|
|
756
|
+
},
|
|
757
|
+
},
|
|
548
758
|
isVisible: () => tracker.currentWidget instanceof JupyterGISDocumentWidget,
|
|
549
759
|
execute: () => {
|
|
550
760
|
var _a;
|
|
@@ -562,37 +772,98 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
562
772
|
});
|
|
563
773
|
commands.addCommand(CommandIDs.zoomToLayer, {
|
|
564
774
|
label: trans.__('Zoom to Layer'),
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
775
|
+
caption: 'Zoom to the selected layer in the current JupyterGIS document.',
|
|
776
|
+
describedBy: {
|
|
777
|
+
args: {
|
|
778
|
+
type: 'object',
|
|
779
|
+
properties: {
|
|
780
|
+
filePath: { type: 'string' },
|
|
781
|
+
layerId: { type: 'string' },
|
|
782
|
+
},
|
|
783
|
+
},
|
|
784
|
+
},
|
|
785
|
+
execute: (args) => {
|
|
786
|
+
var _a, _b;
|
|
787
|
+
const { filePath, layerId } = args !== null && args !== void 0 ? args : {};
|
|
788
|
+
// Determine model from provided file path or fallback to current widget
|
|
789
|
+
const current = filePath
|
|
790
|
+
? tracker.find(w => w.model.filePath === filePath)
|
|
791
|
+
: tracker.currentWidget;
|
|
792
|
+
if (!current || !current.model.sharedModel.editable) {
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
const model = current.model;
|
|
796
|
+
if (filePath && layerId) {
|
|
797
|
+
model.centerOnPosition(layerId);
|
|
569
798
|
return;
|
|
570
799
|
}
|
|
571
|
-
const
|
|
572
|
-
const selectedItems = (_a = model.localState) === null || _a === void 0 ? void 0 : _a.selected.value;
|
|
800
|
+
const selectedItems = (_b = (_a = model.localState) === null || _a === void 0 ? void 0 : _a.selected) === null || _b === void 0 ? void 0 : _b.value;
|
|
573
801
|
if (!selectedItems) {
|
|
574
802
|
return;
|
|
575
803
|
}
|
|
576
|
-
const
|
|
577
|
-
model.centerOnPosition(
|
|
804
|
+
const selLayerId = Object.keys(selectedItems)[0];
|
|
805
|
+
model.centerOnPosition(selLayerId);
|
|
578
806
|
},
|
|
579
807
|
});
|
|
580
808
|
commands.addCommand(CommandIDs.downloadGeoJSON, {
|
|
581
809
|
label: trans.__('Download as GeoJSON'),
|
|
810
|
+
caption: 'Download the selected layer as a GeoJSON file in the current JupyterGIS document.',
|
|
811
|
+
describedBy: {
|
|
812
|
+
args: {
|
|
813
|
+
type: 'object',
|
|
814
|
+
properties: {
|
|
815
|
+
filePath: { type: 'string' },
|
|
816
|
+
layerId: { type: 'string' },
|
|
817
|
+
exportFileName: { type: 'string' },
|
|
818
|
+
},
|
|
819
|
+
},
|
|
820
|
+
},
|
|
582
821
|
isEnabled: () => {
|
|
583
|
-
const
|
|
584
|
-
return
|
|
585
|
-
? ['VectorLayer', 'ShapefileLayer'].includes(selectedLayer.type)
|
|
586
|
-
: false;
|
|
822
|
+
const layer = getSingleSelectedLayer(tracker);
|
|
823
|
+
return !!layer && ['VectorLayer', 'ShapefileLayer'].includes(layer.type);
|
|
587
824
|
},
|
|
588
|
-
execute: async () => {
|
|
589
|
-
var _a
|
|
825
|
+
execute: async (args) => {
|
|
826
|
+
var _a;
|
|
827
|
+
const exportLayer = async (model, layer, exportFileName) => {
|
|
828
|
+
var _a, _b;
|
|
829
|
+
if (!['VectorLayer', 'ShapefileLayer'].includes(layer.type)) {
|
|
830
|
+
console.warn('Layer type not supported for GeoJSON export');
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
const sources = (_a = model.sharedModel.sources) !== null && _a !== void 0 ? _a : {};
|
|
834
|
+
const sourceId = (_b = layer.parameters) === null || _b === void 0 ? void 0 : _b.source;
|
|
835
|
+
const source = sources[sourceId];
|
|
836
|
+
if (!source) {
|
|
837
|
+
console.warn('Source not found for selected layer');
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
const geojsonString = await getGeoJSONDataFromLayerSource(source, model);
|
|
841
|
+
if (!geojsonString) {
|
|
842
|
+
console.warn('Failed to generate GeoJSON data');
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
downloadFile(geojsonString, `${exportFileName}.geojson`, 'application/geo+json');
|
|
846
|
+
};
|
|
847
|
+
const { filePath, layerId, exportFileName } = args !== null && args !== void 0 ? args : {};
|
|
848
|
+
if (filePath && layerId && exportFileName) {
|
|
849
|
+
const widget = tracker.find(w => w.model.filePath === filePath);
|
|
850
|
+
if (!widget || !widget.model.sharedModel.editable) {
|
|
851
|
+
console.warn('Invalid or non-editable document');
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
const model = widget.model;
|
|
855
|
+
const layer = model.getLayer(layerId);
|
|
856
|
+
if (!layer) {
|
|
857
|
+
console.warn('Layer not found');
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
return exportLayer(model, layer, exportFileName);
|
|
861
|
+
}
|
|
590
862
|
const selectedLayer = getSingleSelectedLayer(tracker);
|
|
591
|
-
|
|
863
|
+
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
864
|
+
if (!selectedLayer || !model) {
|
|
592
865
|
return;
|
|
593
866
|
}
|
|
594
|
-
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
595
|
-
const sources = (_b = model.sharedModel.sources) !== null && _b !== void 0 ? _b : {};
|
|
596
867
|
const exportSchema = Object.assign({}, formSchemaRegistry
|
|
597
868
|
.getSchemas()
|
|
598
869
|
.get('ExportGeoJSONSchema'));
|
|
@@ -614,21 +885,31 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
614
885
|
if (!formValues || !selectedLayer.parameters) {
|
|
615
886
|
return;
|
|
616
887
|
}
|
|
617
|
-
|
|
618
|
-
const sourceId = selectedLayer.parameters.source;
|
|
619
|
-
const source = sources[sourceId];
|
|
620
|
-
const geojsonString = await getGeoJSONDataFromLayerSource(source, model);
|
|
621
|
-
if (!geojsonString) {
|
|
622
|
-
return;
|
|
623
|
-
}
|
|
624
|
-
downloadFile(geojsonString, `${exportFileName}.geojson`, 'application/geo+json');
|
|
888
|
+
return exportLayer(model, selectedLayer, formValues.exportFileName);
|
|
625
889
|
},
|
|
626
890
|
});
|
|
627
891
|
commands.addCommand(CommandIDs.getGeolocation, {
|
|
628
892
|
label: trans.__('Center on Geolocation'),
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
893
|
+
caption: "Center the map on the user's current geolocation.",
|
|
894
|
+
describedBy: {
|
|
895
|
+
args: {
|
|
896
|
+
type: 'object',
|
|
897
|
+
properties: {
|
|
898
|
+
filePath: { type: 'string' },
|
|
899
|
+
},
|
|
900
|
+
},
|
|
901
|
+
},
|
|
902
|
+
execute: async (args) => {
|
|
903
|
+
const { filePath } = args !== null && args !== void 0 ? args : {};
|
|
904
|
+
// Resolve widget once
|
|
905
|
+
const current = filePath
|
|
906
|
+
? tracker.find(w => w.model.filePath === filePath)
|
|
907
|
+
: tracker.currentWidget;
|
|
908
|
+
if (!current) {
|
|
909
|
+
console.warn('No document found');
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
912
|
+
const viewModel = current.model;
|
|
632
913
|
const options = {
|
|
633
914
|
enableHighAccuracy: true,
|
|
634
915
|
timeout: 5000,
|
|
@@ -639,16 +920,14 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
639
920
|
pos.coords.longitude,
|
|
640
921
|
pos.coords.latitude,
|
|
641
922
|
]);
|
|
642
|
-
const
|
|
923
|
+
const jgisLocation = {
|
|
643
924
|
x: location[0],
|
|
644
925
|
y: location[1],
|
|
645
926
|
};
|
|
646
|
-
|
|
647
|
-
viewModel.geolocationChanged.emit(Jgislocation);
|
|
648
|
-
}
|
|
927
|
+
viewModel.geolocationChanged.emit(jgisLocation);
|
|
649
928
|
};
|
|
650
929
|
const error = (err) => {
|
|
651
|
-
console.warn(`
|
|
930
|
+
console.warn(`Geolocation error (${err.code}): ${err.message}`);
|
|
652
931
|
};
|
|
653
932
|
navigator.geolocation.getCurrentPosition(success, error, options);
|
|
654
933
|
},
|
|
@@ -657,6 +936,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
657
936
|
// Panel visibility commands
|
|
658
937
|
commands.addCommand(CommandIDs.toggleLeftPanel, {
|
|
659
938
|
label: trans.__('Toggle Left Panel'),
|
|
939
|
+
caption: 'Toggle the left panel in the current JupyterGIS document.',
|
|
940
|
+
describedBy: {
|
|
941
|
+
args: {
|
|
942
|
+
type: 'object',
|
|
943
|
+
properties: {},
|
|
944
|
+
},
|
|
945
|
+
},
|
|
660
946
|
isEnabled: () => Boolean(tracker.currentWidget),
|
|
661
947
|
isToggled: () => {
|
|
662
948
|
const current = tracker.currentWidget;
|
|
@@ -681,6 +967,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
681
967
|
});
|
|
682
968
|
commands.addCommand(CommandIDs.toggleRightPanel, {
|
|
683
969
|
label: trans.__('Toggle Right Panel'),
|
|
970
|
+
caption: 'Toggle the right panel in the current JupyterGIS document.',
|
|
971
|
+
describedBy: {
|
|
972
|
+
args: {
|
|
973
|
+
type: 'object',
|
|
974
|
+
properties: {},
|
|
975
|
+
},
|
|
976
|
+
},
|
|
684
977
|
isEnabled: () => Boolean(tracker.currentWidget),
|
|
685
978
|
isToggled: () => {
|
|
686
979
|
const current = tracker.currentWidget;
|
|
@@ -706,6 +999,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
706
999
|
// Left panel tabs
|
|
707
1000
|
commands.addCommand(CommandIDs.showLayersTab, {
|
|
708
1001
|
label: trans.__('Show Layers Tab'),
|
|
1002
|
+
caption: 'Show the layers tab in the current JupyterGIS document.',
|
|
1003
|
+
describedBy: {
|
|
1004
|
+
args: {
|
|
1005
|
+
type: 'object',
|
|
1006
|
+
properties: {},
|
|
1007
|
+
},
|
|
1008
|
+
},
|
|
709
1009
|
isEnabled: () => Boolean(tracker.currentWidget),
|
|
710
1010
|
isToggled: () => tracker.currentWidget
|
|
711
1011
|
? !tracker.currentWidget.model.jgisSettings.layersDisabled
|
|
@@ -724,6 +1024,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
724
1024
|
});
|
|
725
1025
|
commands.addCommand(CommandIDs.showStacBrowserTab, {
|
|
726
1026
|
label: trans.__('Show STAC Browser Tab'),
|
|
1027
|
+
caption: 'Show the STAC browser tab in the current JupyterGIS document.',
|
|
1028
|
+
describedBy: {
|
|
1029
|
+
args: {
|
|
1030
|
+
type: 'object',
|
|
1031
|
+
properties: {},
|
|
1032
|
+
},
|
|
1033
|
+
},
|
|
727
1034
|
isEnabled: () => Boolean(tracker.currentWidget),
|
|
728
1035
|
isToggled: () => tracker.currentWidget
|
|
729
1036
|
? !tracker.currentWidget.model.jgisSettings.stacBrowserDisabled
|
|
@@ -742,6 +1049,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
742
1049
|
});
|
|
743
1050
|
commands.addCommand(CommandIDs.showFiltersTab, {
|
|
744
1051
|
label: trans.__('Show Filters Tab'),
|
|
1052
|
+
caption: 'Show the filters tab in the current JupyterGIS document.',
|
|
1053
|
+
describedBy: {
|
|
1054
|
+
args: {
|
|
1055
|
+
type: 'object',
|
|
1056
|
+
properties: {},
|
|
1057
|
+
},
|
|
1058
|
+
},
|
|
745
1059
|
isEnabled: () => Boolean(tracker.currentWidget),
|
|
746
1060
|
isToggled: () => tracker.currentWidget
|
|
747
1061
|
? !tracker.currentWidget.model.jgisSettings.filtersDisabled
|
|
@@ -761,6 +1075,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
761
1075
|
// Right panel tabs
|
|
762
1076
|
commands.addCommand(CommandIDs.showObjectPropertiesTab, {
|
|
763
1077
|
label: trans.__('Show Object Properties Tab'),
|
|
1078
|
+
caption: 'Show the object properties tab in the current JupyterGIS document.',
|
|
1079
|
+
describedBy: {
|
|
1080
|
+
args: {
|
|
1081
|
+
type: 'object',
|
|
1082
|
+
properties: {},
|
|
1083
|
+
},
|
|
1084
|
+
},
|
|
764
1085
|
isEnabled: () => Boolean(tracker.currentWidget),
|
|
765
1086
|
isToggled: () => tracker.currentWidget
|
|
766
1087
|
? !tracker.currentWidget.model.jgisSettings.objectPropertiesDisabled
|
|
@@ -779,6 +1100,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
779
1100
|
});
|
|
780
1101
|
commands.addCommand(CommandIDs.showAnnotationsTab, {
|
|
781
1102
|
label: trans.__('Show Annotations Tab'),
|
|
1103
|
+
caption: 'Show the annotations tab in the current JupyterGIS document.',
|
|
1104
|
+
describedBy: {
|
|
1105
|
+
args: {
|
|
1106
|
+
type: 'object',
|
|
1107
|
+
properties: {},
|
|
1108
|
+
},
|
|
1109
|
+
},
|
|
782
1110
|
isEnabled: () => Boolean(tracker.currentWidget),
|
|
783
1111
|
isToggled: () => tracker.currentWidget
|
|
784
1112
|
? !tracker.currentWidget.model.jgisSettings.annotationsDisabled
|
|
@@ -797,6 +1125,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
797
1125
|
});
|
|
798
1126
|
commands.addCommand(CommandIDs.showIdentifyPanelTab, {
|
|
799
1127
|
label: trans.__('Show Identify Panel Tab'),
|
|
1128
|
+
caption: 'Show the identify panel tab in the current JupyterGIS document.',
|
|
1129
|
+
describedBy: {
|
|
1130
|
+
args: {
|
|
1131
|
+
type: 'object',
|
|
1132
|
+
properties: {},
|
|
1133
|
+
},
|
|
1134
|
+
},
|
|
800
1135
|
isEnabled: () => Boolean(tracker.currentWidget),
|
|
801
1136
|
isToggled: () => tracker.currentWidget
|
|
802
1137
|
? !tracker.currentWidget.model.jgisSettings.identifyDisabled
|
|
@@ -871,6 +1206,63 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
871
1206
|
current.model.setOptions(Object.assign(Object.assign({}, currentOptions), { storyMapPresentationMode: !currentOptions.storyMapPresentationMode }));
|
|
872
1207
|
commands.notifyCommandChanged(CommandIDs.toggleStoryPresentationMode);
|
|
873
1208
|
} }, icons.get(CommandIDs.toggleStoryPresentationMode)));
|
|
1209
|
+
/* Needs to be enabled in Specta mode, so add without Specta-aware wrapper */
|
|
1210
|
+
originalAddCommand(CommandIDs.storyPrev, {
|
|
1211
|
+
label: trans.__('Previous Story Segment'),
|
|
1212
|
+
isEnabled: () => {
|
|
1213
|
+
var _a, _b;
|
|
1214
|
+
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
1215
|
+
const storySegments = (_b = model === null || model === void 0 ? void 0 : model.getSelectedStory().story) === null || _b === void 0 ? void 0 : _b.storySegments;
|
|
1216
|
+
if (!model ||
|
|
1217
|
+
model.jgisSettings.storyMapsDisabled ||
|
|
1218
|
+
!storySegments ||
|
|
1219
|
+
storySegments.length < 1) {
|
|
1220
|
+
return false;
|
|
1221
|
+
}
|
|
1222
|
+
if (!model.isSpectaMode()) {
|
|
1223
|
+
return false;
|
|
1224
|
+
}
|
|
1225
|
+
return model.getCurrentSegmentIndex() > 0;
|
|
1226
|
+
},
|
|
1227
|
+
execute: () => {
|
|
1228
|
+
var _a, _b;
|
|
1229
|
+
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
1230
|
+
if (!model) {
|
|
1231
|
+
return;
|
|
1232
|
+
}
|
|
1233
|
+
const current = (_b = model.getCurrentSegmentIndex()) !== null && _b !== void 0 ? _b : 0;
|
|
1234
|
+
model.setCurrentSegmentIndex(current - 1);
|
|
1235
|
+
},
|
|
1236
|
+
});
|
|
1237
|
+
originalAddCommand(CommandIDs.storyNext, {
|
|
1238
|
+
label: trans.__('Next Story Segment'),
|
|
1239
|
+
isEnabled: () => {
|
|
1240
|
+
var _a, _b, _c;
|
|
1241
|
+
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
1242
|
+
const storySegments = (_b = model === null || model === void 0 ? void 0 : model.getSelectedStory().story) === null || _b === void 0 ? void 0 : _b.storySegments;
|
|
1243
|
+
if (!model ||
|
|
1244
|
+
model.jgisSettings.storyMapsDisabled ||
|
|
1245
|
+
!storySegments ||
|
|
1246
|
+
storySegments.length < 1) {
|
|
1247
|
+
return false;
|
|
1248
|
+
}
|
|
1249
|
+
const isSpecta = model.isSpectaMode();
|
|
1250
|
+
if (!isSpecta) {
|
|
1251
|
+
return false;
|
|
1252
|
+
}
|
|
1253
|
+
const current = (_c = model.getCurrentSegmentIndex()) !== null && _c !== void 0 ? _c : 0;
|
|
1254
|
+
return current < storySegments.length - 1;
|
|
1255
|
+
},
|
|
1256
|
+
execute: () => {
|
|
1257
|
+
var _a, _b;
|
|
1258
|
+
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
1259
|
+
if (!model) {
|
|
1260
|
+
return;
|
|
1261
|
+
}
|
|
1262
|
+
const current = (_b = model.getCurrentSegmentIndex()) !== null && _b !== void 0 ? _b : 0;
|
|
1263
|
+
model.setCurrentSegmentIndex(current + 1);
|
|
1264
|
+
},
|
|
1265
|
+
});
|
|
874
1266
|
loadKeybindings(commands, keybindings);
|
|
875
1267
|
}
|
|
876
1268
|
var Private;
|
|
@@ -964,21 +1356,6 @@ var Private;
|
|
|
964
1356
|
model.setEditingItem(item.type, itemId);
|
|
965
1357
|
}
|
|
966
1358
|
Private.renameSelectedItem = renameSelectedItem;
|
|
967
|
-
function removeSelectedSources(model) {
|
|
968
|
-
var _a, _b;
|
|
969
|
-
const selected = (_b = (_a = model === null || model === void 0 ? void 0 : model.localState) === null || _a === void 0 ? void 0 : _a.selected) === null || _b === void 0 ? void 0 : _b.value;
|
|
970
|
-
if (!selected || !model) {
|
|
971
|
-
return;
|
|
972
|
-
}
|
|
973
|
-
for (const id of Object.keys(selected)) {
|
|
974
|
-
if (model.getLayersBySource(id).length > 0) {
|
|
975
|
-
showErrorMessage('Remove source error', 'The source is used by a layer.');
|
|
976
|
-
continue;
|
|
977
|
-
}
|
|
978
|
-
model.sharedModel.removeSource(id);
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
Private.removeSelectedSources = removeSelectedSources;
|
|
982
1359
|
function executeConsole(tracker) {
|
|
983
1360
|
const current = tracker.currentWidget;
|
|
984
1361
|
if (!current || !(current instanceof JupyterGISDocumentWidget)) {
|
|
@@ -1003,4 +1380,25 @@ var Private;
|
|
|
1003
1380
|
await current.content.toggleConsole(current.model.filePath);
|
|
1004
1381
|
}
|
|
1005
1382
|
Private.toggleConsole = toggleConsole;
|
|
1383
|
+
function generateCopyName(baseName, model) {
|
|
1384
|
+
const layers = model.getLayers();
|
|
1385
|
+
const existingNames = Object.values(layers).map(l => l.name);
|
|
1386
|
+
const copyRegex = /(.*?)( Copy(_\d+)?)?$/;
|
|
1387
|
+
const match = baseName.match(copyRegex);
|
|
1388
|
+
const cleanBase = match ? match[1].trim() : baseName;
|
|
1389
|
+
const firstCopyName = `${cleanBase} Copy`;
|
|
1390
|
+
if (!existingNames.includes(firstCopyName)) {
|
|
1391
|
+
return firstCopyName;
|
|
1392
|
+
}
|
|
1393
|
+
const pattern = new RegExp(`^${cleanBase} Copy_(\\d+)$`);
|
|
1394
|
+
const numbers = existingNames
|
|
1395
|
+
.map(name => {
|
|
1396
|
+
const m = name.match(pattern);
|
|
1397
|
+
return m ? parseInt(m[1], 10) : null;
|
|
1398
|
+
})
|
|
1399
|
+
.filter((n) => n !== null);
|
|
1400
|
+
const nextNumber = numbers.length > 0 ? Math.max(...numbers) + 1 : 1;
|
|
1401
|
+
return `${cleanBase} Copy_${nextNumber}`;
|
|
1402
|
+
}
|
|
1403
|
+
Private.generateCopyName = generateCopyName;
|
|
1006
1404
|
})(Private || (Private = {}));
|