umap-project 2.9.3__py3-none-any.whl → 3.0.1__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/context_processors.py +1 -0
- umap/forms.py +1 -2
- umap/locale/de/LC_MESSAGES/django.mo +0 -0
- umap/locale/de/LC_MESSAGES/django.po +218 -96
- umap/locale/en/LC_MESSAGES/django.po +128 -52
- umap/locale/fr/LC_MESSAGES/django.mo +0 -0
- umap/locale/fr/LC_MESSAGES/django.po +128 -52
- umap/locale/hu/LC_MESSAGES/django.mo +0 -0
- umap/locale/hu/LC_MESSAGES/django.po +209 -88
- umap/locale/is/LC_MESSAGES/django.mo +0 -0
- umap/locale/is/LC_MESSAGES/django.po +296 -175
- umap/migrations/0027_map_tags.py +23 -0
- umap/models.py +13 -2
- umap/settings/base.py +23 -5
- umap/static/umap/base.css +41 -8
- umap/static/umap/content.css +72 -37
- umap/static/umap/css/bar.css +43 -21
- umap/static/umap/css/dialog.css +4 -1
- umap/static/umap/css/form.css +40 -27
- umap/static/umap/css/icon.css +11 -1
- umap/static/umap/css/importers.css +7 -0
- umap/static/umap/img/16-white.svg +23 -2
- umap/static/umap/img/16.svg +1 -1
- umap/static/umap/img/24.svg +4 -4
- umap/static/umap/img/home.svg +7 -0
- umap/static/umap/img/importers/banfr.svg +1 -0
- umap/static/umap/img/marker.svg +2 -5
- umap/static/umap/img/source/16-white.svg +24 -3
- umap/static/umap/img/source/16.svg +1 -1
- umap/static/umap/img/source/24.svg +5 -5
- umap/static/umap/img/target.svg +1 -0
- umap/static/umap/js/components/alerts/alert.js +0 -1
- umap/static/umap/js/modules/browser.js +4 -4
- umap/static/umap/js/modules/caption.js +1 -1
- umap/static/umap/js/modules/data/features.js +25 -25
- umap/static/umap/js/modules/data/layer.js +91 -97
- umap/static/umap/js/modules/facets.js +9 -5
- umap/static/umap/js/modules/form/builder.js +19 -27
- umap/static/umap/js/modules/form/fields.js +40 -14
- umap/static/umap/js/modules/formatter.js +1 -1
- umap/static/umap/js/modules/global.js +9 -5
- umap/static/umap/js/modules/help.js +18 -5
- umap/static/umap/js/modules/importer.js +5 -2
- umap/static/umap/js/modules/importers/banfr.js +93 -0
- umap/static/umap/js/modules/importers/cadastrefr.js +2 -2
- umap/static/umap/js/modules/importers/communesfr.js +1 -1
- umap/static/umap/js/modules/permissions.js +20 -10
- umap/static/umap/js/modules/rendering/icon.js +15 -2
- umap/static/umap/js/modules/rendering/layers/classified.js +7 -7
- umap/static/umap/js/modules/rendering/layers/cluster.js +2 -2
- umap/static/umap/js/modules/rendering/layers/heat.js +4 -4
- umap/static/umap/js/modules/rendering/map.js +14 -6
- umap/static/umap/js/modules/rendering/popup.js +2 -2
- umap/static/umap/js/modules/rendering/template.js +3 -3
- umap/static/umap/js/modules/rendering/ui.js +17 -11
- umap/static/umap/js/modules/rules.js +13 -16
- umap/static/umap/js/modules/schema.js +23 -1
- umap/static/umap/js/modules/share.js +1 -1
- umap/static/umap/js/modules/slideshow.js +1 -0
- umap/static/umap/js/modules/sync/engine.js +141 -19
- umap/static/umap/js/modules/sync/undo.js +101 -0
- umap/static/umap/js/modules/sync/updaters.js +51 -28
- umap/static/umap/js/modules/tableeditor.js +1 -1
- umap/static/umap/js/modules/ui/bar.js +61 -21
- umap/static/umap/js/modules/ui/tooltip.js +1 -1
- umap/static/umap/js/modules/umap.js +190 -176
- umap/static/umap/js/modules/utils.js +30 -4
- umap/static/umap/js/umap.controls.js +82 -38
- umap/static/umap/locale/am_ET.js +11 -6
- umap/static/umap/locale/am_ET.json +11 -6
- umap/static/umap/locale/ar.js +11 -6
- umap/static/umap/locale/ar.json +11 -6
- umap/static/umap/locale/ast.js +11 -6
- umap/static/umap/locale/ast.json +11 -6
- umap/static/umap/locale/bg.js +11 -6
- umap/static/umap/locale/bg.json +11 -6
- umap/static/umap/locale/br.js +12 -7
- umap/static/umap/locale/br.json +12 -7
- umap/static/umap/locale/ca.js +11 -6
- umap/static/umap/locale/ca.json +11 -6
- umap/static/umap/locale/cs_CZ.js +11 -6
- umap/static/umap/locale/cs_CZ.json +11 -6
- umap/static/umap/locale/da.js +11 -6
- umap/static/umap/locale/da.json +11 -6
- umap/static/umap/locale/de.js +47 -42
- umap/static/umap/locale/de.json +47 -42
- umap/static/umap/locale/el.js +11 -6
- umap/static/umap/locale/el.json +11 -6
- umap/static/umap/locale/en.js +11 -6
- umap/static/umap/locale/en.json +11 -6
- umap/static/umap/locale/en_US.json +11 -6
- umap/static/umap/locale/es.js +11 -6
- umap/static/umap/locale/es.json +11 -6
- umap/static/umap/locale/et.js +11 -6
- umap/static/umap/locale/et.json +11 -6
- umap/static/umap/locale/eu.js +11 -6
- umap/static/umap/locale/eu.json +11 -6
- umap/static/umap/locale/fa_IR.js +11 -6
- umap/static/umap/locale/fa_IR.json +11 -6
- umap/static/umap/locale/fi.js +11 -6
- umap/static/umap/locale/fi.json +11 -6
- umap/static/umap/locale/fr.js +11 -6
- umap/static/umap/locale/fr.json +11 -6
- umap/static/umap/locale/gl.js +12 -7
- umap/static/umap/locale/gl.json +12 -7
- umap/static/umap/locale/he.js +11 -6
- umap/static/umap/locale/he.json +11 -6
- umap/static/umap/locale/hr.js +11 -6
- umap/static/umap/locale/hr.json +11 -6
- umap/static/umap/locale/hu.js +25 -20
- umap/static/umap/locale/hu.json +25 -20
- umap/static/umap/locale/id.js +11 -6
- umap/static/umap/locale/id.json +11 -6
- umap/static/umap/locale/is.js +151 -146
- umap/static/umap/locale/is.json +151 -146
- umap/static/umap/locale/it.js +11 -6
- umap/static/umap/locale/it.json +11 -6
- umap/static/umap/locale/ja.js +11 -6
- umap/static/umap/locale/ja.json +11 -6
- umap/static/umap/locale/ko.js +11 -6
- umap/static/umap/locale/ko.json +11 -6
- umap/static/umap/locale/lt.js +11 -6
- umap/static/umap/locale/lt.json +11 -6
- umap/static/umap/locale/ms.js +11 -6
- umap/static/umap/locale/ms.json +11 -6
- umap/static/umap/locale/nl.js +12 -7
- umap/static/umap/locale/nl.json +12 -7
- umap/static/umap/locale/no.js +11 -6
- umap/static/umap/locale/no.json +11 -6
- umap/static/umap/locale/pl.js +11 -6
- umap/static/umap/locale/pl.json +11 -6
- umap/static/umap/locale/pl_PL.json +11 -6
- umap/static/umap/locale/pt.js +11 -6
- umap/static/umap/locale/pt.json +11 -6
- umap/static/umap/locale/pt_BR.js +11 -6
- umap/static/umap/locale/pt_BR.json +11 -6
- umap/static/umap/locale/pt_PT.js +11 -6
- umap/static/umap/locale/pt_PT.json +11 -6
- umap/static/umap/locale/ro.js +11 -6
- umap/static/umap/locale/ro.json +11 -6
- umap/static/umap/locale/ru.js +11 -6
- umap/static/umap/locale/ru.json +11 -6
- umap/static/umap/locale/sk_SK.js +11 -6
- umap/static/umap/locale/sk_SK.json +11 -6
- umap/static/umap/locale/sl.js +11 -6
- umap/static/umap/locale/sl.json +11 -6
- umap/static/umap/locale/sr.js +11 -6
- umap/static/umap/locale/sr.json +11 -6
- umap/static/umap/locale/sv.js +11 -6
- umap/static/umap/locale/sv.json +11 -6
- umap/static/umap/locale/th_TH.js +11 -6
- umap/static/umap/locale/th_TH.json +11 -6
- umap/static/umap/locale/tr.js +11 -6
- umap/static/umap/locale/tr.json +11 -6
- umap/static/umap/locale/uk_UA.js +11 -6
- umap/static/umap/locale/uk_UA.json +11 -6
- umap/static/umap/locale/vi.js +11 -6
- umap/static/umap/locale/vi.json +11 -6
- umap/static/umap/locale/vi_VN.json +11 -6
- umap/static/umap/locale/zh.js +11 -6
- umap/static/umap/locale/zh.json +11 -6
- umap/static/umap/locale/zh_CN.json +11 -6
- umap/static/umap/locale/zh_TW.Big5.json +11 -6
- umap/static/umap/locale/zh_TW.js +19 -14
- umap/static/umap/locale/zh_TW.json +19 -14
- umap/static/umap/map.css +58 -28
- umap/static/umap/unittests/sync.js +0 -57
- umap/static/umap/unittests/utils.js +47 -0
- umap/static/umap/vars.css +5 -2
- umap/static/umap/vendors/photon/leaflet.photon.js +3 -0
- umap/sync/payloads.py +3 -2
- umap/templates/auth/user_detail.html +1 -1
- umap/templates/auth/user_stars.html +1 -1
- umap/templates/umap/content.html +17 -12
- umap/templates/umap/home.html +7 -5
- umap/templates/umap/map_fragment.html +1 -1
- umap/templates/umap/map_list.html +20 -13
- umap/templates/umap/search.html +7 -3
- umap/templates/umap/search_bar.html +13 -11
- umap/templates/umap/team_detail.html +1 -1
- umap/tests/base.py +2 -1
- umap/tests/fixtures/remote_data.umap +55 -0
- umap/tests/fixtures/test_upload_data_with_iconurl.umap +122 -0
- umap/tests/integration/test_browser.py +1 -3
- umap/tests/integration/test_conditional_rules.py +3 -0
- umap/tests/integration/test_edit_datalayer.py +2 -7
- umap/tests/integration/test_edit_map.py +15 -0
- umap/tests/integration/test_edit_polygon.py +1 -2
- umap/tests/integration/test_import.py +59 -2
- umap/tests/integration/test_optimistic_merge.py +4 -3
- umap/tests/integration/test_owned_map.py +0 -1
- umap/tests/integration/test_save.py +2 -4
- umap/tests/integration/test_undo_redo.py +267 -0
- umap/tests/integration/test_websocket_sync.py +78 -11
- umap/tests/settings.py +1 -3
- umap/tests/test_datalayer_s3.py +1 -0
- umap/tests/test_map_views.py +1 -0
- umap/tests/test_views.py +34 -0
- umap/utils.py +1 -1
- umap/views.py +23 -2
- {umap_project-2.9.3.dist-info → umap_project-3.0.1.dist-info}/METADATA +13 -12
- {umap_project-2.9.3.dist-info → umap_project-3.0.1.dist-info}/RECORD +206 -208
- umap/static/umap/js/modules/saving.js +0 -52
- umap/static/umap/test/.eslintrc +0 -21
- umap/static/umap/test/DataLayer.js +0 -463
- umap/static/umap/test/Feature.js +0 -131
- umap/static/umap/test/Map.js +0 -37
- umap/static/umap/test/Marker.js +0 -126
- umap/static/umap/test/Polygon.js +0 -111
- umap/static/umap/test/Polyline.js +0 -286
- umap/static/umap/test/Util.js +0 -28
- umap/static/umap/test/_pre.js +0 -455
- umap/static/umap/test/index.html +0 -139
- {umap_project-2.9.3.dist-info → umap_project-3.0.1.dist-info}/WHEEL +0 -0
- {umap_project-2.9.3.dist-info → umap_project-3.0.1.dist-info}/entry_points.txt +0 -0
- {umap_project-2.9.3.dist-info → umap_project-3.0.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,44 +1,41 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DomUtil,
|
|
3
3
|
Util as LeafletUtil,
|
|
4
|
-
stamp,
|
|
5
4
|
latLngBounds,
|
|
5
|
+
stamp,
|
|
6
6
|
} from '../../vendors/leaflet/leaflet-src.esm.js'
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import { SyncEngine } from './sync/engine.js'
|
|
12
|
-
import { LeafletMap } from './rendering/map.js'
|
|
13
|
-
import URLs from './urls.js'
|
|
14
|
-
import { Panel, EditPanel, FullPanel } from './ui/panel.js'
|
|
15
|
-
import Dialog from './ui/dialog.js'
|
|
16
|
-
import { BottomBar, TopBar, EditBar } from './ui/bar.js'
|
|
17
|
-
import Tooltip from './ui/tooltip.js'
|
|
18
|
-
import ContextMenu from './ui/contextmenu.js'
|
|
19
|
-
import { Request, ServerRequest } from './request.js'
|
|
20
|
-
import Help from './help.js'
|
|
21
|
-
import { Formatter } from './formatter.js'
|
|
22
|
-
import Slideshow from './slideshow.js'
|
|
23
|
-
import { MapPermissions } from './permissions.js'
|
|
24
|
-
import { SCHEMA } from './schema.js'
|
|
25
|
-
import { DataLayer } from './data/layer.js'
|
|
26
|
-
import Facets from './facets.js'
|
|
7
|
+
import {
|
|
8
|
+
uMapAlert as Alert,
|
|
9
|
+
uMapAlertCreation as AlertCreation,
|
|
10
|
+
} from '../components/alerts/alert.js'
|
|
27
11
|
import Browser from './browser.js'
|
|
28
12
|
import Caption from './caption.js'
|
|
13
|
+
import { DataLayer } from './data/layer.js'
|
|
14
|
+
import Facets from './facets.js'
|
|
15
|
+
import { MutatingForm } from './form/builder.js'
|
|
16
|
+
import { Formatter } from './formatter.js'
|
|
17
|
+
import Help from './help.js'
|
|
18
|
+
import { getLocale, setLocale, translate } from './i18n.js'
|
|
29
19
|
import Importer from './importer.js'
|
|
20
|
+
import Orderable from './orderable.js'
|
|
21
|
+
import { MapPermissions } from './permissions.js'
|
|
22
|
+
import { LeafletMap } from './rendering/map.js'
|
|
23
|
+
import { Request, ServerRequest } from './request.js'
|
|
30
24
|
import Rules from './rules.js'
|
|
25
|
+
import { SCHEMA } from './schema.js'
|
|
31
26
|
import Share from './share.js'
|
|
32
|
-
import
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
import
|
|
37
|
-
import {
|
|
27
|
+
import Slideshow from './slideshow.js'
|
|
28
|
+
import { SyncEngine } from './sync/engine.js'
|
|
29
|
+
import { BottomBar, EditBar, TopBar } from './ui/bar.js'
|
|
30
|
+
import ContextMenu from './ui/contextmenu.js'
|
|
31
|
+
import Dialog from './ui/dialog.js'
|
|
32
|
+
import { EditPanel, FullPanel, Panel } from './ui/panel.js'
|
|
33
|
+
import Tooltip from './ui/tooltip.js'
|
|
34
|
+
import URLs from './urls.js'
|
|
35
|
+
import * as Utils from './utils.js'
|
|
38
36
|
|
|
39
|
-
export default class Umap
|
|
37
|
+
export default class Umap {
|
|
40
38
|
constructor(element, geojson) {
|
|
41
|
-
super()
|
|
42
39
|
// We need to call async function in the init process,
|
|
43
40
|
// the init itself does not need to be awaited, but some calls
|
|
44
41
|
// in the process must be blocker
|
|
@@ -96,15 +93,19 @@ export default class Umap extends ServerStored {
|
|
|
96
93
|
this._leafletMap.latLng(center)
|
|
97
94
|
}
|
|
98
95
|
|
|
96
|
+
// Needed for permissions
|
|
97
|
+
this.syncEngine = new SyncEngine(this)
|
|
98
|
+
this.sync = this.syncEngine.proxy(this)
|
|
99
|
+
|
|
99
100
|
// Needed to render controls
|
|
100
101
|
this.permissions = new MapPermissions(this)
|
|
101
102
|
this.urls = new URLs(this.properties.urls)
|
|
102
103
|
this.slideshow = new Slideshow(this, this._leafletMap)
|
|
103
104
|
|
|
104
|
-
this._leafletMap.setup()
|
|
105
|
-
|
|
106
105
|
if (geojson.properties.schema) this.overrideSchema(geojson.properties.schema)
|
|
107
106
|
|
|
107
|
+
this._leafletMap.setup()
|
|
108
|
+
|
|
108
109
|
this.panel = new Panel(this, this._leafletMap)
|
|
109
110
|
this.dialog = new Dialog({ className: 'dark' })
|
|
110
111
|
this.topBar = new TopBar(this, this._leafletMap._controlContainer)
|
|
@@ -130,9 +131,6 @@ export default class Umap extends ServerStored {
|
|
|
130
131
|
this.share = new Share(this)
|
|
131
132
|
this.rules = new Rules(this)
|
|
132
133
|
|
|
133
|
-
this.syncEngine = new SyncEngine(this)
|
|
134
|
-
this.sync = this.syncEngine.proxy(this)
|
|
135
|
-
|
|
136
134
|
if (this.hasEditMode()) {
|
|
137
135
|
this.editPanel = new EditPanel(this, this._leafletMap)
|
|
138
136
|
this.fullPanel = new FullPanel(this, this._leafletMap)
|
|
@@ -196,7 +194,6 @@ export default class Umap extends ServerStored {
|
|
|
196
194
|
// Creation mode
|
|
197
195
|
if (!this.id) {
|
|
198
196
|
if (!this.properties.preview) {
|
|
199
|
-
this.isDirty = true
|
|
200
197
|
this.enableEdit()
|
|
201
198
|
}
|
|
202
199
|
this._defaultExtent = true
|
|
@@ -212,10 +209,14 @@ export default class Umap extends ServerStored {
|
|
|
212
209
|
this.propagate()
|
|
213
210
|
}
|
|
214
211
|
|
|
215
|
-
window.onbeforeunload = () => (this.editEnabled &&
|
|
212
|
+
window.onbeforeunload = () => (this.editEnabled && this.isDirty) || null
|
|
216
213
|
this.backup()
|
|
217
214
|
}
|
|
218
215
|
|
|
216
|
+
get isDirty() {
|
|
217
|
+
return this.sync._undoManager.isDirty()
|
|
218
|
+
}
|
|
219
|
+
|
|
219
220
|
get editedFeature() {
|
|
220
221
|
return this._editedFeature
|
|
221
222
|
}
|
|
@@ -349,7 +350,7 @@ export default class Umap extends ServerStored {
|
|
|
349
350
|
const items = []
|
|
350
351
|
if (this.hasEditMode()) {
|
|
351
352
|
if (this.editEnabled) {
|
|
352
|
-
if (!
|
|
353
|
+
if (!this.isDirty) {
|
|
353
354
|
items.push({
|
|
354
355
|
label: this.help.displayLabel('STOP_EDIT'),
|
|
355
356
|
action: () => this.disableEdit(),
|
|
@@ -498,92 +499,88 @@ export default class Umap extends ServerStored {
|
|
|
498
499
|
}
|
|
499
500
|
|
|
500
501
|
initShortcuts() {
|
|
501
|
-
const
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
this.importer.dialog.
|
|
505
|
-
|
|
506
|
-
this._leafletMap.editTools.
|
|
507
|
-
|
|
508
|
-
this._leafletMap.measureTools.
|
|
509
|
-
|
|
510
|
-
this.fullPanel?.
|
|
511
|
-
|
|
512
|
-
this.editPanel?.
|
|
513
|
-
|
|
514
|
-
this.panel.
|
|
515
|
-
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// From now on, only ctrl/meta shortcut
|
|
519
|
-
if (!(event.ctrlKey || event.metaKey) || event.shiftKey) return
|
|
520
|
-
|
|
521
|
-
if (event.key === 'f') {
|
|
522
|
-
event.stopPropagation()
|
|
523
|
-
event.preventDefault()
|
|
524
|
-
this.search()
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
/* Edit mode only shortcuts */
|
|
528
|
-
if (!this.hasEditMode()) return
|
|
529
|
-
|
|
530
|
-
// Edit mode Off
|
|
531
|
-
if (!this.editEnabled) {
|
|
532
|
-
switch (event.key) {
|
|
533
|
-
case 'e':
|
|
534
|
-
event.stopPropagation()
|
|
535
|
-
event.preventDefault()
|
|
536
|
-
this.enableEdit()
|
|
537
|
-
break
|
|
538
|
-
}
|
|
539
|
-
return
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
// Edit mode on
|
|
543
|
-
let used = true
|
|
544
|
-
switch (event.key) {
|
|
545
|
-
case 'e':
|
|
546
|
-
if (!SAVEMANAGER.isDirty) this.disableEdit()
|
|
547
|
-
break
|
|
548
|
-
case 's':
|
|
549
|
-
if (SAVEMANAGER.isDirty) this.saveAll()
|
|
550
|
-
break
|
|
551
|
-
case 'z':
|
|
552
|
-
if (Utils.isWritable(event.target)) {
|
|
553
|
-
used = false
|
|
554
|
-
break
|
|
502
|
+
const shortcuts = {
|
|
503
|
+
Escape: {
|
|
504
|
+
do: () => {
|
|
505
|
+
if (this.importer.dialog.visible) {
|
|
506
|
+
this.importer.dialog.close()
|
|
507
|
+
} else if (this.editEnabled && this._leafletMap.editTools.drawing()) {
|
|
508
|
+
this._leafletMap.editTools.onEscape()
|
|
509
|
+
} else if (this._leafletMap.measureTools.enabled()) {
|
|
510
|
+
this._leafletMap.measureTools.stopDrawing()
|
|
511
|
+
} else if (this.fullPanel?.isOpen()) {
|
|
512
|
+
this.fullPanel?.close()
|
|
513
|
+
} else if (this.editPanel?.isOpen()) {
|
|
514
|
+
this.editPanel?.close()
|
|
515
|
+
} else if (this.panel.isOpen()) {
|
|
516
|
+
this.panel.close()
|
|
555
517
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
this.
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
518
|
+
},
|
|
519
|
+
},
|
|
520
|
+
'Ctrl+f': {
|
|
521
|
+
do: () => {
|
|
522
|
+
this.search()
|
|
523
|
+
},
|
|
524
|
+
},
|
|
525
|
+
'Ctrl+e': {
|
|
526
|
+
if: () => this.hasEditMode(),
|
|
527
|
+
do: () => {
|
|
528
|
+
console.log('doing')
|
|
529
|
+
if (!this.editEnabled) this.enableEdit()
|
|
530
|
+
else if (!this.isDirty) this.disableEdit()
|
|
531
|
+
},
|
|
532
|
+
},
|
|
533
|
+
'Ctrl+s': {
|
|
534
|
+
if: () => this.editEnabled && this.isDirty,
|
|
535
|
+
do: () => this.saveAll(),
|
|
536
|
+
},
|
|
537
|
+
'Ctrl+z': {
|
|
538
|
+
if: () => this.editEnabled && !Utils.isWritable(event.target),
|
|
539
|
+
do: () => this.sync._undoManager.undo(),
|
|
540
|
+
},
|
|
541
|
+
'Ctrl+Shift+Z': {
|
|
542
|
+
if: () => this.editEnabled && !Utils.isWritable(event.target),
|
|
543
|
+
do: () => this.sync._undoManager.redo(),
|
|
544
|
+
},
|
|
545
|
+
'Ctrl+m': {
|
|
546
|
+
if: () => this.editEnabled,
|
|
547
|
+
do: () => this._leafletMap.editTools.startMarker(),
|
|
548
|
+
},
|
|
549
|
+
'Ctrl+p': {
|
|
550
|
+
if: () => this.editEnabled,
|
|
551
|
+
do: () => this._leafletMap.editTools.startPolygon(),
|
|
552
|
+
},
|
|
553
|
+
'Ctrl+l': {
|
|
554
|
+
if: () => this.editEnabled,
|
|
555
|
+
do: () => this._leafletMap.editTools.startPolyline(),
|
|
556
|
+
},
|
|
557
|
+
'Ctrl+i': {
|
|
558
|
+
if: () => this.editEnabled,
|
|
559
|
+
do: () => this.importer.open(),
|
|
560
|
+
},
|
|
561
|
+
'Ctrl+o': {
|
|
562
|
+
if: () => this.editEnabled,
|
|
563
|
+
do: () => this.importer.openFiles(),
|
|
564
|
+
},
|
|
565
|
+
'Ctrl+h': {
|
|
566
|
+
if: () => this.editEnabled,
|
|
567
|
+
do: () => this.help.showGetStarted(),
|
|
568
|
+
},
|
|
569
|
+
}
|
|
570
|
+
const onKeyDown = (event) => {
|
|
571
|
+
const shiftKey = event.shiftKey ? 'Shift+' : ''
|
|
572
|
+
const altKey = event.altKey ? 'Alt+' : ''
|
|
573
|
+
const ctrlKey = event.ctrlKey || event.metaKey ? 'Ctrl+' : ''
|
|
574
|
+
const combination = `${ctrlKey}${shiftKey}${altKey}${event.key}`
|
|
575
|
+
|
|
576
|
+
const shortcut = shortcuts[combination]
|
|
577
|
+
if (shortcut && (!shortcut.if || shortcut.if())) {
|
|
578
|
+
shortcut.do()
|
|
582
579
|
event.stopPropagation()
|
|
583
580
|
event.preventDefault()
|
|
584
581
|
}
|
|
585
582
|
}
|
|
586
|
-
document.addEventListener('keydown',
|
|
583
|
+
document.addEventListener('keydown', onKeyDown)
|
|
587
584
|
}
|
|
588
585
|
|
|
589
586
|
async initDataLayers(datalayers) {
|
|
@@ -671,10 +668,10 @@ export default class Umap extends ServerStored {
|
|
|
671
668
|
}
|
|
672
669
|
|
|
673
670
|
async saveAll() {
|
|
674
|
-
if (!
|
|
671
|
+
if (!this.isDirty) return
|
|
675
672
|
if (this._defaultExtent) this._setCenterAndZoom()
|
|
676
673
|
this.backup()
|
|
677
|
-
await
|
|
674
|
+
await this.sync.save()
|
|
678
675
|
// Do a blind render for now, as we are not sure what could
|
|
679
676
|
// have changed, we'll be more subtil when we'll remove the
|
|
680
677
|
// save action
|
|
@@ -685,7 +682,6 @@ export default class Umap extends ServerStored {
|
|
|
685
682
|
Alert.success(translate('Map has been saved!'))
|
|
686
683
|
})
|
|
687
684
|
}
|
|
688
|
-
this.sync.saved()
|
|
689
685
|
this.fire('saved')
|
|
690
686
|
}
|
|
691
687
|
|
|
@@ -757,6 +753,12 @@ export default class Umap extends ServerStored {
|
|
|
757
753
|
const form = builder.build()
|
|
758
754
|
container.appendChild(form)
|
|
759
755
|
|
|
756
|
+
const tags = DomUtil.createFieldset(container, translate('Tags'))
|
|
757
|
+
const tagsFields = ['properties.tags']
|
|
758
|
+
const tagsBuilder = new MutatingForm(this, tagsFields, {
|
|
759
|
+
umap: this,
|
|
760
|
+
})
|
|
761
|
+
tags.appendChild(tagsBuilder.build())
|
|
760
762
|
const credits = DomUtil.createFieldset(container, translate('Credits'))
|
|
761
763
|
const creditsFields = [
|
|
762
764
|
'properties.licence',
|
|
@@ -1019,35 +1021,36 @@ export default class Umap extends ServerStored {
|
|
|
1019
1021
|
'button',
|
|
1020
1022
|
boundsButtons,
|
|
1021
1023
|
translate('Use current bounds'),
|
|
1022
|
-
|
|
1024
|
+
() => {
|
|
1023
1025
|
const bounds = this._leafletMap.getBounds()
|
|
1026
|
+
const oldLimitBounds = { ...this.properties.limitBounds }
|
|
1024
1027
|
this.properties.limitBounds.south = LeafletUtil.formatNum(bounds.getSouth())
|
|
1025
1028
|
this.properties.limitBounds.west = LeafletUtil.formatNum(bounds.getWest())
|
|
1026
1029
|
this.properties.limitBounds.north = LeafletUtil.formatNum(bounds.getNorth())
|
|
1027
1030
|
this.properties.limitBounds.east = LeafletUtil.formatNum(bounds.getEast())
|
|
1028
1031
|
boundsBuilder.fetchAll()
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
this
|
|
1035
|
-
)
|
|
1036
|
-
DomUtil.createButton(
|
|
1037
|
-
'button',
|
|
1038
|
-
boundsButtons,
|
|
1039
|
-
translate('Empty'),
|
|
1040
|
-
function () {
|
|
1041
|
-
this.properties.limitBounds.south = null
|
|
1042
|
-
this.properties.limitBounds.west = null
|
|
1043
|
-
this.properties.limitBounds.north = null
|
|
1044
|
-
this.properties.limitBounds.east = null
|
|
1045
|
-
boundsBuilder.fetchAll()
|
|
1046
|
-
this.isDirty = true
|
|
1032
|
+
this.sync.update(
|
|
1033
|
+
'properties.limitBounds',
|
|
1034
|
+
this.properties.limitBounds,
|
|
1035
|
+
oldLimitBounds
|
|
1036
|
+
)
|
|
1047
1037
|
this._leafletMap.handleLimitBounds()
|
|
1048
|
-
}
|
|
1049
|
-
this
|
|
1038
|
+
}
|
|
1050
1039
|
)
|
|
1040
|
+
DomUtil.createButton('button', boundsButtons, translate('Empty'), () => {
|
|
1041
|
+
const oldLimitBounds = { ...this.properties.limitBounds }
|
|
1042
|
+
this.properties.limitBounds.south = null
|
|
1043
|
+
this.properties.limitBounds.west = null
|
|
1044
|
+
this.properties.limitBounds.north = null
|
|
1045
|
+
this.properties.limitBounds.east = null
|
|
1046
|
+
boundsBuilder.fetchAll()
|
|
1047
|
+
this._leafletMap.handleLimitBounds()
|
|
1048
|
+
this.sync.update(
|
|
1049
|
+
'properties.limitBounds',
|
|
1050
|
+
this.properties.limitBounds,
|
|
1051
|
+
oldLimitBounds
|
|
1052
|
+
)
|
|
1053
|
+
})
|
|
1051
1054
|
}
|
|
1052
1055
|
|
|
1053
1056
|
_editSlideshow(container) {
|
|
@@ -1160,23 +1163,7 @@ export default class Umap extends ServerStored {
|
|
|
1160
1163
|
})
|
|
1161
1164
|
}
|
|
1162
1165
|
|
|
1163
|
-
reset() {
|
|
1164
|
-
if (this._leafletMap.editTools) this._leafletMap.editTools.stopDrawing()
|
|
1165
|
-
this.resetProperties()
|
|
1166
|
-
this.datalayersIndex = [].concat(this._datalayersIndex_bk)
|
|
1167
|
-
// Iter over all datalayers, including deleted if any.
|
|
1168
|
-
for (const datalayer of Object.values(this.datalayers)) {
|
|
1169
|
-
if (datalayer.isDeleted) datalayer.connectToMap()
|
|
1170
|
-
if (datalayer.isDirty) datalayer.reset()
|
|
1171
|
-
}
|
|
1172
|
-
this.ensurePanesOrder()
|
|
1173
|
-
this._leafletMap.initTileLayers()
|
|
1174
|
-
this.onDataLayersChanged()
|
|
1175
|
-
this.isDirty = !this.id
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
1166
|
async save() {
|
|
1179
|
-
this.rules.commit()
|
|
1180
1167
|
const geojson = {
|
|
1181
1168
|
type: 'Feature',
|
|
1182
1169
|
geometry: this.geometry(),
|
|
@@ -1185,6 +1172,7 @@ export default class Umap extends ServerStored {
|
|
|
1185
1172
|
const formData = new FormData()
|
|
1186
1173
|
formData.append('name', this.properties.name)
|
|
1187
1174
|
formData.append('center', JSON.stringify(this.geometry()))
|
|
1175
|
+
formData.append('tags', this.properties.tags || [])
|
|
1188
1176
|
formData.append('settings', JSON.stringify(geojson))
|
|
1189
1177
|
const uri = this.urls.get('map_save', { map_id: this.id })
|
|
1190
1178
|
const [data, _, error] = await this.server.post(uri, {}, formData)
|
|
@@ -1301,16 +1289,6 @@ export default class Umap extends ServerStored {
|
|
|
1301
1289
|
this._leafletMap.fire(name)
|
|
1302
1290
|
}
|
|
1303
1291
|
|
|
1304
|
-
askForReset(e) {
|
|
1305
|
-
if (this.getProperty('syncEnabled')) return
|
|
1306
|
-
this.dialog
|
|
1307
|
-
.confirm(translate('Are you sure you want to cancel your changes?'))
|
|
1308
|
-
.then(() => {
|
|
1309
|
-
this.reset()
|
|
1310
|
-
this.disableEdit()
|
|
1311
|
-
})
|
|
1312
|
-
}
|
|
1313
|
-
|
|
1314
1292
|
async initSyncEngine() {
|
|
1315
1293
|
// this.properties.websocketEnabled is set by the server admin
|
|
1316
1294
|
if (this.properties.websocketEnabled === false) return
|
|
@@ -1324,11 +1302,14 @@ export default class Umap extends ServerStored {
|
|
|
1324
1302
|
|
|
1325
1303
|
getSyncMetadata() {
|
|
1326
1304
|
return {
|
|
1327
|
-
engine: this.sync,
|
|
1328
1305
|
subject: 'map',
|
|
1329
1306
|
}
|
|
1330
1307
|
}
|
|
1331
1308
|
|
|
1309
|
+
onPropertiesUpdated(fields = []) {
|
|
1310
|
+
this._leafletMap.pullProperties()
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1332
1313
|
render(fields = []) {
|
|
1333
1314
|
// Propagate will remove the fields it has already
|
|
1334
1315
|
// processed
|
|
@@ -1344,6 +1325,9 @@ export default class Umap extends ServerStored {
|
|
|
1344
1325
|
this.bottomBar.redraw()
|
|
1345
1326
|
break
|
|
1346
1327
|
case 'data':
|
|
1328
|
+
if (fields.includes('properties.rules')) {
|
|
1329
|
+
this.rules.load()
|
|
1330
|
+
}
|
|
1347
1331
|
this.eachVisibleDataLayer((datalayer) => {
|
|
1348
1332
|
datalayer.redraw()
|
|
1349
1333
|
})
|
|
@@ -1518,7 +1502,7 @@ export default class Umap extends ServerStored {
|
|
|
1518
1502
|
const form = builder.build()
|
|
1519
1503
|
row.appendChild(form)
|
|
1520
1504
|
row.classList.toggle('off', !datalayer.isVisible())
|
|
1521
|
-
row.dataset.id =
|
|
1505
|
+
row.dataset.id = datalayer.id
|
|
1522
1506
|
})
|
|
1523
1507
|
const onReorder = (src, dst, initialIndex, finalIndex) => {
|
|
1524
1508
|
const movedLayer = this.datalayers[src.dataset.id]
|
|
@@ -1549,7 +1533,7 @@ export default class Umap extends ServerStored {
|
|
|
1549
1533
|
}
|
|
1550
1534
|
|
|
1551
1535
|
getDataLayerByUmapId(id) {
|
|
1552
|
-
const datalayer = this.
|
|
1536
|
+
const datalayer = this.datalayers[id]
|
|
1553
1537
|
if (!datalayer) throw new Error(`Can't find datalayer with id ${id}`)
|
|
1554
1538
|
return datalayer
|
|
1555
1539
|
}
|
|
@@ -1630,7 +1614,16 @@ export default class Umap extends ServerStored {
|
|
|
1630
1614
|
|
|
1631
1615
|
importRaw(rawData) {
|
|
1632
1616
|
const importedData = JSON.parse(rawData)
|
|
1633
|
-
|
|
1617
|
+
let remoteOrigin = ''
|
|
1618
|
+
if (importedData.uri) {
|
|
1619
|
+
const uri = new URL(importedData.uri)
|
|
1620
|
+
if (uri.origin !== window.location.origin) {
|
|
1621
|
+
remoteOrigin = uri.origin
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
if (importedData.properties?.iconUrl?.startsWith('/')) {
|
|
1625
|
+
importedData.properties.iconUrl = remoteOrigin + importedData.properties.iconUrl
|
|
1626
|
+
}
|
|
1634
1627
|
this.setProperties(importedData.properties)
|
|
1635
1628
|
|
|
1636
1629
|
if (importedData.geometry) {
|
|
@@ -1642,6 +1635,9 @@ export default class Umap extends ServerStored {
|
|
|
1642
1635
|
delete geojson._storage
|
|
1643
1636
|
}
|
|
1644
1637
|
delete geojson._umap_options?.id // Never trust an id at this stage
|
|
1638
|
+
if (geojson._umap_options?.iconUrl?.startsWith('/')) {
|
|
1639
|
+
geojson._umap_options.iconUrl = remoteOrigin + geojson._umap_options.iconUrl
|
|
1640
|
+
}
|
|
1645
1641
|
const dataLayer = this.createDirtyDataLayer(geojson._umap_options)
|
|
1646
1642
|
dataLayer.fromUmapGeoJSON(geojson)
|
|
1647
1643
|
}
|
|
@@ -1653,7 +1649,6 @@ export default class Umap extends ServerStored {
|
|
|
1653
1649
|
)
|
|
1654
1650
|
this.render(fields)
|
|
1655
1651
|
this._leafletMap._setDefaultCenter()
|
|
1656
|
-
this.isDirty = true
|
|
1657
1652
|
}
|
|
1658
1653
|
|
|
1659
1654
|
importUmapFile(file) {
|
|
@@ -1747,14 +1742,33 @@ export default class Umap extends ServerStored {
|
|
|
1747
1742
|
}
|
|
1748
1743
|
|
|
1749
1744
|
setCenterAndZoom() {
|
|
1750
|
-
this._setCenterAndZoom()
|
|
1745
|
+
this._setCenterAndZoom(true)
|
|
1751
1746
|
Alert.success(translate('The zoom and center have been modified.'))
|
|
1752
1747
|
}
|
|
1753
1748
|
|
|
1754
|
-
_setCenterAndZoom() {
|
|
1749
|
+
_setCenterAndZoom(manual) {
|
|
1750
|
+
const oldCenter = { ...this.properties.center }
|
|
1751
|
+
const oldZoom = this.properties.zoom
|
|
1755
1752
|
this.properties.center = this._leafletMap.getCenter()
|
|
1756
1753
|
this.properties.zoom = this._leafletMap.getZoom()
|
|
1757
|
-
this.isDirty = true
|
|
1758
1754
|
this._defaultExtent = false
|
|
1755
|
+
if (manual) {
|
|
1756
|
+
this.sync.startBatch()
|
|
1757
|
+
this.sync.update('properties.center', this.properties.center, oldCenter)
|
|
1758
|
+
this.sync.update('properties.zoom', this.properties.zoom, oldZoom)
|
|
1759
|
+
this.sync.commitBatch()
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
getStaticPathFor(name) {
|
|
1764
|
+
return SCHEMA.iconUrl.default.replace('marker.svg', name)
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
undo() {
|
|
1768
|
+
this.sync._undoManager.undo()
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
redo() {
|
|
1772
|
+
this.sync._undoManager.redo()
|
|
1759
1773
|
}
|
|
1760
1774
|
}
|
|
@@ -117,6 +117,7 @@ export function escapeHTML(s) {
|
|
|
117
117
|
'dd',
|
|
118
118
|
'b',
|
|
119
119
|
'i',
|
|
120
|
+
'kbd',
|
|
120
121
|
],
|
|
121
122
|
ADD_ATTR: [
|
|
122
123
|
'target',
|
|
@@ -125,6 +126,7 @@ export function escapeHTML(s) {
|
|
|
125
126
|
'frameborder',
|
|
126
127
|
'scrolling',
|
|
127
128
|
'controls',
|
|
129
|
+
'class',
|
|
128
130
|
],
|
|
129
131
|
ALLOWED_ATTR: ['href', 'src', 'width', 'height', 'style', 'dir', 'title', 'type'],
|
|
130
132
|
// Added: `geo:` URL scheme as defined in RFC5870:
|
|
@@ -368,10 +370,13 @@ export function isDataImage(value) {
|
|
|
368
370
|
* characters and no diacritics.
|
|
369
371
|
*/
|
|
370
372
|
export function normalize(s) {
|
|
371
|
-
return (
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
373
|
+
return (
|
|
374
|
+
(s || '')
|
|
375
|
+
.toLowerCase()
|
|
376
|
+
.normalize('NFD')
|
|
377
|
+
// biome-ignore lint/suspicious/noMisleadingCharacterClass: <explanation>
|
|
378
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
379
|
+
)
|
|
375
380
|
}
|
|
376
381
|
|
|
377
382
|
// Vendorized from leaflet.utils
|
|
@@ -481,6 +486,27 @@ export const debounce = (callback, wait) => {
|
|
|
481
486
|
}
|
|
482
487
|
}
|
|
483
488
|
|
|
489
|
+
export function setObjectValue(obj, key, value) {
|
|
490
|
+
const parts = key.split('.')
|
|
491
|
+
const lastKey = parts.pop()
|
|
492
|
+
|
|
493
|
+
// Reduce the current list of attributes,
|
|
494
|
+
// to find the object to set the property onto
|
|
495
|
+
const objectToSet = parts.reduce((currentObj, part) => {
|
|
496
|
+
if (currentObj !== undefined && part in currentObj) return currentObj[part]
|
|
497
|
+
}, obj)
|
|
498
|
+
|
|
499
|
+
// In case the given path doesn't exist, stop here
|
|
500
|
+
if (objectToSet === undefined) return
|
|
501
|
+
|
|
502
|
+
// Set the value (or delete it)
|
|
503
|
+
if (typeof value === 'undefined') {
|
|
504
|
+
delete objectToSet[lastKey]
|
|
505
|
+
} else {
|
|
506
|
+
objectToSet[lastKey] = value
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
484
510
|
export const COLORS = [
|
|
485
511
|
'Black',
|
|
486
512
|
'Navy',
|