@jupytergis/base 0.13.3 → 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 +523 -117
- package/lib/commands/operationCommands.d.ts +22 -0
- package/lib/commands/operationCommands.js +305 -0
- package/lib/constants.js +9 -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 +62 -35
- 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/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,7 +468,7 @@ 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
|
*/
|
|
@@ -389,25 +500,116 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
389
500
|
}
|
|
390
501
|
await Private.removeSelectedItems(model);
|
|
391
502
|
} }, icons.get(CommandIDs.removeSelected)));
|
|
392
|
-
commands.addCommand(CommandIDs.
|
|
393
|
-
label:
|
|
394
|
-
|
|
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');
|
|
513
|
+
},
|
|
514
|
+
execute: () => {
|
|
395
515
|
var _a, _b, _c;
|
|
396
516
|
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
397
|
-
const
|
|
398
|
-
|
|
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;
|
|
399
568
|
if (!selectedLayers) {
|
|
400
569
|
return;
|
|
401
570
|
}
|
|
402
|
-
|
|
571
|
+
const targetGroup = args === null || args === void 0 ? void 0 : args.label;
|
|
572
|
+
model.moveItemsToGroup(Object.keys(selectedLayers), targetGroup);
|
|
403
573
|
},
|
|
404
574
|
});
|
|
405
|
-
commands.addCommand(CommandIDs.
|
|
406
|
-
label: trans.__('Move
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
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;
|
|
411
613
|
if (!selectedLayers) {
|
|
412
614
|
return;
|
|
413
615
|
}
|
|
@@ -456,28 +658,16 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
456
658
|
model.addNewLayerGroup(selectedLayers, newLayerGroup);
|
|
457
659
|
},
|
|
458
660
|
});
|
|
459
|
-
/**
|
|
460
|
-
* Source actions
|
|
461
|
-
*/
|
|
462
|
-
commands.addCommand(CommandIDs.renameSource, {
|
|
463
|
-
label: trans.__('Rename Source'),
|
|
464
|
-
execute: async () => {
|
|
465
|
-
var _a;
|
|
466
|
-
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
467
|
-
await Private.renameSelectedItem(model);
|
|
468
|
-
},
|
|
469
|
-
});
|
|
470
|
-
commands.addCommand(CommandIDs.removeSource, {
|
|
471
|
-
label: trans.__('Remove Source'),
|
|
472
|
-
execute: () => {
|
|
473
|
-
var _a;
|
|
474
|
-
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
475
|
-
Private.removeSelectedSources(model);
|
|
476
|
-
},
|
|
477
|
-
});
|
|
478
661
|
// Console commands
|
|
479
662
|
commands.addCommand(CommandIDs.toggleConsole, {
|
|
480
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
|
+
},
|
|
481
671
|
isVisible: () => tracker.currentWidget instanceof JupyterGISDocumentWidget,
|
|
482
672
|
isEnabled: () => {
|
|
483
673
|
return tracker.currentWidget
|
|
@@ -500,6 +690,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
500
690
|
});
|
|
501
691
|
commands.addCommand(CommandIDs.executeConsole, {
|
|
502
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
|
+
},
|
|
503
700
|
isVisible: () => tracker.currentWidget instanceof JupyterGISDocumentWidget,
|
|
504
701
|
isEnabled: () => {
|
|
505
702
|
return tracker.currentWidget
|
|
@@ -510,6 +707,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
510
707
|
});
|
|
511
708
|
commands.addCommand(CommandIDs.removeConsole, {
|
|
512
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
|
+
},
|
|
513
717
|
isVisible: () => tracker.currentWidget instanceof JupyterGISDocumentWidget,
|
|
514
718
|
isEnabled: () => {
|
|
515
719
|
return tracker.currentWidget
|
|
@@ -520,6 +724,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
520
724
|
});
|
|
521
725
|
commands.addCommand(CommandIDs.invokeCompleter, {
|
|
522
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
|
+
},
|
|
523
734
|
isVisible: () => tracker.currentWidget instanceof JupyterGISDocumentWidget,
|
|
524
735
|
execute: () => {
|
|
525
736
|
var _a;
|
|
@@ -537,6 +748,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
537
748
|
});
|
|
538
749
|
commands.addCommand(CommandIDs.selectCompleter, {
|
|
539
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
|
+
},
|
|
540
758
|
isVisible: () => tracker.currentWidget instanceof JupyterGISDocumentWidget,
|
|
541
759
|
execute: () => {
|
|
542
760
|
var _a;
|
|
@@ -554,37 +772,98 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
554
772
|
});
|
|
555
773
|
commands.addCommand(CommandIDs.zoomToLayer, {
|
|
556
774
|
label: trans.__('Zoom to Layer'),
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
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) {
|
|
561
793
|
return;
|
|
562
794
|
}
|
|
563
|
-
const model =
|
|
564
|
-
|
|
795
|
+
const model = current.model;
|
|
796
|
+
if (filePath && layerId) {
|
|
797
|
+
model.centerOnPosition(layerId);
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
const selectedItems = (_b = (_a = model.localState) === null || _a === void 0 ? void 0 : _a.selected) === null || _b === void 0 ? void 0 : _b.value;
|
|
565
801
|
if (!selectedItems) {
|
|
566
802
|
return;
|
|
567
803
|
}
|
|
568
|
-
const
|
|
569
|
-
model.centerOnPosition(
|
|
804
|
+
const selLayerId = Object.keys(selectedItems)[0];
|
|
805
|
+
model.centerOnPosition(selLayerId);
|
|
570
806
|
},
|
|
571
807
|
});
|
|
572
808
|
commands.addCommand(CommandIDs.downloadGeoJSON, {
|
|
573
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
|
+
},
|
|
574
821
|
isEnabled: () => {
|
|
575
|
-
const
|
|
576
|
-
return
|
|
577
|
-
? ['VectorLayer', 'ShapefileLayer'].includes(selectedLayer.type)
|
|
578
|
-
: false;
|
|
822
|
+
const layer = getSingleSelectedLayer(tracker);
|
|
823
|
+
return !!layer && ['VectorLayer', 'ShapefileLayer'].includes(layer.type);
|
|
579
824
|
},
|
|
580
|
-
execute: async () => {
|
|
581
|
-
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
|
+
}
|
|
582
862
|
const selectedLayer = getSingleSelectedLayer(tracker);
|
|
583
|
-
|
|
863
|
+
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
864
|
+
if (!selectedLayer || !model) {
|
|
584
865
|
return;
|
|
585
866
|
}
|
|
586
|
-
const model = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model;
|
|
587
|
-
const sources = (_b = model.sharedModel.sources) !== null && _b !== void 0 ? _b : {};
|
|
588
867
|
const exportSchema = Object.assign({}, formSchemaRegistry
|
|
589
868
|
.getSchemas()
|
|
590
869
|
.get('ExportGeoJSONSchema'));
|
|
@@ -606,21 +885,31 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
606
885
|
if (!formValues || !selectedLayer.parameters) {
|
|
607
886
|
return;
|
|
608
887
|
}
|
|
609
|
-
|
|
610
|
-
const sourceId = selectedLayer.parameters.source;
|
|
611
|
-
const source = sources[sourceId];
|
|
612
|
-
const geojsonString = await getGeoJSONDataFromLayerSource(source, model);
|
|
613
|
-
if (!geojsonString) {
|
|
614
|
-
return;
|
|
615
|
-
}
|
|
616
|
-
downloadFile(geojsonString, `${exportFileName}.geojson`, 'application/geo+json');
|
|
888
|
+
return exportLayer(model, selectedLayer, formValues.exportFileName);
|
|
617
889
|
},
|
|
618
890
|
});
|
|
619
891
|
commands.addCommand(CommandIDs.getGeolocation, {
|
|
620
892
|
label: trans.__('Center on Geolocation'),
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
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;
|
|
624
913
|
const options = {
|
|
625
914
|
enableHighAccuracy: true,
|
|
626
915
|
timeout: 5000,
|
|
@@ -631,16 +920,14 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
631
920
|
pos.coords.longitude,
|
|
632
921
|
pos.coords.latitude,
|
|
633
922
|
]);
|
|
634
|
-
const
|
|
923
|
+
const jgisLocation = {
|
|
635
924
|
x: location[0],
|
|
636
925
|
y: location[1],
|
|
637
926
|
};
|
|
638
|
-
|
|
639
|
-
viewModel.geolocationChanged.emit(Jgislocation);
|
|
640
|
-
}
|
|
927
|
+
viewModel.geolocationChanged.emit(jgisLocation);
|
|
641
928
|
};
|
|
642
929
|
const error = (err) => {
|
|
643
|
-
console.warn(`
|
|
930
|
+
console.warn(`Geolocation error (${err.code}): ${err.message}`);
|
|
644
931
|
};
|
|
645
932
|
navigator.geolocation.getCurrentPosition(success, error, options);
|
|
646
933
|
},
|
|
@@ -649,6 +936,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
649
936
|
// Panel visibility commands
|
|
650
937
|
commands.addCommand(CommandIDs.toggleLeftPanel, {
|
|
651
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
|
+
},
|
|
652
946
|
isEnabled: () => Boolean(tracker.currentWidget),
|
|
653
947
|
isToggled: () => {
|
|
654
948
|
const current = tracker.currentWidget;
|
|
@@ -673,6 +967,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
673
967
|
});
|
|
674
968
|
commands.addCommand(CommandIDs.toggleRightPanel, {
|
|
675
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
|
+
},
|
|
676
977
|
isEnabled: () => Boolean(tracker.currentWidget),
|
|
677
978
|
isToggled: () => {
|
|
678
979
|
const current = tracker.currentWidget;
|
|
@@ -698,6 +999,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
698
999
|
// Left panel tabs
|
|
699
1000
|
commands.addCommand(CommandIDs.showLayersTab, {
|
|
700
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
|
+
},
|
|
701
1009
|
isEnabled: () => Boolean(tracker.currentWidget),
|
|
702
1010
|
isToggled: () => tracker.currentWidget
|
|
703
1011
|
? !tracker.currentWidget.model.jgisSettings.layersDisabled
|
|
@@ -716,6 +1024,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
716
1024
|
});
|
|
717
1025
|
commands.addCommand(CommandIDs.showStacBrowserTab, {
|
|
718
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
|
+
},
|
|
719
1034
|
isEnabled: () => Boolean(tracker.currentWidget),
|
|
720
1035
|
isToggled: () => tracker.currentWidget
|
|
721
1036
|
? !tracker.currentWidget.model.jgisSettings.stacBrowserDisabled
|
|
@@ -734,6 +1049,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
734
1049
|
});
|
|
735
1050
|
commands.addCommand(CommandIDs.showFiltersTab, {
|
|
736
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
|
+
},
|
|
737
1059
|
isEnabled: () => Boolean(tracker.currentWidget),
|
|
738
1060
|
isToggled: () => tracker.currentWidget
|
|
739
1061
|
? !tracker.currentWidget.model.jgisSettings.filtersDisabled
|
|
@@ -753,6 +1075,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
753
1075
|
// Right panel tabs
|
|
754
1076
|
commands.addCommand(CommandIDs.showObjectPropertiesTab, {
|
|
755
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
|
+
},
|
|
756
1085
|
isEnabled: () => Boolean(tracker.currentWidget),
|
|
757
1086
|
isToggled: () => tracker.currentWidget
|
|
758
1087
|
? !tracker.currentWidget.model.jgisSettings.objectPropertiesDisabled
|
|
@@ -771,6 +1100,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
771
1100
|
});
|
|
772
1101
|
commands.addCommand(CommandIDs.showAnnotationsTab, {
|
|
773
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
|
+
},
|
|
774
1110
|
isEnabled: () => Boolean(tracker.currentWidget),
|
|
775
1111
|
isToggled: () => tracker.currentWidget
|
|
776
1112
|
? !tracker.currentWidget.model.jgisSettings.annotationsDisabled
|
|
@@ -789,6 +1125,13 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
789
1125
|
});
|
|
790
1126
|
commands.addCommand(CommandIDs.showIdentifyPanelTab, {
|
|
791
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
|
+
},
|
|
792
1135
|
isEnabled: () => Boolean(tracker.currentWidget),
|
|
793
1136
|
isToggled: () => tracker.currentWidget
|
|
794
1137
|
? !tracker.currentWidget.model.jgisSettings.identifyDisabled
|
|
@@ -863,6 +1206,63 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
863
1206
|
current.model.setOptions(Object.assign(Object.assign({}, currentOptions), { storyMapPresentationMode: !currentOptions.storyMapPresentationMode }));
|
|
864
1207
|
commands.notifyCommandChanged(CommandIDs.toggleStoryPresentationMode);
|
|
865
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
|
+
});
|
|
866
1266
|
loadKeybindings(commands, keybindings);
|
|
867
1267
|
}
|
|
868
1268
|
var Private;
|
|
@@ -956,21 +1356,6 @@ var Private;
|
|
|
956
1356
|
model.setEditingItem(item.type, itemId);
|
|
957
1357
|
}
|
|
958
1358
|
Private.renameSelectedItem = renameSelectedItem;
|
|
959
|
-
function removeSelectedSources(model) {
|
|
960
|
-
var _a, _b;
|
|
961
|
-
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;
|
|
962
|
-
if (!selected || !model) {
|
|
963
|
-
return;
|
|
964
|
-
}
|
|
965
|
-
for (const id of Object.keys(selected)) {
|
|
966
|
-
if (model.getLayersBySource(id).length > 0) {
|
|
967
|
-
showErrorMessage('Remove source error', 'The source is used by a layer.');
|
|
968
|
-
continue;
|
|
969
|
-
}
|
|
970
|
-
model.sharedModel.removeSource(id);
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
Private.removeSelectedSources = removeSelectedSources;
|
|
974
1359
|
function executeConsole(tracker) {
|
|
975
1360
|
const current = tracker.currentWidget;
|
|
976
1361
|
if (!current || !(current instanceof JupyterGISDocumentWidget)) {
|
|
@@ -995,4 +1380,25 @@ var Private;
|
|
|
995
1380
|
await current.content.toggleConsole(current.model.filePath);
|
|
996
1381
|
}
|
|
997
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;
|
|
998
1404
|
})(Private || (Private = {}));
|