umap-project 2.8.1__py3-none-any.whl → 2.9.0__py3-none-any.whl
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.
Potentially problematic release.
This version of umap-project might be problematic. Click here for more details.
- umap/__init__.py +1 -1
- umap/admin.py +15 -2
- umap/asgi.py +12 -7
- umap/context_processors.py +1 -0
- umap/locale/br/LC_MESSAGES/django.mo +0 -0
- umap/locale/br/LC_MESSAGES/django.po +111 -67
- umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
- umap/locale/cs_CZ/LC_MESSAGES/django.po +110 -66
- umap/locale/el/LC_MESSAGES/django.mo +0 -0
- umap/locale/el/LC_MESSAGES/django.po +129 -85
- umap/locale/en/LC_MESSAGES/django.po +103 -60
- umap/locale/es/LC_MESSAGES/django.mo +0 -0
- umap/locale/es/LC_MESSAGES/django.po +114 -69
- umap/locale/fr/LC_MESSAGES/django.mo +0 -0
- umap/locale/fr/LC_MESSAGES/django.po +105 -61
- umap/locale/gl/LC_MESSAGES/django.mo +0 -0
- umap/locale/gl/LC_MESSAGES/django.po +216 -171
- umap/locale/hu/LC_MESSAGES/django.mo +0 -0
- umap/locale/hu/LC_MESSAGES/django.po +10 -10
- umap/locale/it/LC_MESSAGES/django.mo +0 -0
- umap/locale/it/LC_MESSAGES/django.po +142 -98
- umap/locale/nl/LC_MESSAGES/django.mo +0 -0
- umap/locale/nl/LC_MESSAGES/django.po +196 -151
- umap/locale/pt/LC_MESSAGES/django.mo +0 -0
- umap/locale/pt/LC_MESSAGES/django.po +115 -71
- umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
- umap/locale/zh_TW/LC_MESSAGES/django.po +109 -65
- umap/management/commands/empty_trash.py +12 -1
- umap/migrations/0026_datalayer_modified_at_datalayer_share_status.py +26 -0
- umap/models.py +43 -13
- umap/settings/base.py +5 -2
- umap/static/umap/base.css +5 -2
- umap/static/umap/content.css +2 -22
- umap/static/umap/css/bar.css +39 -10
- umap/static/umap/css/contextmenu.css +14 -2
- umap/static/umap/css/form.css +33 -39
- umap/static/umap/css/icon.css +47 -5
- umap/static/umap/css/panel.css +20 -2
- umap/static/umap/css/popup.css +0 -1
- umap/static/umap/css/tooltip.css +33 -31
- umap/static/umap/img/16-white.svg +5 -3
- umap/static/umap/img/16.svg +1 -1
- umap/static/umap/img/24-white.svg +17 -16
- umap/static/umap/img/24.svg +29 -18
- umap/static/umap/img/providers/bitbucket.png +0 -0
- umap/static/umap/img/providers/github.png +0 -0
- umap/static/umap/img/providers/keycloak.png +0 -0
- umap/static/umap/img/providers/openstreetmap-oauth2.png +0 -0
- umap/static/umap/img/providers/twitter-oauth2.png +0 -0
- umap/static/umap/img/source/16-white.svg +6 -4
- umap/static/umap/img/source/16.svg +1 -1
- umap/static/umap/img/source/24-white.svg +20 -18
- umap/static/umap/img/source/24.svg +30 -19
- umap/static/umap/js/components/alerts/alert.js +4 -1
- umap/static/umap/js/modules/browser.js +8 -8
- umap/static/umap/js/modules/caption.js +30 -7
- umap/static/umap/js/modules/data/features.js +101 -56
- umap/static/umap/js/modules/data/layer.js +108 -83
- umap/static/umap/js/modules/form/builder.js +242 -0
- umap/static/umap/js/modules/form/fields.js +1346 -0
- umap/static/umap/js/modules/formatter.js +9 -8
- umap/static/umap/js/modules/help.js +20 -24
- umap/static/umap/js/modules/importer.js +6 -3
- umap/static/umap/js/modules/permissions.js +11 -6
- umap/static/umap/js/modules/rendering/icon.js +5 -1
- umap/static/umap/js/modules/rendering/layers/classified.js +12 -8
- umap/static/umap/js/modules/rendering/layers/cluster.js +11 -1
- umap/static/umap/js/modules/rendering/map.js +1 -23
- umap/static/umap/js/modules/rendering/ui.js +20 -38
- umap/static/umap/js/modules/rules.js +3 -2
- umap/static/umap/js/modules/saving.js +5 -0
- umap/static/umap/js/modules/schema.js +8 -6
- umap/static/umap/js/modules/share.js +3 -3
- umap/static/umap/js/modules/sync/engine.js +56 -26
- umap/static/umap/js/modules/sync/updaters.js +15 -6
- umap/static/umap/js/modules/sync/websocket.js +50 -37
- umap/static/umap/js/modules/tableeditor.js +3 -2
- umap/static/umap/js/modules/ui/bar.js +101 -9
- umap/static/umap/js/modules/ui/base.js +7 -24
- umap/static/umap/js/modules/ui/contextmenu.js +9 -2
- umap/static/umap/js/modules/ui/panel.js +5 -1
- umap/static/umap/js/modules/ui/tooltip.js +19 -11
- umap/static/umap/js/modules/umap.js +124 -71
- umap/static/umap/js/modules/utils.js +196 -12
- umap/static/umap/js/umap.controls.js +12 -354
- umap/static/umap/locale/am_ET.js +17 -5
- umap/static/umap/locale/am_ET.json +17 -5
- umap/static/umap/locale/ar.js +17 -5
- umap/static/umap/locale/ar.json +17 -5
- umap/static/umap/locale/ast.js +17 -5
- umap/static/umap/locale/ast.json +17 -5
- umap/static/umap/locale/bg.js +17 -5
- umap/static/umap/locale/bg.json +17 -5
- umap/static/umap/locale/br.js +33 -20
- umap/static/umap/locale/br.json +33 -20
- umap/static/umap/locale/ca.js +17 -5
- umap/static/umap/locale/ca.json +17 -5
- umap/static/umap/locale/cs_CZ.js +15 -5
- umap/static/umap/locale/cs_CZ.json +15 -5
- umap/static/umap/locale/da.js +17 -5
- umap/static/umap/locale/da.json +17 -5
- umap/static/umap/locale/de.js +17 -5
- umap/static/umap/locale/de.json +17 -5
- umap/static/umap/locale/el.js +63 -51
- umap/static/umap/locale/el.json +63 -51
- umap/static/umap/locale/en.js +15 -5
- umap/static/umap/locale/en.json +15 -5
- umap/static/umap/locale/en_US.json +17 -5
- umap/static/umap/locale/es.js +25 -13
- umap/static/umap/locale/es.json +25 -13
- umap/static/umap/locale/et.js +17 -5
- umap/static/umap/locale/et.json +17 -5
- umap/static/umap/locale/eu.js +17 -5
- umap/static/umap/locale/eu.json +17 -5
- umap/static/umap/locale/fa_IR.js +17 -5
- umap/static/umap/locale/fa_IR.json +17 -5
- umap/static/umap/locale/fi.js +17 -5
- umap/static/umap/locale/fi.json +17 -5
- umap/static/umap/locale/fr.js +16 -6
- umap/static/umap/locale/fr.json +16 -6
- umap/static/umap/locale/gl.js +357 -345
- umap/static/umap/locale/gl.json +357 -345
- umap/static/umap/locale/he.js +17 -5
- umap/static/umap/locale/he.json +17 -5
- umap/static/umap/locale/hr.js +17 -5
- umap/static/umap/locale/hr.json +17 -5
- umap/static/umap/locale/hu.js +39 -27
- umap/static/umap/locale/hu.json +39 -27
- umap/static/umap/locale/id.js +17 -5
- umap/static/umap/locale/id.json +17 -5
- umap/static/umap/locale/is.js +17 -5
- umap/static/umap/locale/is.json +17 -5
- umap/static/umap/locale/it.js +125 -113
- umap/static/umap/locale/it.json +125 -113
- umap/static/umap/locale/ja.js +17 -5
- umap/static/umap/locale/ja.json +17 -5
- umap/static/umap/locale/ko.js +17 -5
- umap/static/umap/locale/ko.json +17 -5
- umap/static/umap/locale/lt.js +17 -5
- umap/static/umap/locale/lt.json +17 -5
- umap/static/umap/locale/ms.js +17 -5
- umap/static/umap/locale/ms.json +17 -5
- umap/static/umap/locale/nl.js +132 -119
- umap/static/umap/locale/nl.json +132 -119
- umap/static/umap/locale/no.js +17 -5
- umap/static/umap/locale/no.json +17 -5
- umap/static/umap/locale/pl.js +17 -5
- umap/static/umap/locale/pl.json +17 -5
- umap/static/umap/locale/pl_PL.json +17 -5
- umap/static/umap/locale/pt.js +38 -25
- umap/static/umap/locale/pt.json +38 -25
- umap/static/umap/locale/pt_BR.js +17 -5
- umap/static/umap/locale/pt_BR.json +17 -5
- umap/static/umap/locale/pt_PT.js +17 -5
- umap/static/umap/locale/pt_PT.json +17 -5
- umap/static/umap/locale/ro.js +17 -5
- umap/static/umap/locale/ro.json +17 -5
- umap/static/umap/locale/ru.js +17 -5
- umap/static/umap/locale/ru.json +17 -5
- umap/static/umap/locale/sk_SK.js +17 -5
- umap/static/umap/locale/sk_SK.json +17 -5
- umap/static/umap/locale/sl.js +17 -5
- umap/static/umap/locale/sl.json +17 -5
- umap/static/umap/locale/sr.js +17 -5
- umap/static/umap/locale/sr.json +17 -5
- umap/static/umap/locale/sv.js +17 -5
- umap/static/umap/locale/sv.json +17 -5
- umap/static/umap/locale/th_TH.js +17 -5
- umap/static/umap/locale/th_TH.json +17 -5
- umap/static/umap/locale/tr.js +17 -5
- umap/static/umap/locale/tr.json +17 -5
- umap/static/umap/locale/uk_UA.js +17 -5
- umap/static/umap/locale/uk_UA.json +17 -5
- umap/static/umap/locale/vi.js +17 -5
- umap/static/umap/locale/vi.json +17 -5
- umap/static/umap/locale/vi_VN.json +17 -5
- umap/static/umap/locale/zh.js +17 -5
- umap/static/umap/locale/zh.json +17 -5
- umap/static/umap/locale/zh_CN.json +17 -5
- umap/static/umap/locale/zh_TW.Big5.json +17 -5
- umap/static/umap/locale/zh_TW.js +15 -5
- umap/static/umap/locale/zh_TW.json +15 -5
- umap/static/umap/map.css +29 -76
- umap/static/umap/nav.css +6 -3
- umap/static/umap/unittests/utils.js +14 -0
- umap/static/umap/vars.css +3 -0
- umap/static/umap/vendors/dompurify/purify.es.js +138 -354
- umap/static/umap/vendors/dompurify/purify.es.mjs.map +1 -1
- umap/static/umap/vendors/editable/Leaflet.Editable.js +1 -0
- umap/sync/__init__.py +0 -0
- umap/sync/app.py +187 -0
- umap/sync/payloads.py +56 -0
- umap/templates/auth/user_detail.html +4 -0
- umap/templates/auth/user_form.html +9 -6
- umap/templates/auth/user_stars.html +4 -0
- umap/templates/base.html +1 -1
- umap/templates/registration/login.html +2 -5
- umap/templates/umap/about.html +5 -0
- umap/templates/umap/about_summary.html +2 -2
- umap/templates/umap/components/provider.html +8 -0
- umap/templates/umap/content_footer.html +1 -1
- umap/templates/umap/css.html +0 -2
- umap/templates/umap/js.html +0 -4
- umap/templates/umap/map_detail.html +1 -1
- umap/templates/umap/password_change.html +4 -0
- umap/templates/umap/password_change_done.html +4 -0
- umap/templates/umap/search.html +4 -0
- umap/templates/umap/search_bar.html +1 -0
- umap/templates/umap/team_confirm_delete.html +4 -0
- umap/templates/umap/team_detail.html +4 -0
- umap/templates/umap/team_form.html +4 -0
- umap/templates/umap/user_dashboard.html +1 -1
- umap/templates/umap/user_teams.html +4 -0
- umap/tests/base.py +3 -1
- umap/tests/integration/conftest.py +16 -23
- umap/tests/integration/test_anonymous_owned_map.py +2 -2
- umap/tests/integration/test_basics.py +4 -7
- umap/tests/integration/test_caption.py +1 -0
- umap/tests/integration/test_categorized_layer.py +4 -8
- umap/tests/integration/test_choropleth.py +1 -1
- umap/tests/integration/test_conditional_rules.py +3 -3
- umap/tests/integration/test_draw_polygon.py +14 -22
- umap/tests/integration/test_draw_polyline.py +6 -14
- umap/tests/integration/test_edit_datalayer.py +11 -11
- umap/tests/integration/test_edit_map.py +30 -4
- umap/tests/integration/test_edit_marker.py +5 -5
- umap/tests/integration/test_edit_polygon.py +6 -6
- umap/tests/integration/test_features_id_generation.py +2 -6
- umap/tests/integration/test_import.py +115 -29
- umap/tests/integration/test_optimistic_merge.py +1 -0
- umap/tests/integration/test_owned_map.py +1 -1
- umap/tests/integration/test_picto.py +8 -8
- umap/tests/integration/test_save.py +3 -2
- umap/tests/integration/test_star.py +13 -9
- umap/tests/integration/test_tableeditor.py +8 -7
- umap/tests/integration/test_view_marker.py +10 -0
- umap/tests/integration/test_websocket_sync.py +239 -64
- umap/tests/settings.py +2 -0
- umap/tests/test_datalayer.py +2 -3
- umap/tests/test_datalayer_views.py +20 -1
- umap/tests/test_empty_trash.py +10 -3
- umap/tests/test_map_views.py +11 -0
- umap/utils.py +27 -11
- umap/views.py +37 -6
- {umap_project-2.8.1.dist-info → umap_project-2.9.0.dist-info}/METADATA +22 -22
- {umap_project-2.8.1.dist-info → umap_project-2.9.0.dist-info}/RECORD +249 -250
- {umap_project-2.8.1.dist-info → umap_project-2.9.0.dist-info}/WHEEL +1 -1
- umap/management/commands/run_websocket_server.py +0 -23
- umap/settings/local_s3.py +0 -45
- umap/static/umap/bitbucket.png +0 -0
- umap/static/umap/github.png +0 -0
- umap/static/umap/js/umap.forms.js +0 -1242
- umap/static/umap/keycloak.png +0 -0
- umap/static/umap/openstreetmap.png +0 -0
- umap/static/umap/twitter.png +0 -0
- umap/static/umap/vendors/formbuilder/Leaflet.FormBuilder.js +0 -468
- umap/static/umap/vendors/toolbar/leaflet.toolbar.css +0 -1
- umap/static/umap/vendors/toolbar/leaflet.toolbar.js +0 -1
- umap/tests/test_websocket_server.py +0 -22
- umap/websocket_server.py +0 -202
- {umap_project-2.8.1.dist-info → umap_project-2.9.0.dist-info}/entry_points.txt +0 -0
- {umap_project-2.8.1.dist-info → umap_project-2.9.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// Uses U.FormBuilder not available as ESM
|
|
2
|
-
|
|
3
1
|
// FIXME: this module should not depend on Leaflet
|
|
4
2
|
import {
|
|
5
3
|
DomUtil,
|
|
@@ -22,6 +20,7 @@ import { Point, LineString, Polygon } from './features.js'
|
|
|
22
20
|
import TableEditor from '../tableeditor.js'
|
|
23
21
|
import { ServerStored } from '../saving.js'
|
|
24
22
|
import * as Schema from '../schema.js'
|
|
23
|
+
import { MutatingForm } from '../form/builder.js'
|
|
25
24
|
|
|
26
25
|
export const LAYER_TYPES = [
|
|
27
26
|
DefaultLayer,
|
|
@@ -46,8 +45,6 @@ export class DataLayer extends ServerStored {
|
|
|
46
45
|
this._features = {}
|
|
47
46
|
this._geojson = null
|
|
48
47
|
this._propertiesIndex = []
|
|
49
|
-
this._loaded = false // Are layer metadata loaded
|
|
50
|
-
this._dataloaded = false // Are layer data loaded
|
|
51
48
|
|
|
52
49
|
this._leafletMap = leafletMap
|
|
53
50
|
this.parentPane = this._leafletMap.getPane('overlayPane')
|
|
@@ -86,6 +83,7 @@ export class DataLayer extends ServerStored {
|
|
|
86
83
|
this.connectToMap()
|
|
87
84
|
this.permissions = new DataLayerPermissions(this._umap, this)
|
|
88
85
|
|
|
86
|
+
this._needsFetch = this.createdOnServer
|
|
89
87
|
if (!this.createdOnServer) {
|
|
90
88
|
if (this.showAtLoad()) this.show()
|
|
91
89
|
}
|
|
@@ -244,21 +242,22 @@ export class DataLayer extends ServerStored {
|
|
|
244
242
|
}
|
|
245
243
|
|
|
246
244
|
dataChanged() {
|
|
247
|
-
if (!this.
|
|
245
|
+
if (!this.isLoaded()) return
|
|
248
246
|
this._umap.onDataLayersChanged()
|
|
249
247
|
this.layer.dataChanged()
|
|
250
248
|
}
|
|
251
249
|
|
|
252
250
|
fromGeoJSON(geojson, sync = true) {
|
|
251
|
+
if (!geojson) return []
|
|
253
252
|
const features = this.addData(geojson, sync)
|
|
254
253
|
this._geojson = geojson
|
|
254
|
+
this._needsFetch = false
|
|
255
255
|
this.onDataLoaded()
|
|
256
256
|
this.dataChanged()
|
|
257
257
|
return features
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
onDataLoaded() {
|
|
261
|
-
this._dataloaded = true
|
|
262
261
|
this.renderLegend()
|
|
263
262
|
}
|
|
264
263
|
|
|
@@ -268,7 +267,6 @@ export class DataLayer extends ServerStored {
|
|
|
268
267
|
if (geojson._umap_options) this.setOptions(geojson._umap_options)
|
|
269
268
|
if (this.isRemoteLayer()) await this.fetchRemoteData()
|
|
270
269
|
else this.fromGeoJSON(geojson, false)
|
|
271
|
-
this._loaded = true
|
|
272
270
|
}
|
|
273
271
|
|
|
274
272
|
clear() {
|
|
@@ -283,7 +281,9 @@ export class DataLayer extends ServerStored {
|
|
|
283
281
|
}
|
|
284
282
|
|
|
285
283
|
backupData() {
|
|
286
|
-
|
|
284
|
+
if (this._geojson) {
|
|
285
|
+
this._geojson_bk = Utils.CopyJSON(this._geojson)
|
|
286
|
+
}
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
reindex() {
|
|
@@ -303,29 +303,47 @@ export class DataLayer extends ServerStored {
|
|
|
303
303
|
return this.isRemoteLayer() && Boolean(this.options.remoteData?.dynamic)
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
+
async getUrl(url, initialUrl) {
|
|
307
|
+
const response = await this._umap.request.get(url)
|
|
308
|
+
return new Promise((resolve) => {
|
|
309
|
+
if (response?.ok) return resolve(response.text())
|
|
310
|
+
Alert.error(
|
|
311
|
+
translate('Cannot load remote data for layer "{layer}" with url "{url}"', {
|
|
312
|
+
layer: this.getName(),
|
|
313
|
+
url: initialUrl || url,
|
|
314
|
+
})
|
|
315
|
+
)
|
|
316
|
+
})
|
|
317
|
+
}
|
|
318
|
+
|
|
306
319
|
async fetchRemoteData(force) {
|
|
307
320
|
if (!this.isRemoteLayer()) return
|
|
308
|
-
if (!this.hasDynamicData() && this.
|
|
321
|
+
if (!this.hasDynamicData() && this.isLoaded() && !force) return
|
|
309
322
|
if (!this.isVisible()) return
|
|
310
|
-
|
|
323
|
+
// Keep non proxied url for later use in Alert.
|
|
324
|
+
const remoteUrl = this._umap.renderUrl(this.options.remoteData.url)
|
|
325
|
+
let url = remoteUrl
|
|
311
326
|
if (this.options.remoteData.proxy) {
|
|
312
327
|
url = this._umap.proxyUrl(url, this.options.remoteData.ttl)
|
|
313
328
|
}
|
|
314
|
-
|
|
315
|
-
if (response?.ok) {
|
|
329
|
+
return await this.getUrl(url, remoteUrl).then((raw) => {
|
|
316
330
|
this.clear()
|
|
317
331
|
return this._umap.formatter
|
|
318
|
-
.parse(
|
|
332
|
+
.parse(raw, this.options.remoteData.format)
|
|
319
333
|
.then((geojson) => this.fromGeoJSON(geojson))
|
|
320
|
-
|
|
334
|
+
.catch((error) => {
|
|
335
|
+
Alert.error(
|
|
336
|
+
translate('Cannot parse remote data for layer "{layer}" with url "{url}"', {
|
|
337
|
+
layer: this.getName(),
|
|
338
|
+
url: remoteUrl,
|
|
339
|
+
})
|
|
340
|
+
)
|
|
341
|
+
})
|
|
342
|
+
})
|
|
321
343
|
}
|
|
322
344
|
|
|
323
345
|
isLoaded() {
|
|
324
|
-
return !this.
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
hasDataLoaded() {
|
|
328
|
-
return this._dataloaded
|
|
346
|
+
return !this._needsFetch
|
|
329
347
|
}
|
|
330
348
|
|
|
331
349
|
backupOptions() {
|
|
@@ -444,14 +462,14 @@ export class DataLayer extends ServerStored {
|
|
|
444
462
|
// otherwise the layer becomes uneditable.
|
|
445
463
|
return this.makeFeatures(geojson, sync)
|
|
446
464
|
} catch (err) {
|
|
447
|
-
console.
|
|
465
|
+
console.debug('Error with DataLayer', this.id)
|
|
448
466
|
console.error(err)
|
|
449
467
|
return []
|
|
450
468
|
}
|
|
451
469
|
}
|
|
452
470
|
|
|
453
471
|
sortFeatures(collection) {
|
|
454
|
-
const sortKeys = this.
|
|
472
|
+
const sortKeys = this.getOption('sortKey') || U.DEFAULT_LABEL_KEY
|
|
455
473
|
return Utils.sortFeatures(collection, sortKeys, U.lang)
|
|
456
474
|
}
|
|
457
475
|
|
|
@@ -491,14 +509,14 @@ export class DataLayer extends ServerStored {
|
|
|
491
509
|
feature = new Polygon(this._umap, this, geojson, id)
|
|
492
510
|
break
|
|
493
511
|
default:
|
|
494
|
-
console.
|
|
512
|
+
console.debug(geojson)
|
|
495
513
|
Alert.error(
|
|
496
514
|
translate('Skipping unknown geometry.type: {type}', {
|
|
497
515
|
type: geometry.type || 'undefined',
|
|
498
516
|
})
|
|
499
517
|
)
|
|
500
518
|
}
|
|
501
|
-
if (feature) {
|
|
519
|
+
if (feature && !feature.isEmpty()) {
|
|
502
520
|
this.addFeature(feature)
|
|
503
521
|
if (sync) feature.onCommit()
|
|
504
522
|
return feature
|
|
@@ -513,6 +531,9 @@ export class DataLayer extends ServerStored {
|
|
|
513
531
|
if (data?.length) this.isDirty = true
|
|
514
532
|
return data
|
|
515
533
|
})
|
|
534
|
+
.catch((error) => {
|
|
535
|
+
Alert.error(translate('Import failed: invalid data'))
|
|
536
|
+
})
|
|
516
537
|
}
|
|
517
538
|
|
|
518
539
|
readFile(f) {
|
|
@@ -542,10 +563,9 @@ export class DataLayer extends ServerStored {
|
|
|
542
563
|
|
|
543
564
|
async importFromUrl(uri, type) {
|
|
544
565
|
uri = this._umap.renderUrl(uri)
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
}
|
|
566
|
+
return await this.getUrl(uri).then((raw) => {
|
|
567
|
+
return this.importRaw(raw, type)
|
|
568
|
+
})
|
|
549
569
|
}
|
|
550
570
|
|
|
551
571
|
getColor() {
|
|
@@ -574,9 +594,12 @@ export class DataLayer extends ServerStored {
|
|
|
574
594
|
})
|
|
575
595
|
}
|
|
576
596
|
|
|
577
|
-
|
|
578
|
-
this.isDeleted = true
|
|
597
|
+
del(sync = true) {
|
|
579
598
|
this.erase()
|
|
599
|
+
if (sync) {
|
|
600
|
+
this.isDeleted = true
|
|
601
|
+
this.sync.delete()
|
|
602
|
+
}
|
|
580
603
|
}
|
|
581
604
|
|
|
582
605
|
empty() {
|
|
@@ -604,8 +627,6 @@ export class DataLayer extends ServerStored {
|
|
|
604
627
|
this.propagateDelete()
|
|
605
628
|
this._leaflet_events_bk = this._leaflet_events
|
|
606
629
|
this.clear()
|
|
607
|
-
delete this._loaded
|
|
608
|
-
delete this._dataloaded
|
|
609
630
|
}
|
|
610
631
|
|
|
611
632
|
reset() {
|
|
@@ -623,7 +644,6 @@ export class DataLayer extends ServerStored {
|
|
|
623
644
|
this.hide()
|
|
624
645
|
if (this.isRemoteLayer()) this.fetchRemoteData()
|
|
625
646
|
else if (this._geojson_bk) this.fromGeoJSON(this._geojson_bk)
|
|
626
|
-
this._loaded = true
|
|
627
647
|
this.show()
|
|
628
648
|
this.isDirty = false
|
|
629
649
|
}
|
|
@@ -656,7 +676,7 @@ export class DataLayer extends ServerStored {
|
|
|
656
676
|
{
|
|
657
677
|
label: translate('Data is browsable'),
|
|
658
678
|
handler: 'Switch',
|
|
659
|
-
helpEntries: 'browsable',
|
|
679
|
+
helpEntries: ['browsable'],
|
|
660
680
|
},
|
|
661
681
|
],
|
|
662
682
|
[
|
|
@@ -668,20 +688,19 @@ export class DataLayer extends ServerStored {
|
|
|
668
688
|
],
|
|
669
689
|
]
|
|
670
690
|
DomUtil.createTitle(container, translate('Layer properties'), 'icon-layers')
|
|
671
|
-
let builder = new
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
},
|
|
691
|
+
let builder = new MutatingForm(this, metadataFields)
|
|
692
|
+
builder.on('set', ({ detail }) => {
|
|
693
|
+
this._umap.onDataLayersChanged()
|
|
694
|
+
if (detail.helper.field === 'options.type') {
|
|
695
|
+
this.edit()
|
|
696
|
+
}
|
|
678
697
|
})
|
|
679
698
|
container.appendChild(builder.build())
|
|
680
699
|
|
|
681
700
|
const layerOptions = this.layer.getEditableOptions()
|
|
682
701
|
|
|
683
702
|
if (layerOptions.length) {
|
|
684
|
-
builder = new
|
|
703
|
+
builder = new MutatingForm(this, layerOptions, {
|
|
685
704
|
id: 'datalayer-layer-properties',
|
|
686
705
|
})
|
|
687
706
|
const layerProperties = DomUtil.createFieldset(
|
|
@@ -704,7 +723,7 @@ export class DataLayer extends ServerStored {
|
|
|
704
723
|
'options.fillOpacity',
|
|
705
724
|
]
|
|
706
725
|
|
|
707
|
-
builder = new
|
|
726
|
+
builder = new MutatingForm(this, shapeOptions, {
|
|
708
727
|
id: 'datalayer-advanced-properties',
|
|
709
728
|
})
|
|
710
729
|
const shapeProperties = DomUtil.createFieldset(
|
|
@@ -719,11 +738,17 @@ export class DataLayer extends ServerStored {
|
|
|
719
738
|
'options.zoomTo',
|
|
720
739
|
'options.fromZoom',
|
|
721
740
|
'options.toZoom',
|
|
741
|
+
'options.sortKey',
|
|
722
742
|
]
|
|
723
743
|
|
|
724
|
-
builder = new
|
|
744
|
+
builder = new MutatingForm(this, optionsFields, {
|
|
725
745
|
id: 'datalayer-advanced-properties',
|
|
726
746
|
})
|
|
747
|
+
builder.on('set', ({ detail }) => {
|
|
748
|
+
if (detail.helper.field === 'options.sortKey') {
|
|
749
|
+
this.reindex()
|
|
750
|
+
}
|
|
751
|
+
})
|
|
727
752
|
const advancedProperties = DomUtil.createFieldset(
|
|
728
753
|
container,
|
|
729
754
|
translate('Advanced properties')
|
|
@@ -740,7 +765,7 @@ export class DataLayer extends ServerStored {
|
|
|
740
765
|
'options.outlinkTarget',
|
|
741
766
|
'options.interactive',
|
|
742
767
|
]
|
|
743
|
-
builder = new
|
|
768
|
+
builder = new MutatingForm(this, popupFields)
|
|
744
769
|
const popupFieldset = DomUtil.createFieldset(
|
|
745
770
|
container,
|
|
746
771
|
translate('Interaction options')
|
|
@@ -796,7 +821,7 @@ export class DataLayer extends ServerStored {
|
|
|
796
821
|
container,
|
|
797
822
|
translate('Remote data')
|
|
798
823
|
)
|
|
799
|
-
builder = new
|
|
824
|
+
builder = new MutatingForm(this, remoteDataFields)
|
|
800
825
|
remoteDataContainer.appendChild(builder.build())
|
|
801
826
|
DomUtil.createButton(
|
|
802
827
|
'button umap-verify',
|
|
@@ -813,44 +838,36 @@ export class DataLayer extends ServerStored {
|
|
|
813
838
|
container,
|
|
814
839
|
translate('Advanced actions')
|
|
815
840
|
)
|
|
816
|
-
const
|
|
817
|
-
const
|
|
818
|
-
|
|
841
|
+
const filename = `${Utils.slugify(this.options.name)}.geojson`
|
|
842
|
+
const tpl = `
|
|
843
|
+
<div class="button-bar half">
|
|
844
|
+
<button class="button" type="button" data-ref=del>
|
|
819
845
|
<i class="icon icon-24 icon-delete"></i>${translate('Delete')}
|
|
820
|
-
</button
|
|
821
|
-
|
|
822
|
-
|
|
846
|
+
</button>
|
|
847
|
+
<button class="button" type="button" data-ref=empty hidden>
|
|
848
|
+
<i class="icon icon-24 icon-empty"></i>${translate('Empty')}
|
|
849
|
+
</button>
|
|
850
|
+
<button class="button" type="button" data-ref=clone>
|
|
851
|
+
<i class="icon icon-24 icon-clone"></i>${translate('Clone')}
|
|
852
|
+
</button>
|
|
853
|
+
<a class="button" href="${this._dataUrl()}" download="${filename}" data-ref=download hidden>
|
|
854
|
+
<i class="icon icon-24 icon-download"></i>${translate('Download')}
|
|
855
|
+
</a>
|
|
856
|
+
</div>
|
|
857
|
+
`
|
|
858
|
+
const [bar, { del, empty, clone, download }] = Utils.loadTemplateWithRefs(tpl)
|
|
859
|
+
advancedActions.appendChild(bar)
|
|
860
|
+
del.addEventListener('click', () => {
|
|
861
|
+
this.del()
|
|
823
862
|
this._umap.editPanel.close()
|
|
824
863
|
})
|
|
825
|
-
advancedButtons.appendChild(deleteButton)
|
|
826
864
|
|
|
827
865
|
if (!this.isRemoteLayer()) {
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
advancedButtons,
|
|
831
|
-
translate('Empty'),
|
|
832
|
-
this.empty,
|
|
833
|
-
this
|
|
834
|
-
)
|
|
835
|
-
}
|
|
836
|
-
const cloneLink = DomUtil.createButton(
|
|
837
|
-
'button umap-clone',
|
|
838
|
-
advancedButtons,
|
|
839
|
-
translate('Clone'),
|
|
840
|
-
function () {
|
|
841
|
-
const datalayer = this.clone()
|
|
842
|
-
datalayer.edit()
|
|
843
|
-
},
|
|
844
|
-
this
|
|
845
|
-
)
|
|
846
|
-
if (this.createdOnServer) {
|
|
847
|
-
const filename = `${Utils.slugify(this.options.name)}.geojson`
|
|
848
|
-
const download = Utils.loadTemplate(`
|
|
849
|
-
<a class="button" href="${this._dataUrl()}" download="${filename}">
|
|
850
|
-
<i class="icon icon-24 icon-download"></i>${translate('Download')}
|
|
851
|
-
</a>`)
|
|
852
|
-
advancedButtons.appendChild(download)
|
|
866
|
+
empty.hidden = false
|
|
867
|
+
empty.addEventListener('click', () => this.empty())
|
|
853
868
|
}
|
|
869
|
+
clone.addEventListener('click', () => this.clone().edit())
|
|
870
|
+
if (this.createdOnServer) download.hidden = false
|
|
854
871
|
const backButton = DomUtil.createButtonIcon(
|
|
855
872
|
undefined,
|
|
856
873
|
'icon-back',
|
|
@@ -863,6 +880,7 @@ export class DataLayer extends ServerStored {
|
|
|
863
880
|
|
|
864
881
|
this._umap.editPanel.open({
|
|
865
882
|
content: container,
|
|
883
|
+
highlight: 'layers',
|
|
866
884
|
actions: [backButton],
|
|
867
885
|
})
|
|
868
886
|
}
|
|
@@ -1073,9 +1091,7 @@ export class DataLayer extends ServerStored {
|
|
|
1073
1091
|
|
|
1074
1092
|
async save() {
|
|
1075
1093
|
if (this.isDeleted) return await this.saveDelete()
|
|
1076
|
-
if (!this.isLoaded())
|
|
1077
|
-
return
|
|
1078
|
-
}
|
|
1094
|
+
if (!this.isLoaded()) return
|
|
1079
1095
|
const geojson = this.umapGeoJSON()
|
|
1080
1096
|
const formData = new FormData()
|
|
1081
1097
|
formData.append('name', this.options.name)
|
|
@@ -1137,7 +1153,6 @@ export class DataLayer extends ServerStored {
|
|
|
1137
1153
|
this.backupOptions()
|
|
1138
1154
|
this.backupData()
|
|
1139
1155
|
this.connectToMap()
|
|
1140
|
-
this._loaded = true
|
|
1141
1156
|
this.redraw() // Needed for reordering features
|
|
1142
1157
|
return true
|
|
1143
1158
|
}
|
|
@@ -1147,14 +1162,24 @@ export class DataLayer extends ServerStored {
|
|
|
1147
1162
|
if (this.createdOnServer) {
|
|
1148
1163
|
await this._umap.server.post(this.getDeleteUrl())
|
|
1149
1164
|
}
|
|
1150
|
-
|
|
1165
|
+
this.commitDelete()
|
|
1151
1166
|
return true
|
|
1152
1167
|
}
|
|
1153
1168
|
|
|
1169
|
+
commitDelete() {
|
|
1170
|
+
delete this._umap.datalayers[stamp(this)]
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1154
1173
|
getName() {
|
|
1155
1174
|
return this.options.name || translate('Untitled layer')
|
|
1156
1175
|
}
|
|
1157
1176
|
|
|
1177
|
+
getPermalink() {
|
|
1178
|
+
return `${Utils.getBaseUrl()}?${Utils.buildQueryString({ datalayers: this.id })}${
|
|
1179
|
+
window.location.hash
|
|
1180
|
+
}`
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1158
1183
|
tableEdit() {
|
|
1159
1184
|
if (!this.isVisible()) return
|
|
1160
1185
|
const editor = new TableEditor(this._umap, this, this._leafletMap)
|
|
@@ -1221,7 +1246,7 @@ export class DataLayer extends ServerStored {
|
|
|
1221
1246
|
this._umap.dialog
|
|
1222
1247
|
.confirm(translate('Are you sure you want to delete this layer?'))
|
|
1223
1248
|
.then(() => {
|
|
1224
|
-
this.
|
|
1249
|
+
this.del()
|
|
1225
1250
|
})
|
|
1226
1251
|
},
|
|
1227
1252
|
this
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import getClass from './fields.js'
|
|
2
|
+
import * as Utils from '../utils.js'
|
|
3
|
+
import { SCHEMA } from '../schema.js'
|
|
4
|
+
import { translate } from '../i18n.js'
|
|
5
|
+
|
|
6
|
+
export class Form extends Utils.WithEvents {
|
|
7
|
+
constructor(obj, fields, properties) {
|
|
8
|
+
super()
|
|
9
|
+
this.setProperties(properties)
|
|
10
|
+
this.defaultProperties = {}
|
|
11
|
+
this.obj = obj
|
|
12
|
+
this.form = Utils.loadTemplate('<form></form>')
|
|
13
|
+
this.setFields(fields)
|
|
14
|
+
if (this.properties.id) {
|
|
15
|
+
this.form.id = this.properties.id
|
|
16
|
+
}
|
|
17
|
+
if (this.properties.className) {
|
|
18
|
+
this.form.classList.add(...this.properties.className.split(' '))
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
setProperties(properties) {
|
|
23
|
+
this.properties = Object.assign({}, this.properties, properties)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
setFields(fields) {
|
|
27
|
+
this.fields = fields || []
|
|
28
|
+
this.helpers = {}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
build() {
|
|
32
|
+
this.form.innerHTML = ''
|
|
33
|
+
for (const definition of this.fields) {
|
|
34
|
+
this.buildField(this.makeField(definition))
|
|
35
|
+
}
|
|
36
|
+
return this.form
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
buildField(field) {
|
|
40
|
+
field.buildTemplate()
|
|
41
|
+
field.build()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
makeField(field) {
|
|
45
|
+
// field can be either a string like "option.name" or a full definition array,
|
|
46
|
+
// like ['properties.tilelayer.tms', {handler: 'CheckBox', helpText: 'TMS format'}]
|
|
47
|
+
let properties
|
|
48
|
+
if (Array.isArray(field)) {
|
|
49
|
+
properties = field[1] || {}
|
|
50
|
+
field = field[0]
|
|
51
|
+
} else {
|
|
52
|
+
properties = this.defaultProperties[this.getName(field)] || {}
|
|
53
|
+
}
|
|
54
|
+
const class_ = getClass(properties.handler || 'Input')
|
|
55
|
+
this.helpers[field] = new class_(this, field, properties)
|
|
56
|
+
return this.helpers[field]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
getter(field) {
|
|
60
|
+
const path = field.split('.')
|
|
61
|
+
let value = this.obj
|
|
62
|
+
for (const sub of path) {
|
|
63
|
+
try {
|
|
64
|
+
value = value[sub]
|
|
65
|
+
} catch {
|
|
66
|
+
console.debug(field)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return value
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
setter(field, value) {
|
|
73
|
+
const path = field.split('.')
|
|
74
|
+
let obj = this.obj
|
|
75
|
+
let what
|
|
76
|
+
for (let i = 0, l = path.length; i < l; i++) {
|
|
77
|
+
what = path[i]
|
|
78
|
+
if (what === path[l - 1]) {
|
|
79
|
+
if (typeof value === 'undefined') {
|
|
80
|
+
delete obj[what]
|
|
81
|
+
} else {
|
|
82
|
+
obj[what] = value
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
obj = obj[what]
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
restoreField(field) {
|
|
91
|
+
const initial = this.helpers[field].initial
|
|
92
|
+
this.setter(field, initial)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
getName(field) {
|
|
96
|
+
const fieldEls = field.split('.')
|
|
97
|
+
return fieldEls[fieldEls.length - 1]
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
fetchAll() {
|
|
101
|
+
for (const helper of Object.values(this.helpers)) {
|
|
102
|
+
helper.fetch()
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
syncAll() {
|
|
107
|
+
for (const helper of Object.values(this.helpers)) {
|
|
108
|
+
helper.sync()
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
onPostSync(helper) {
|
|
113
|
+
if (this.properties.callback) {
|
|
114
|
+
this.properties.callback(helper)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
finish() {}
|
|
119
|
+
|
|
120
|
+
getTemplate(helper) {
|
|
121
|
+
return `
|
|
122
|
+
<div class="formbox" data-ref=container>
|
|
123
|
+
${helper.getTemplate()}
|
|
124
|
+
<small class="help-text" data-ref=helpText></small>
|
|
125
|
+
</div>`
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export class MutatingForm extends Form {
|
|
130
|
+
constructor(obj, fields, properties) {
|
|
131
|
+
super(obj, fields, properties)
|
|
132
|
+
this._umap = obj._umap || properties.umap
|
|
133
|
+
this.computeDefaultProperties()
|
|
134
|
+
// this.on('finish', this.finish)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
computeDefaultProperties() {
|
|
138
|
+
const customHandlers = {
|
|
139
|
+
sortKey: 'PropertyInput',
|
|
140
|
+
easing: 'Switch',
|
|
141
|
+
facetKey: 'PropertyInput',
|
|
142
|
+
slugKey: 'PropertyInput',
|
|
143
|
+
labelKey: 'PropertyInput',
|
|
144
|
+
}
|
|
145
|
+
for (const [key, defaults] of Object.entries(SCHEMA)) {
|
|
146
|
+
const properties = Object.assign({}, defaults)
|
|
147
|
+
if (properties.type === Boolean) {
|
|
148
|
+
if (properties.nullable) properties.handler = 'NullableChoices'
|
|
149
|
+
else properties.handler = 'Switch'
|
|
150
|
+
} else if (properties.type === 'Text') {
|
|
151
|
+
properties.handler = 'Textarea'
|
|
152
|
+
} else if (properties.type === Number) {
|
|
153
|
+
if (properties.step) properties.handler = 'Range'
|
|
154
|
+
else properties.handler = 'IntInput'
|
|
155
|
+
} else if (properties.choices) {
|
|
156
|
+
const text_length = properties.choices.reduce(
|
|
157
|
+
(acc, [_, label]) => acc + label.length,
|
|
158
|
+
0
|
|
159
|
+
)
|
|
160
|
+
// Try to be smart and use MultiChoice only
|
|
161
|
+
// for choices where labels are shorts…
|
|
162
|
+
if (text_length < 40) {
|
|
163
|
+
properties.handler = 'MultiChoice'
|
|
164
|
+
} else {
|
|
165
|
+
properties.handler = 'Select'
|
|
166
|
+
properties.selectOptions = properties.choices
|
|
167
|
+
}
|
|
168
|
+
} else {
|
|
169
|
+
switch (key) {
|
|
170
|
+
case 'color':
|
|
171
|
+
case 'fillColor':
|
|
172
|
+
properties.handler = 'ColorPicker'
|
|
173
|
+
break
|
|
174
|
+
case 'iconUrl':
|
|
175
|
+
properties.handler = 'IconUrl'
|
|
176
|
+
break
|
|
177
|
+
case 'licence':
|
|
178
|
+
properties.handler = 'LicenceChooser'
|
|
179
|
+
break
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (customHandlers[key]) {
|
|
184
|
+
properties.handler = customHandlers[key]
|
|
185
|
+
}
|
|
186
|
+
// Input uses this key for its type attribute
|
|
187
|
+
delete properties.type
|
|
188
|
+
this.defaultProperties[key] = properties
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
setter(field, value) {
|
|
193
|
+
super.setter(field, value)
|
|
194
|
+
this.obj.isDirty = true
|
|
195
|
+
if ('render' in this.obj) {
|
|
196
|
+
this.obj.render([field], this)
|
|
197
|
+
}
|
|
198
|
+
if ('sync' in this.obj) {
|
|
199
|
+
this.obj.sync.update(field, value)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
getTemplate(helper) {
|
|
204
|
+
let template
|
|
205
|
+
if (helper.properties.inheritable) {
|
|
206
|
+
const extraClassName = this.getter(helper.field) === undefined ? ' undefined' : ''
|
|
207
|
+
template = `
|
|
208
|
+
<div class="umap-field-${helper.name} formbox inheritable${extraClassName}">
|
|
209
|
+
<div class="header" data-ref=header>
|
|
210
|
+
${helper.getLabelTemplate()}
|
|
211
|
+
<span class="actions show-on-defined" data-ref=actions></span>
|
|
212
|
+
<span class="buttons" data-ref=buttons>
|
|
213
|
+
<button type="button" class="button undefine" data-ref=undefine>${translate('clear')}</button>
|
|
214
|
+
<button type="button" class="button define" data-ref=define>${translate('define')}</button>
|
|
215
|
+
</span>
|
|
216
|
+
</div>
|
|
217
|
+
<div class="show-on-defined" data-ref=container>
|
|
218
|
+
${helper.getTemplate()}
|
|
219
|
+
<small class="help-text" data-ref=helpText></small>
|
|
220
|
+
</div>
|
|
221
|
+
</div>`
|
|
222
|
+
} else {
|
|
223
|
+
template = `
|
|
224
|
+
<div class="formbox umap-field-${helper.name}" data-ref=container>
|
|
225
|
+
${helper.getLabelTemplate()}
|
|
226
|
+
${helper.getTemplate()}
|
|
227
|
+
<small class="help-text" data-ref=helpText></small>
|
|
228
|
+
</div>`
|
|
229
|
+
}
|
|
230
|
+
return template
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
build() {
|
|
234
|
+
super.build()
|
|
235
|
+
this._umap.help.parse(this.form)
|
|
236
|
+
return this.form
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
finish(helper) {
|
|
240
|
+
helper.input?.blur()
|
|
241
|
+
}
|
|
242
|
+
}
|