umap-project 2.6.2__py3-none-any.whl → 2.7.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 +64 -1
- umap/asgi.py +15 -0
- umap/context_processors.py +1 -0
- umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
- umap/locale/cs_CZ/LC_MESSAGES/django.po +96 -92
- umap/locale/de/LC_MESSAGES/django.mo +0 -0
- umap/locale/de/LC_MESSAGES/django.po +19 -18
- umap/locale/en/LC_MESSAGES/django.po +47 -43
- umap/locale/es/LC_MESSAGES/django.mo +0 -0
- umap/locale/es/LC_MESSAGES/django.po +134 -128
- umap/locale/fr/LC_MESSAGES/django.mo +0 -0
- umap/locale/fr/LC_MESSAGES/django.po +51 -47
- umap/locale/pt/LC_MESSAGES/django.mo +0 -0
- umap/locale/pt/LC_MESSAGES/django.po +64 -60
- umap/management/commands/clean_tilelayer.py +152 -0
- umap/management/commands/purge_purgatory.py +28 -0
- umap/models.py +27 -2
- umap/settings/base.py +3 -1
- umap/static/umap/base.css +4 -4
- umap/static/umap/css/contextmenu.css +6 -1
- umap/static/umap/css/icon.css +7 -2
- umap/static/umap/css/importers.css +4 -0
- umap/static/umap/img/16-white.svg +9 -2
- umap/static/umap/img/16.svg +1 -181
- umap/static/umap/img/24-white.svg +1 -0
- umap/static/umap/img/24.svg +1 -0
- umap/static/umap/img/importers/cadastrefr.svg +23 -0
- umap/static/umap/img/source/16-white.svg +10 -3
- umap/static/umap/img/source/16.svg +753 -197
- umap/static/umap/img/source/24-white.svg +3 -2
- umap/static/umap/img/source/24.svg +3 -2
- umap/static/umap/js/modules/autocomplete.js +7 -3
- umap/static/umap/js/modules/browser.js +55 -2
- umap/static/umap/js/modules/caption.js +16 -5
- umap/static/umap/js/modules/data/features.js +183 -8
- umap/static/umap/js/modules/data/layer.js +57 -40
- umap/static/umap/js/modules/formatter.js +3 -2
- umap/static/umap/js/modules/global.js +2 -0
- umap/static/umap/js/modules/importer.js +3 -0
- umap/static/umap/js/modules/importers/cadastrefr.js +62 -0
- umap/static/umap/js/modules/importers/communesfr.js +15 -3
- umap/static/umap/js/modules/permissions.js +123 -93
- umap/static/umap/js/modules/rendering/layers/classified.js +2 -0
- umap/static/umap/js/modules/rendering/ui.js +60 -213
- umap/static/umap/js/modules/share.js +1 -3
- umap/static/umap/js/modules/slideshow.js +1 -1
- umap/static/umap/js/modules/sync/engine.js +371 -14
- umap/static/umap/js/modules/sync/hlc.js +106 -0
- umap/static/umap/js/modules/sync/updaters.js +18 -6
- umap/static/umap/js/modules/sync/websocket.js +1 -1
- umap/static/umap/js/modules/tableeditor.js +1 -1
- umap/static/umap/js/modules/ui/base.js +2 -2
- umap/static/umap/js/modules/ui/contextmenu.js +51 -18
- umap/static/umap/js/modules/urls.js +5 -1
- umap/static/umap/js/modules/utils.js +28 -4
- umap/static/umap/js/umap.controls.js +76 -55
- umap/static/umap/js/umap.core.js +3 -3
- umap/static/umap/js/umap.forms.js +3 -1
- umap/static/umap/js/umap.js +115 -124
- umap/static/umap/locale/am_ET.js +2 -2
- umap/static/umap/locale/am_ET.json +2 -2
- umap/static/umap/locale/ar.js +2 -2
- umap/static/umap/locale/ar.json +2 -2
- umap/static/umap/locale/ast.js +2 -2
- umap/static/umap/locale/ast.json +2 -2
- umap/static/umap/locale/bg.js +2 -2
- umap/static/umap/locale/bg.json +2 -2
- umap/static/umap/locale/br.js +13 -4
- umap/static/umap/locale/br.json +13 -4
- umap/static/umap/locale/ca.js +30 -17
- umap/static/umap/locale/ca.json +30 -17
- umap/static/umap/locale/cs_CZ.js +89 -80
- umap/static/umap/locale/cs_CZ.json +89 -80
- umap/static/umap/locale/da.js +2 -2
- umap/static/umap/locale/da.json +2 -2
- umap/static/umap/locale/de.js +17 -8
- umap/static/umap/locale/de.json +17 -8
- umap/static/umap/locale/el.js +2 -2
- umap/static/umap/locale/el.json +2 -2
- umap/static/umap/locale/en.js +15 -4
- umap/static/umap/locale/en.json +15 -4
- umap/static/umap/locale/en_US.json +2 -2
- umap/static/umap/locale/es.js +338 -325
- umap/static/umap/locale/es.json +338 -325
- umap/static/umap/locale/et.js +2 -2
- umap/static/umap/locale/et.json +2 -2
- umap/static/umap/locale/eu.js +11 -4
- umap/static/umap/locale/eu.json +11 -4
- umap/static/umap/locale/fa_IR.js +11 -4
- umap/static/umap/locale/fa_IR.json +11 -4
- umap/static/umap/locale/fi.js +2 -2
- umap/static/umap/locale/fi.json +2 -2
- umap/static/umap/locale/fr.js +15 -4
- umap/static/umap/locale/fr.json +15 -4
- umap/static/umap/locale/gl.js +2 -2
- umap/static/umap/locale/gl.json +2 -2
- umap/static/umap/locale/he.js +2 -2
- umap/static/umap/locale/he.json +2 -2
- umap/static/umap/locale/hr.js +2 -2
- umap/static/umap/locale/hr.json +2 -2
- umap/static/umap/locale/hu.js +12 -5
- umap/static/umap/locale/hu.json +12 -5
- umap/static/umap/locale/id.js +2 -2
- umap/static/umap/locale/id.json +2 -2
- umap/static/umap/locale/is.js +2 -2
- umap/static/umap/locale/is.json +2 -2
- umap/static/umap/locale/it.js +2 -2
- umap/static/umap/locale/it.json +2 -2
- umap/static/umap/locale/ja.js +2 -2
- umap/static/umap/locale/ja.json +2 -2
- umap/static/umap/locale/ko.js +2 -2
- umap/static/umap/locale/ko.json +2 -2
- umap/static/umap/locale/lt.js +2 -2
- umap/static/umap/locale/lt.json +2 -2
- umap/static/umap/locale/ms.js +2 -2
- umap/static/umap/locale/ms.json +2 -2
- umap/static/umap/locale/nl.js +2 -2
- umap/static/umap/locale/nl.json +2 -2
- umap/static/umap/locale/no.js +2 -2
- umap/static/umap/locale/no.json +2 -2
- umap/static/umap/locale/pl.js +2 -2
- umap/static/umap/locale/pl.json +2 -2
- umap/static/umap/locale/pl_PL.json +2 -2
- umap/static/umap/locale/pt.js +19 -10
- umap/static/umap/locale/pt.json +19 -10
- umap/static/umap/locale/pt_BR.js +2 -2
- umap/static/umap/locale/pt_BR.json +2 -2
- umap/static/umap/locale/pt_PT.js +13 -4
- umap/static/umap/locale/pt_PT.json +13 -4
- umap/static/umap/locale/ro.js +2 -2
- umap/static/umap/locale/ro.json +2 -2
- umap/static/umap/locale/ru.js +2 -2
- umap/static/umap/locale/ru.json +2 -2
- umap/static/umap/locale/si.js +2 -2
- umap/static/umap/locale/si.json +2 -2
- umap/static/umap/locale/sk_SK.js +2 -2
- umap/static/umap/locale/sk_SK.json +2 -2
- umap/static/umap/locale/sl.js +2 -2
- umap/static/umap/locale/sl.json +2 -2
- umap/static/umap/locale/sr.js +2 -2
- umap/static/umap/locale/sr.json +2 -2
- umap/static/umap/locale/sv.js +2 -2
- umap/static/umap/locale/sv.json +2 -2
- umap/static/umap/locale/th_TH.js +2 -2
- umap/static/umap/locale/th_TH.json +2 -2
- umap/static/umap/locale/tr.js +2 -2
- umap/static/umap/locale/tr.json +2 -2
- umap/static/umap/locale/uk_UA.js +2 -2
- umap/static/umap/locale/uk_UA.json +2 -2
- umap/static/umap/locale/vi.js +2 -2
- umap/static/umap/locale/vi.json +2 -2
- umap/static/umap/locale/vi_VN.json +2 -2
- umap/static/umap/locale/zh.js +2 -2
- umap/static/umap/locale/zh.json +2 -2
- umap/static/umap/locale/zh_CN.json +2 -2
- umap/static/umap/locale/zh_TW.Big5.json +2 -2
- umap/static/umap/locale/zh_TW.js +13 -4
- umap/static/umap/locale/zh_TW.json +13 -4
- umap/static/umap/map.css +44 -29
- umap/static/umap/unittests/hlc.js +165 -0
- umap/static/umap/unittests/sync.js +321 -15
- umap/static/umap/unittests/utils.js +47 -0
- umap/static/umap/vars.css +2 -1
- umap/static/umap/vendors/colorbrewer/colorbrewer.js +309 -317
- umap/static/umap/vendors/dompurify/purify.es.js +15 -16
- umap/static/umap/vendors/dompurify/purify.es.mjs.map +1 -1
- umap/static/umap/vendors/georsstogeojson/GeoRSSToGeoJSON.js +111 -80
- umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.js +2 -2
- umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.js.map +1 -1
- umap/static/umap/vendors/simple-statistics/simple-statistics.min.js +1 -1
- umap/static/umap/vendors/simple-statistics/simple-statistics.min.js.map +1 -1
- umap/templates/umap/css.html +0 -2
- umap/templates/umap/dashboard_menu.html +4 -2
- umap/templates/umap/js.html +0 -5
- umap/templates/umap/map_detail.html +2 -2
- umap/tests/fixtures/test_upload_data.csv +2 -2
- umap/tests/integration/test_anonymous_owned_map.py +1 -0
- umap/tests/integration/test_basics.py +1 -1
- umap/tests/integration/test_browser.py +69 -7
- umap/tests/integration/test_caption.py +3 -3
- umap/tests/integration/test_circles_layer.py +12 -0
- umap/tests/integration/test_cluster.py +53 -0
- umap/tests/integration/test_datalayer.py +2 -1
- umap/tests/integration/test_draw_polygon.py +17 -9
- umap/tests/integration/test_draw_polyline.py +84 -7
- umap/tests/integration/test_edit_datalayer.py +5 -8
- umap/tests/integration/test_edit_map.py +2 -2
- umap/tests/integration/test_edit_marker.py +1 -1
- umap/tests/integration/test_facets_browser.py +3 -3
- umap/tests/integration/test_import.py +1 -0
- umap/tests/integration/test_map.py +1 -0
- umap/tests/integration/test_owned_map.py +1 -1
- umap/tests/integration/test_view_marker.py +63 -0
- umap/tests/integration/test_view_polygon.py +12 -12
- umap/tests/integration/test_websocket_sync.py +65 -3
- umap/tests/test_clean_tilelayer.py +83 -0
- umap/tests/test_datalayer.py +24 -0
- umap/tests/test_map_views.py +20 -0
- umap/tests/test_purge_purgatory.py +25 -0
- umap/tests/test_websocket_server.py +22 -0
- umap/urls.py +5 -1
- umap/views.py +6 -3
- umap/websocket_server.py +130 -27
- {umap_project-2.6.2.dist-info → umap_project-2.7.0.dist-info}/METADATA +18 -14
- {umap_project-2.6.2.dist-info → umap_project-2.7.0.dist-info}/RECORD +209 -200
- umap/static/umap/vendors/contextmenu/leaflet.contextmenu.min.css +0 -1
- umap/static/umap/vendors/contextmenu/leaflet.contextmenu.min.js +0 -7
- {umap_project-2.6.2.dist-info → umap_project-2.7.0.dist-info}/WHEEL +0 -0
- {umap_project-2.6.2.dist-info → umap_project-2.7.0.dist-info}/entry_points.txt +0 -0
- {umap_project-2.6.2.dist-info → umap_project-2.7.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -92,12 +92,12 @@ export class DataLayer {
|
|
|
92
92
|
set isDirty(status) {
|
|
93
93
|
this._isDirty = status
|
|
94
94
|
if (status) {
|
|
95
|
-
this.map.
|
|
95
|
+
this.map.isDirty = true
|
|
96
96
|
// A layer can be made dirty by indirect action (like dragging layers)
|
|
97
97
|
// we need to have it loaded before saving it.
|
|
98
98
|
if (!this.isLoaded()) this.fetchData()
|
|
99
99
|
} else {
|
|
100
|
-
this.map.
|
|
100
|
+
this.map.checkDirty()
|
|
101
101
|
this.isDeleted = false
|
|
102
102
|
}
|
|
103
103
|
}
|
|
@@ -115,6 +115,10 @@ export class DataLayer {
|
|
|
115
115
|
return this._isDeleted
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
get cssId() {
|
|
119
|
+
return `datalayer-${stamp(this)}`
|
|
120
|
+
}
|
|
121
|
+
|
|
118
122
|
getSyncMetadata() {
|
|
119
123
|
return {
|
|
120
124
|
subject: 'datalayer',
|
|
@@ -235,6 +239,7 @@ export class DataLayer {
|
|
|
235
239
|
}
|
|
236
240
|
|
|
237
241
|
dataChanged() {
|
|
242
|
+
if (!this.hasDataLoaded()) return
|
|
238
243
|
this.map.onDataLayersChanged()
|
|
239
244
|
this.layer.dataChanged()
|
|
240
245
|
}
|
|
@@ -242,10 +247,15 @@ export class DataLayer {
|
|
|
242
247
|
fromGeoJSON(geojson, sync = true) {
|
|
243
248
|
this.addData(geojson, sync)
|
|
244
249
|
this._geojson = geojson
|
|
245
|
-
this.
|
|
250
|
+
this.onDataLoaded()
|
|
246
251
|
this.dataChanged()
|
|
247
252
|
}
|
|
248
253
|
|
|
254
|
+
onDataLoaded() {
|
|
255
|
+
this._dataloaded = true
|
|
256
|
+
this.renderLegend()
|
|
257
|
+
}
|
|
258
|
+
|
|
249
259
|
async fromUmapGeoJSON(geojson) {
|
|
250
260
|
if (geojson._storage) geojson._umap_options = geojson._storage // Retrocompat
|
|
251
261
|
if (geojson._umap_options) this.setOptions(geojson._umap_options)
|
|
@@ -339,11 +349,11 @@ export class DataLayer {
|
|
|
339
349
|
const id = stamp(this)
|
|
340
350
|
if (!this.map.datalayers[id]) {
|
|
341
351
|
this.map.datalayers[id] = this
|
|
342
|
-
if (!this.map.datalayers_index.includes(this)) {
|
|
343
|
-
this.map.datalayers_index.push(this)
|
|
344
|
-
}
|
|
345
|
-
this.map.onDataLayersChanged()
|
|
346
352
|
}
|
|
353
|
+
if (!this.map.datalayers_index.includes(this)) {
|
|
354
|
+
this.map.datalayers_index.push(this)
|
|
355
|
+
}
|
|
356
|
+
this.map.onDataLayersChanged()
|
|
347
357
|
}
|
|
348
358
|
|
|
349
359
|
_dataUrl() {
|
|
@@ -384,7 +394,7 @@ export class DataLayer {
|
|
|
384
394
|
this.indexProperties(feature)
|
|
385
395
|
this.map.features_index[feature.getSlug()] = feature
|
|
386
396
|
this.showFeature(feature)
|
|
387
|
-
|
|
397
|
+
this.dataChanged()
|
|
388
398
|
}
|
|
389
399
|
|
|
390
400
|
removeFeature(feature, sync) {
|
|
@@ -395,7 +405,7 @@ export class DataLayer {
|
|
|
395
405
|
feature.disconnectFromDataLayer(this)
|
|
396
406
|
this._index.splice(this._index.indexOf(id), 1)
|
|
397
407
|
delete this._features[id]
|
|
398
|
-
if (this.
|
|
408
|
+
if (this.isVisible()) this.dataChanged()
|
|
399
409
|
}
|
|
400
410
|
|
|
401
411
|
indexProperties(feature) {
|
|
@@ -559,7 +569,6 @@ export class DataLayer {
|
|
|
559
569
|
|
|
560
570
|
erase() {
|
|
561
571
|
this.hide()
|
|
562
|
-
delete this.map.datalayers[stamp(this)]
|
|
563
572
|
this.map.datalayers_index.splice(this.getRank(), 1)
|
|
564
573
|
this.parentPane.removeChild(this.pane)
|
|
565
574
|
this.map.onDataLayersChanged()
|
|
@@ -716,7 +725,7 @@ export class DataLayer {
|
|
|
716
725
|
const remoteDataFields = [
|
|
717
726
|
[
|
|
718
727
|
'options.remoteData.url',
|
|
719
|
-
{ handler: 'Url', label: translate('Url'), helpEntries: 'formatURL' },
|
|
728
|
+
{ handler: 'Url', label: translate('Url'), helpEntries: ['formatURL'] },
|
|
720
729
|
],
|
|
721
730
|
[
|
|
722
731
|
'options.remoteData.format',
|
|
@@ -729,7 +738,7 @@ export class DataLayer {
|
|
|
729
738
|
{
|
|
730
739
|
handler: 'Switch',
|
|
731
740
|
label: translate('Dynamic'),
|
|
732
|
-
helpEntries: 'dynamicRemoteData',
|
|
741
|
+
helpEntries: ['dynamicRemoteData'],
|
|
733
742
|
},
|
|
734
743
|
],
|
|
735
744
|
[
|
|
@@ -746,7 +755,7 @@ export class DataLayer {
|
|
|
746
755
|
{
|
|
747
756
|
handler: 'Switch',
|
|
748
757
|
label: translate('Proxy request'),
|
|
749
|
-
helpEntries: 'proxyRemoteData',
|
|
758
|
+
helpEntries: ['proxyRemoteData'],
|
|
750
759
|
},
|
|
751
760
|
])
|
|
752
761
|
remoteDataFields.push('options.remoteData.ttl')
|
|
@@ -803,13 +812,12 @@ export class DataLayer {
|
|
|
803
812
|
this
|
|
804
813
|
)
|
|
805
814
|
if (this.umap_id) {
|
|
806
|
-
const
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
)
|
|
815
|
+
const filename = `${Utils.slugify(this.options.name)}.geojson`
|
|
816
|
+
const download = Utils.loadTemplate(`
|
|
817
|
+
<a class="button" href="${this._dataUrl()}" download="${filename}">
|
|
818
|
+
<i class="icon icon-24 icon-download"></i>${translate('Download')}
|
|
819
|
+
</a>`)
|
|
820
|
+
advancedButtons.appendChild(download)
|
|
813
821
|
}
|
|
814
822
|
const backButton = DomUtil.createButtonIcon(
|
|
815
823
|
undefined,
|
|
@@ -874,18 +882,21 @@ export class DataLayer {
|
|
|
874
882
|
|
|
875
883
|
async restore(version) {
|
|
876
884
|
if (!this.map.editEnabled) return
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
885
|
+
this.map.dialog
|
|
886
|
+
.confirm(translate('Are you sure you want to restore this version?'))
|
|
887
|
+
.then(async () => {
|
|
888
|
+
const [geojson, response, error] = await this.map.server.get(
|
|
889
|
+
this.getVersionUrl(version)
|
|
890
|
+
)
|
|
891
|
+
if (!error) {
|
|
892
|
+
if (geojson._storage) geojson._umap_options = geojson._storage // Retrocompat.
|
|
893
|
+
if (geojson._umap_options) this.setOptions(geojson._umap_options)
|
|
894
|
+
this.empty()
|
|
895
|
+
if (this.isRemoteLayer()) this.fetchRemoteData()
|
|
896
|
+
else this.addData(geojson)
|
|
897
|
+
this.isDirty = true
|
|
898
|
+
}
|
|
899
|
+
})
|
|
889
900
|
}
|
|
890
901
|
|
|
891
902
|
featuresToGeoJSON() {
|
|
@@ -1026,7 +1037,7 @@ export class DataLayer {
|
|
|
1026
1037
|
}
|
|
1027
1038
|
|
|
1028
1039
|
async save() {
|
|
1029
|
-
if (this.isDeleted) return this.saveDelete()
|
|
1040
|
+
if (this.isDeleted) return await this.saveDelete()
|
|
1030
1041
|
if (!this.isLoaded()) {
|
|
1031
1042
|
return
|
|
1032
1043
|
}
|
|
@@ -1090,8 +1101,8 @@ export class DataLayer {
|
|
|
1090
1101
|
if (this.umap_id) {
|
|
1091
1102
|
await this.map.server.post(this.getDeleteUrl())
|
|
1092
1103
|
}
|
|
1104
|
+
delete this.map.datalayers[stamp(this)]
|
|
1093
1105
|
this.isDirty = false
|
|
1094
|
-
this.map.continueSaving()
|
|
1095
1106
|
}
|
|
1096
1107
|
|
|
1097
1108
|
getMap() {
|
|
@@ -1118,10 +1129,13 @@ export class DataLayer {
|
|
|
1118
1129
|
return 'displayName'
|
|
1119
1130
|
}
|
|
1120
1131
|
|
|
1121
|
-
renderLegend(
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1132
|
+
renderLegend() {
|
|
1133
|
+
for (const container of document.querySelectorAll(`.${this.cssId} .datalayer-legend`)) {
|
|
1134
|
+
container.innerHTML = ''
|
|
1135
|
+
if (this.layer.renderLegend) return this.layer.renderLegend(container)
|
|
1136
|
+
const color = DomUtil.create('span', 'datalayer-color', container)
|
|
1137
|
+
color.style.backgroundColor = this.getColor()
|
|
1138
|
+
}
|
|
1125
1139
|
}
|
|
1126
1140
|
|
|
1127
1141
|
renderToolbox(container) {
|
|
@@ -1160,8 +1174,11 @@ export class DataLayer {
|
|
|
1160
1174
|
'click',
|
|
1161
1175
|
function () {
|
|
1162
1176
|
if (!this.isVisible()) return
|
|
1163
|
-
|
|
1164
|
-
|
|
1177
|
+
this.map.dialog
|
|
1178
|
+
.confirm(translate('Are you sure you want to delete this layer?'))
|
|
1179
|
+
.then(() => {
|
|
1180
|
+
this._delete()
|
|
1181
|
+
})
|
|
1165
1182
|
},
|
|
1166
1183
|
this
|
|
1167
1184
|
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Uses globals for: csv2geojson, osmtogeojson
|
|
1
|
+
/* Uses globals for: csv2geojson, osmtogeojson (not available as ESM) */
|
|
2
2
|
import { translate } from './i18n.js'
|
|
3
3
|
|
|
4
4
|
export const EXPORT_FORMATS = {
|
|
@@ -115,7 +115,8 @@ export class Formatter {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
async fromGeoRSS(str) {
|
|
118
|
-
|
|
118
|
+
const GeoRSSToGeoJSON = await import('../../vendors/georsstogeojson/GeoRSSToGeoJSON.js')
|
|
119
|
+
return GeoRSSToGeoJSON.parse(this.toDom(str))
|
|
119
120
|
}
|
|
120
121
|
|
|
121
122
|
toDom(x) {
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from './autocomplete.js'
|
|
10
10
|
import Browser from './browser.js'
|
|
11
11
|
import Caption from './caption.js'
|
|
12
|
+
import ContextMenu from './ui/contextmenu.js'
|
|
12
13
|
import Facets from './facets.js'
|
|
13
14
|
import { Formatter } from './formatter.js'
|
|
14
15
|
import Help from './help.js'
|
|
@@ -43,6 +44,7 @@ window.U = {
|
|
|
43
44
|
AutocompleteDatalist,
|
|
44
45
|
Browser,
|
|
45
46
|
Caption,
|
|
47
|
+
ContextMenu,
|
|
46
48
|
DataLayer,
|
|
47
49
|
DataLayerPermissions,
|
|
48
50
|
Dialog,
|
|
@@ -69,6 +69,9 @@ export default class Importer {
|
|
|
69
69
|
case 'communesfr':
|
|
70
70
|
import('./importers/communesfr.js').then(register)
|
|
71
71
|
break
|
|
72
|
+
case 'cadastrefr':
|
|
73
|
+
import('./importers/cadastrefr.js').then(register)
|
|
74
|
+
break
|
|
72
75
|
case 'overpass':
|
|
73
76
|
import('./importers/overpass.js').then(register)
|
|
74
77
|
break
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
|
|
2
|
+
import { BaseAjax, SingleMixin } from '../autocomplete.js'
|
|
3
|
+
import * as Util from '../utils.js'
|
|
4
|
+
import { AutocompleteCommunes } from './communesfr.js'
|
|
5
|
+
|
|
6
|
+
const TEMPLATE = `
|
|
7
|
+
<h3>Cadastre</h3>
|
|
8
|
+
<p>Importer les données cadastrales d’une commune française.</p>
|
|
9
|
+
<select name="theme">
|
|
10
|
+
<option value="batiments">Bâtiments</option>
|
|
11
|
+
<option value="communes">Communes</option>
|
|
12
|
+
<option value="feuilles">Feuilles</option>
|
|
13
|
+
<option value="lieux_dits">Lieux dits</option>
|
|
14
|
+
<option value="parcelles" selected>Parcelles</option>
|
|
15
|
+
<option value="prefixes_sections">Préfixes sections</option>
|
|
16
|
+
<option value="sections">Sections</option>
|
|
17
|
+
<option value="subdivisions_fiscales">Subdivisions fiscales</option>
|
|
18
|
+
</select>
|
|
19
|
+
<label id="boundary">
|
|
20
|
+
</label>
|
|
21
|
+
`
|
|
22
|
+
|
|
23
|
+
export class Importer {
|
|
24
|
+
constructor(map, options) {
|
|
25
|
+
this.name = options.name || 'Cadastre'
|
|
26
|
+
this.id = 'cadastrefr'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async open(importer) {
|
|
30
|
+
let boundary = null
|
|
31
|
+
let boundaryName = null
|
|
32
|
+
const container = DomUtil.create('div')
|
|
33
|
+
container.innerHTML = TEMPLATE
|
|
34
|
+
const select = container.querySelector('select')
|
|
35
|
+
const options = {
|
|
36
|
+
placeholder: 'Nom ou code INSEE…',
|
|
37
|
+
url: 'https://geo.api.gouv.fr/communes?nom={q}&limit=5',
|
|
38
|
+
on_select: (choice) => {
|
|
39
|
+
boundary = choice.item.value
|
|
40
|
+
boundaryName = choice.item.label
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
this.autocomplete = new AutocompleteCommunes(container, options)
|
|
44
|
+
|
|
45
|
+
const confirm = (form) => {
|
|
46
|
+
if (!boundary || !form.theme) {
|
|
47
|
+
Alert.error(translate('Please choose a theme and a boundary first.'))
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
importer.url = `https://cadastre.data.gouv.fr/bundler/cadastre-etalab/communes/${boundary}/geojson/${form.theme}`
|
|
51
|
+
importer.format = 'geojson'
|
|
52
|
+
importer.layerName = `${boundaryName} — ${select.options[select.selectedIndex].textContent}`
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
importer.dialog
|
|
56
|
+
.open({
|
|
57
|
+
template: container,
|
|
58
|
+
className: `${this.id} importer dark`,
|
|
59
|
+
})
|
|
60
|
+
.then(confirm)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
import { DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
|
|
2
2
|
import { BaseAjax, SingleMixin } from '../autocomplete.js'
|
|
3
|
+
import * as Util from '../utils.js'
|
|
3
4
|
|
|
4
|
-
class
|
|
5
|
+
export class AutocompleteCommunes extends SingleMixin(BaseAjax) {
|
|
5
6
|
createResult(item) {
|
|
6
7
|
return super.createResult({
|
|
7
8
|
value: item.code,
|
|
8
9
|
label: `${item.nom} (${item.code})`,
|
|
9
10
|
})
|
|
10
11
|
}
|
|
12
|
+
|
|
13
|
+
buildUrl(value) {
|
|
14
|
+
let url = this.url
|
|
15
|
+
let options = { q: encodeURIComponent(value) }
|
|
16
|
+
const re = /^(0[1-9]|[1-9][ABab\d])\d{3}$/gm
|
|
17
|
+
if (re.test(value)) {
|
|
18
|
+
url = "https://geo.api.gouv.fr/communes?code={code}&limit=5"
|
|
19
|
+
options = { code: encodeURIComponent(value) }
|
|
20
|
+
}
|
|
21
|
+
return Util.template(url, options)
|
|
22
|
+
}
|
|
11
23
|
}
|
|
12
24
|
|
|
13
25
|
export class Importer {
|
|
@@ -25,7 +37,7 @@ export class Importer {
|
|
|
25
37
|
textContent: "Importer les contours d'une commune française.",
|
|
26
38
|
})
|
|
27
39
|
const options = {
|
|
28
|
-
placeholder: '
|
|
40
|
+
placeholder: 'Nom ou code INSEE…',
|
|
29
41
|
url: 'https://geo.api.gouv.fr/communes?nom={q}&limit=5',
|
|
30
42
|
on_select: (choice) => {
|
|
31
43
|
importer.url = `https://geo.api.gouv.fr/communes?code=${choice.item.value}&format=geojson&geometry=contour`
|
|
@@ -34,7 +46,7 @@ export class Importer {
|
|
|
34
46
|
importer.dialog.close()
|
|
35
47
|
},
|
|
36
48
|
}
|
|
37
|
-
this.autocomplete = new
|
|
49
|
+
this.autocomplete = new AutocompleteCommunes(container, options)
|
|
38
50
|
|
|
39
51
|
importer.dialog.open({
|
|
40
52
|
template: container,
|
|
@@ -42,101 +42,129 @@ export class MapPermissions {
|
|
|
42
42
|
return !this.map.options.permissions.owner
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
return this.map
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
edit() {
|
|
50
|
-
if (this.map.options.editMode !== 'advanced') return
|
|
51
|
-
if (!this.map.options.umap_id) {
|
|
52
|
-
return Alert.info(translate('Please save the map first'))
|
|
53
|
-
}
|
|
54
|
-
const container = DomUtil.create('div', 'permissions-panel')
|
|
45
|
+
_editAnonymous(container) {
|
|
55
46
|
const fields = []
|
|
56
|
-
|
|
57
|
-
|
|
47
|
+
if (this.isOwner()) {
|
|
48
|
+
fields.push([
|
|
49
|
+
'options.edit_status',
|
|
50
|
+
{
|
|
51
|
+
handler: 'IntSelect',
|
|
52
|
+
label: translate('Who can edit'),
|
|
53
|
+
selectOptions: this.map.options.edit_statuses,
|
|
54
|
+
},
|
|
55
|
+
])
|
|
56
|
+
const builder = new U.FormBuilder(this, fields)
|
|
57
|
+
const form = builder.build()
|
|
58
|
+
container.appendChild(form)
|
|
59
|
+
|
|
58
60
|
if (this.options.anonymous_edit_url) {
|
|
59
|
-
|
|
61
|
+
DomUtil.createCopiableInput(
|
|
62
|
+
container,
|
|
63
|
+
translate('Secret edit link:'),
|
|
60
64
|
this.options.anonymous_edit_url
|
|
61
|
-
|
|
62
|
-
DomUtil.element({
|
|
63
|
-
tagName: 'p',
|
|
64
|
-
className: 'help-text',
|
|
65
|
-
innerHTML: helpText,
|
|
66
|
-
parent: container,
|
|
67
|
-
})
|
|
68
|
-
fields.push([
|
|
69
|
-
'options.edit_status',
|
|
70
|
-
{
|
|
71
|
-
handler: 'IntSelect',
|
|
72
|
-
label: translate('Who can edit'),
|
|
73
|
-
selectOptions: this.map.options.edit_statuses,
|
|
74
|
-
helpText: helpText,
|
|
75
|
-
},
|
|
76
|
-
])
|
|
65
|
+
)
|
|
77
66
|
}
|
|
78
|
-
|
|
79
|
-
if (this.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
67
|
+
|
|
68
|
+
if (this.map.options.user?.id) {
|
|
69
|
+
// We have a user, and this user has come through here, so they can edit the map, so let's allow to own the map.
|
|
70
|
+
// Note: real check is made on the back office anyway.
|
|
71
|
+
const advancedActions = DomUtil.createFieldset(
|
|
72
|
+
container,
|
|
73
|
+
translate('Advanced actions')
|
|
74
|
+
)
|
|
75
|
+
const advancedButtons = DomUtil.create('div', 'button-bar', advancedActions)
|
|
76
|
+
DomUtil.createButton(
|
|
77
|
+
'button',
|
|
78
|
+
advancedButtons,
|
|
79
|
+
translate('Attach the map to my account'),
|
|
80
|
+
this.attach,
|
|
81
|
+
this
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
_editWithOwner(container) {
|
|
88
|
+
const topFields = []
|
|
89
|
+
const collaboratorsFields = []
|
|
90
|
+
const fieldset = Utils.loadTemplate(
|
|
91
|
+
`<fieldset class="separator"><legend>${translate('Map')}</legend></fieldset>`
|
|
92
|
+
)
|
|
93
|
+
container.appendChild(fieldset)
|
|
94
|
+
if (this.isOwner()) {
|
|
95
|
+
topFields.push([
|
|
96
|
+
'options.edit_status',
|
|
97
|
+
{
|
|
98
|
+
handler: 'IntSelect',
|
|
99
|
+
label: translate('Who can edit'),
|
|
100
|
+
selectOptions: this.map.options.edit_statuses,
|
|
101
|
+
},
|
|
102
|
+
])
|
|
103
|
+
topFields.push([
|
|
104
|
+
'options.share_status',
|
|
105
|
+
{
|
|
106
|
+
handler: 'IntSelect',
|
|
107
|
+
label: translate('Who can view'),
|
|
108
|
+
selectOptions: this.map.options.share_statuses,
|
|
109
|
+
},
|
|
110
|
+
])
|
|
111
|
+
collaboratorsFields.push([
|
|
112
|
+
'options.owner',
|
|
113
|
+
{ handler: 'ManageOwner', label: translate("Map's owner") },
|
|
114
|
+
])
|
|
115
|
+
if (this.map.options.user?.teams?.length) {
|
|
116
|
+
collaboratorsFields.push([
|
|
117
|
+
'options.team',
|
|
90
118
|
{
|
|
91
|
-
handler: '
|
|
92
|
-
label: translate('
|
|
93
|
-
|
|
119
|
+
handler: 'ManageTeam',
|
|
120
|
+
label: translate('Attach map to a team'),
|
|
121
|
+
teams: this.map.options.user.teams,
|
|
94
122
|
},
|
|
95
123
|
])
|
|
96
|
-
fields.push([
|
|
97
|
-
'options.owner',
|
|
98
|
-
{ handler: 'ManageOwner', label: translate("Map's owner") },
|
|
99
|
-
])
|
|
100
|
-
if (this.map.options.user?.teams?.length) {
|
|
101
|
-
fields.push([
|
|
102
|
-
'options.team',
|
|
103
|
-
{
|
|
104
|
-
handler: 'ManageTeam',
|
|
105
|
-
label: translate('Attach map to a team'),
|
|
106
|
-
teams: this.map.options.user.teams,
|
|
107
|
-
},
|
|
108
|
-
])
|
|
109
|
-
}
|
|
110
124
|
}
|
|
111
|
-
fields.push([
|
|
112
|
-
'options.editors',
|
|
113
|
-
{ handler: 'ManageEditors', label: translate("Map's editors") },
|
|
114
|
-
])
|
|
115
125
|
}
|
|
126
|
+
collaboratorsFields.push([
|
|
127
|
+
'options.editors',
|
|
128
|
+
{ handler: 'ManageEditors', label: translate("Map's editors") },
|
|
129
|
+
])
|
|
116
130
|
|
|
117
|
-
const builder = new U.FormBuilder(this,
|
|
131
|
+
const builder = new U.FormBuilder(this, topFields)
|
|
118
132
|
const form = builder.build()
|
|
119
133
|
container.appendChild(form)
|
|
120
|
-
if (
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const advancedActions = DomUtil.createFieldset(
|
|
124
|
-
container,
|
|
125
|
-
translate('Advanced actions')
|
|
134
|
+
if (collaboratorsFields.length) {
|
|
135
|
+
const fieldset = Utils.loadTemplate(
|
|
136
|
+
`<fieldset class="separator"><legend>${translate('Manage collaborators')}</legend></fieldset>`
|
|
126
137
|
)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
138
|
+
container.appendChild(fieldset)
|
|
139
|
+
const builder = new U.FormBuilder(this, collaboratorsFields)
|
|
140
|
+
const form = builder.build()
|
|
141
|
+
container.appendChild(form)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
_editDatalayers(container) {
|
|
146
|
+
if (this.map.hasLayers()) {
|
|
147
|
+
const fieldset = Utils.loadTemplate(
|
|
148
|
+
`<fieldset class="separator"><legend>${translate('Datalayers')}</legend></fieldset>`
|
|
134
149
|
)
|
|
150
|
+
container.appendChild(fieldset)
|
|
151
|
+
this.map.eachDataLayer((datalayer) => {
|
|
152
|
+
datalayer.permissions.edit(fieldset)
|
|
153
|
+
})
|
|
135
154
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
edit() {
|
|
158
|
+
if (this.map.options.editMode !== 'advanced') return
|
|
159
|
+
if (!this.map.options.umap_id) {
|
|
160
|
+
Alert.info(translate('Please save the map first'))
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
const container = DomUtil.create('div', 'permissions-panel')
|
|
164
|
+
DomUtil.createTitle(container, translate('Update permissions'), 'icon-key')
|
|
165
|
+
if (this.isAnonymousMap()) this._editAnonymous(container)
|
|
166
|
+
else this._editWithOwner(container)
|
|
167
|
+
this._editDatalayers(container)
|
|
140
168
|
this.map.editPanel.open({ content: container, className: 'dark' })
|
|
141
169
|
}
|
|
142
170
|
|
|
@@ -150,15 +178,16 @@ export class MapPermissions {
|
|
|
150
178
|
}
|
|
151
179
|
|
|
152
180
|
async save() {
|
|
153
|
-
if (!this.isDirty) return
|
|
181
|
+
if (!this.isDirty) return
|
|
154
182
|
const formData = new FormData()
|
|
155
183
|
if (!this.isAnonymousMap() && this.options.editors) {
|
|
156
184
|
const editors = this.options.editors.map((u) => u.id)
|
|
157
185
|
for (let i = 0; i < this.options.editors.length; i++)
|
|
158
186
|
formData.append('editors', this.options.editors[i].id)
|
|
159
187
|
}
|
|
160
|
-
if (this.isOwner() || this.isAnonymousMap())
|
|
188
|
+
if (this.isOwner() || this.isAnonymousMap()) {
|
|
161
189
|
formData.append('edit_status', this.options.edit_status)
|
|
190
|
+
}
|
|
162
191
|
if (this.isOwner()) {
|
|
163
192
|
formData.append('owner', this.options.owner?.id)
|
|
164
193
|
formData.append('team', this.options.team?.id || '')
|
|
@@ -172,7 +201,6 @@ export class MapPermissions {
|
|
|
172
201
|
if (!error) {
|
|
173
202
|
this.commit()
|
|
174
203
|
this.isDirty = false
|
|
175
|
-
this.map.continueSaving()
|
|
176
204
|
this.map.fire('postsync')
|
|
177
205
|
}
|
|
178
206
|
}
|
|
@@ -197,9 +225,11 @@ export class MapPermissions {
|
|
|
197
225
|
}
|
|
198
226
|
|
|
199
227
|
getShareStatusDisplay() {
|
|
200
|
-
|
|
201
|
-
this.options.
|
|
202
|
-
|
|
228
|
+
if (this.map.options.share_statuses) {
|
|
229
|
+
return Object.fromEntries(this.map.options.share_statuses)[
|
|
230
|
+
this.options.share_status
|
|
231
|
+
]
|
|
232
|
+
}
|
|
203
233
|
}
|
|
204
234
|
}
|
|
205
235
|
|
|
@@ -225,7 +255,7 @@ export class DataLayerPermissions {
|
|
|
225
255
|
return this._isDirty
|
|
226
256
|
}
|
|
227
257
|
|
|
228
|
-
|
|
258
|
+
get map() {
|
|
229
259
|
return this.datalayer.map
|
|
230
260
|
}
|
|
231
261
|
|
|
@@ -238,7 +268,7 @@ export class DataLayerPermissions {
|
|
|
238
268
|
label: translate('Who can edit "{layer}"', {
|
|
239
269
|
layer: this.datalayer.getName(),
|
|
240
270
|
}),
|
|
241
|
-
selectOptions: this.
|
|
271
|
+
selectOptions: this.map.options.datalayer_edit_statuses,
|
|
242
272
|
},
|
|
243
273
|
],
|
|
244
274
|
]
|
|
@@ -250,16 +280,17 @@ export class DataLayerPermissions {
|
|
|
250
280
|
}
|
|
251
281
|
|
|
252
282
|
getUrl() {
|
|
253
|
-
return
|
|
254
|
-
map_id: this.
|
|
283
|
+
return this.map.urls.get('datalayer_permissions', {
|
|
284
|
+
map_id: this.map.options.umap_id,
|
|
255
285
|
pk: this.datalayer.umap_id,
|
|
256
286
|
})
|
|
257
287
|
}
|
|
288
|
+
|
|
258
289
|
async save() {
|
|
259
|
-
if (!this.isDirty) return
|
|
290
|
+
if (!this.isDirty) return
|
|
260
291
|
const formData = new FormData()
|
|
261
292
|
formData.append('edit_status', this.options.edit_status)
|
|
262
|
-
const [data, response, error] = await this.
|
|
293
|
+
const [data, response, error] = await this.map.server.post(
|
|
263
294
|
this.getUrl(),
|
|
264
295
|
{},
|
|
265
296
|
formData
|
|
@@ -267,7 +298,6 @@ export class DataLayerPermissions {
|
|
|
267
298
|
if (!error) {
|
|
268
299
|
this.commit()
|
|
269
300
|
this.isDirty = false
|
|
270
|
-
this.datalayer.map.continueSaving()
|
|
271
301
|
}
|
|
272
302
|
}
|
|
273
303
|
|
|
@@ -3,6 +3,7 @@ import { translate } from '../../i18n.js'
|
|
|
3
3
|
import { LayerMixin } from './base.js'
|
|
4
4
|
import * as Utils from '../../utils.js'
|
|
5
5
|
import { CircleMarker } from '../ui.js'
|
|
6
|
+
import colorbrewer from '../../../../vendors/colorbrewer/colorbrewer.js'
|
|
6
7
|
|
|
7
8
|
// Layer where each feature color is relative to the others,
|
|
8
9
|
// so we need all features before behing able to set one
|
|
@@ -74,6 +75,7 @@ const ClassifiedMixin = {
|
|
|
74
75
|
},
|
|
75
76
|
|
|
76
77
|
renderLegend: function (container) {
|
|
78
|
+
if (!this.datalayer.hasDataLoaded()) return
|
|
77
79
|
const parent = DomUtil.create('ul', '', container)
|
|
78
80
|
const items = this.getLegendItems()
|
|
79
81
|
for (const [color, label] of items) {
|