umap-project 3.3.2__py3-none-any.whl → 3.4.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.
- umap/__init__.py +1 -1
- umap/context_processors.py +4 -1
- umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
- umap/locale/cs_CZ/LC_MESSAGES/django.po +43 -33
- umap/locale/da/LC_MESSAGES/django.mo +0 -0
- umap/locale/da/LC_MESSAGES/django.po +43 -33
- umap/locale/de/LC_MESSAGES/django.mo +0 -0
- umap/locale/de/LC_MESSAGES/django.po +64 -53
- umap/locale/el/LC_MESSAGES/django.mo +0 -0
- umap/locale/el/LC_MESSAGES/django.po +35 -29
- umap/locale/en/LC_MESSAGES/django.po +47 -41
- umap/locale/es/LC_MESSAGES/django.mo +0 -0
- umap/locale/es/LC_MESSAGES/django.po +43 -33
- umap/locale/et/LC_MESSAGES/django.mo +0 -0
- umap/locale/et/LC_MESSAGES/django.po +58 -54
- umap/locale/eu/LC_MESSAGES/django.mo +0 -0
- umap/locale/eu/LC_MESSAGES/django.po +43 -33
- umap/locale/fa_IR/LC_MESSAGES/django.mo +0 -0
- umap/locale/fa_IR/LC_MESSAGES/django.po +43 -33
- umap/locale/fr/LC_MESSAGES/django.mo +0 -0
- umap/locale/fr/LC_MESSAGES/django.po +36 -30
- umap/locale/gl/LC_MESSAGES/django.mo +0 -0
- umap/locale/gl/LC_MESSAGES/django.po +43 -33
- umap/locale/hu/LC_MESSAGES/django.mo +0 -0
- umap/locale/hu/LC_MESSAGES/django.po +35 -29
- umap/locale/is/LC_MESSAGES/django.mo +0 -0
- umap/locale/is/LC_MESSAGES/django.po +43 -33
- umap/locale/it/LC_MESSAGES/django.mo +0 -0
- umap/locale/it/LC_MESSAGES/django.po +43 -33
- umap/locale/nl/LC_MESSAGES/django.mo +0 -0
- umap/locale/nl/LC_MESSAGES/django.po +35 -29
- umap/locale/pl/LC_MESSAGES/django.mo +0 -0
- umap/locale/pl/LC_MESSAGES/django.po +114 -103
- umap/locale/pt/LC_MESSAGES/django.mo +0 -0
- umap/locale/pt/LC_MESSAGES/django.po +43 -33
- umap/locale/th_TH/LC_MESSAGES/django.mo +0 -0
- umap/locale/th_TH/LC_MESSAGES/django.po +310 -109
- umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
- umap/locale/zh_TW/LC_MESSAGES/django.po +80 -70
- umap/management/commands/switch_user.py +2 -2
- umap/migrations/0018_datalayer_uuid.py +1 -1
- umap/models.py +7 -3
- umap/settings/local.py.sample +1 -1
- umap/static/umap/base.css +89 -32
- umap/static/umap/content.css +129 -33
- umap/static/umap/css/bar.css +82 -20
- umap/static/umap/css/browser.css +163 -0
- umap/static/umap/css/contextmenu.css +15 -0
- umap/static/umap/css/dialog.css +36 -16
- umap/static/umap/css/form.css +123 -33
- umap/static/umap/css/icon.css +46 -3
- umap/static/umap/css/panel.css +7 -3
- umap/static/umap/css/popup.css +34 -8
- umap/static/umap/css/tooltip.css +8 -4
- umap/static/umap/img/16-white.svg +26 -8
- umap/static/umap/img/16.svg +1 -1
- umap/static/umap/img/source/16-white.svg +36 -18
- umap/static/umap/img/source/16.svg +1 -1
- umap/static/umap/js/components/alerts/alert.css +69 -31
- umap/static/umap/js/components/alerts/alert.js +20 -2
- umap/static/umap/js/components/base.js +1 -1
- umap/static/umap/js/modules/browser.js +69 -61
- umap/static/umap/js/modules/caption.js +10 -7
- umap/static/umap/js/modules/data/features.js +89 -63
- umap/static/umap/js/modules/data/fields.js +446 -0
- umap/static/umap/js/modules/data/layer.js +116 -196
- umap/static/umap/js/modules/domutils.js +109 -0
- umap/static/umap/js/modules/filters.js +780 -0
- umap/static/umap/js/modules/form/builder.js +8 -5
- umap/static/umap/js/modules/form/fields.js +111 -221
- umap/static/umap/js/modules/formatter.js +24 -1
- umap/static/umap/js/modules/help.js +4 -3
- umap/static/umap/js/modules/i18n.js +1 -1
- umap/static/umap/js/modules/importer.js +1 -1
- umap/static/umap/js/modules/importers/opendata.js +15 -0
- umap/static/umap/js/modules/importers/openrouteservice.js +6 -1
- umap/static/umap/js/modules/managers.js +2 -1
- umap/static/umap/js/modules/permissions.js +39 -31
- umap/static/umap/js/modules/rendering/controls.js +11 -9
- umap/static/umap/js/modules/rendering/icon.js +3 -8
- umap/static/umap/js/modules/rendering/layers/base.js +3 -3
- umap/static/umap/js/modules/rendering/layers/classified.js +18 -11
- umap/static/umap/js/modules/rendering/layers/cluster.js +23 -11
- umap/static/umap/js/modules/rendering/layers/heat.js +27 -21
- umap/static/umap/js/modules/rendering/map.js +1 -0
- umap/static/umap/js/modules/rendering/template.js +50 -23
- umap/static/umap/js/modules/rendering/ui.js +33 -25
- umap/static/umap/js/modules/rules.js +38 -44
- umap/static/umap/js/modules/schema.js +3 -6
- umap/static/umap/js/modules/share.js +5 -4
- umap/static/umap/js/modules/tableeditor.js +50 -38
- umap/static/umap/js/modules/templates.js +2 -3
- umap/static/umap/js/modules/ui/bar.js +55 -23
- umap/static/umap/js/modules/ui/dialog.js +38 -27
- umap/static/umap/js/modules/ui/panel.js +23 -8
- umap/static/umap/js/modules/ui/tooltip.js +6 -5
- umap/static/umap/js/modules/umap.js +158 -51
- umap/static/umap/js/modules/utils.js +24 -2
- umap/static/umap/js/umap.core.js +1 -110
- umap/static/umap/locale/am_ET.js +52 -17
- umap/static/umap/locale/am_ET.json +52 -17
- umap/static/umap/locale/ar.js +52 -17
- umap/static/umap/locale/ar.json +52 -17
- umap/static/umap/locale/ast.js +52 -17
- umap/static/umap/locale/ast.json +52 -17
- umap/static/umap/locale/bg.js +52 -17
- umap/static/umap/locale/bg.json +52 -17
- umap/static/umap/locale/br.js +48 -22
- umap/static/umap/locale/br.json +48 -22
- umap/static/umap/locale/ca.js +52 -17
- umap/static/umap/locale/ca.json +52 -17
- umap/static/umap/locale/cs_CZ.js +52 -17
- umap/static/umap/locale/cs_CZ.json +52 -17
- umap/static/umap/locale/da.js +54 -17
- umap/static/umap/locale/da.json +54 -17
- umap/static/umap/locale/de.js +102 -67
- umap/static/umap/locale/de.json +102 -67
- umap/static/umap/locale/el.js +52 -17
- umap/static/umap/locale/el.json +52 -17
- umap/static/umap/locale/en.js +54 -16
- umap/static/umap/locale/en.json +54 -16
- umap/static/umap/locale/en_US.json +52 -17
- umap/static/umap/locale/es.js +54 -17
- umap/static/umap/locale/es.json +54 -17
- umap/static/umap/locale/et.js +91 -56
- umap/static/umap/locale/et.json +91 -56
- umap/static/umap/locale/eu.js +84 -49
- umap/static/umap/locale/eu.json +84 -49
- umap/static/umap/locale/fa_IR.js +52 -17
- umap/static/umap/locale/fa_IR.json +52 -17
- umap/static/umap/locale/fi.js +52 -17
- umap/static/umap/locale/fi.json +52 -17
- umap/static/umap/locale/fr.js +54 -17
- umap/static/umap/locale/fr.json +54 -17
- umap/static/umap/locale/gl.js +52 -17
- umap/static/umap/locale/gl.json +52 -17
- umap/static/umap/locale/he.js +52 -17
- umap/static/umap/locale/he.json +52 -17
- umap/static/umap/locale/hr.js +52 -17
- umap/static/umap/locale/hr.json +52 -17
- umap/static/umap/locale/hu.js +59 -24
- umap/static/umap/locale/hu.json +59 -24
- umap/static/umap/locale/id.js +52 -17
- umap/static/umap/locale/id.json +52 -17
- umap/static/umap/locale/is.js +52 -17
- umap/static/umap/locale/is.json +52 -17
- umap/static/umap/locale/it.js +52 -17
- umap/static/umap/locale/it.json +52 -17
- umap/static/umap/locale/ja.js +52 -17
- umap/static/umap/locale/ja.json +52 -17
- umap/static/umap/locale/ko.js +52 -17
- umap/static/umap/locale/ko.json +52 -17
- umap/static/umap/locale/lt.js +52 -17
- umap/static/umap/locale/lt.json +52 -17
- umap/static/umap/locale/ms.js +52 -17
- umap/static/umap/locale/ms.json +52 -17
- umap/static/umap/locale/nl.js +52 -17
- umap/static/umap/locale/nl.json +52 -17
- umap/static/umap/locale/no.js +52 -17
- umap/static/umap/locale/no.json +52 -17
- umap/static/umap/locale/pl.js +53 -17
- umap/static/umap/locale/pl.json +53 -17
- umap/static/umap/locale/pl_PL.json +52 -17
- umap/static/umap/locale/pt.js +52 -17
- umap/static/umap/locale/pt.json +52 -17
- umap/static/umap/locale/pt_BR.js +52 -17
- umap/static/umap/locale/pt_BR.json +52 -17
- umap/static/umap/locale/pt_PT.js +52 -17
- umap/static/umap/locale/pt_PT.json +52 -17
- umap/static/umap/locale/ro.js +52 -17
- umap/static/umap/locale/ro.json +52 -17
- umap/static/umap/locale/ru.js +52 -17
- umap/static/umap/locale/ru.json +52 -17
- umap/static/umap/locale/si.js +1 -1
- umap/static/umap/locale/si.json +1 -1
- umap/static/umap/locale/sk_SK.js +52 -17
- umap/static/umap/locale/sk_SK.json +52 -17
- umap/static/umap/locale/sl.js +52 -17
- umap/static/umap/locale/sl.json +52 -17
- umap/static/umap/locale/sr.js +52 -17
- umap/static/umap/locale/sr.json +52 -17
- umap/static/umap/locale/sv.js +52 -17
- umap/static/umap/locale/sv.json +52 -17
- umap/static/umap/locale/th_TH.js +52 -17
- umap/static/umap/locale/th_TH.json +52 -17
- umap/static/umap/locale/tr.js +52 -17
- umap/static/umap/locale/tr.json +52 -17
- umap/static/umap/locale/uk_UA.js +52 -17
- umap/static/umap/locale/uk_UA.json +52 -17
- umap/static/umap/locale/vi.js +52 -17
- umap/static/umap/locale/vi.json +52 -17
- umap/static/umap/locale/vi_VN.json +52 -17
- umap/static/umap/locale/zh.js +52 -17
- umap/static/umap/locale/zh.json +52 -17
- umap/static/umap/locale/zh_CN.json +52 -17
- umap/static/umap/locale/zh_TW.Big5.json +52 -17
- umap/static/umap/locale/zh_TW.js +53 -17
- umap/static/umap/locale/zh_TW.json +53 -17
- umap/static/umap/map.css +63 -226
- umap/static/umap/unittests/utils.js +18 -0
- umap/static/umap/vars.css +23 -5
- umap/templates/umap/components/alerts/alert.html +32 -29
- umap/templates/umap/css.html +2 -1
- umap/templates/umap/login_popup_end.html +18 -9
- umap/templates/umap/user_map_table.html +7 -2
- umap/tests/integration/conftest.py +10 -6
- umap/tests/integration/test_anonymous_owned_map.py +90 -37
- umap/tests/integration/test_basics.py +25 -1
- umap/tests/integration/test_browser.py +37 -0
- umap/tests/integration/test_cluster.py +110 -0
- umap/tests/integration/test_conditional_rules.py +107 -52
- umap/tests/integration/test_datalayer.py +9 -16
- umap/tests/integration/test_draw_polygon.py +6 -0
- umap/tests/integration/test_draw_polyline.py +11 -0
- umap/tests/integration/test_edit_marker.py +12 -1
- umap/tests/integration/test_export_map.py +19 -0
- umap/tests/integration/test_fields.py +541 -0
- umap/tests/integration/test_filters.py +616 -0
- umap/tests/integration/test_iframe.py +1 -1
- umap/tests/integration/test_import.py +38 -42
- umap/tests/integration/test_map_preview.py +1 -1
- umap/tests/integration/test_picto.py +1 -1
- umap/tests/integration/test_popup.py +31 -0
- umap/tests/integration/test_remote_data.py +60 -4
- umap/tests/integration/test_save.py +1 -1
- umap/tests/integration/test_share.py +4 -4
- umap/tests/integration/test_tableeditor.py +31 -7
- umap/tests/integration/test_websocket_sync.py +71 -20
- umap/tests/test_dashboard.py +11 -1
- umap/tests/test_statics.py +2 -2
- umap/tests/test_utils.py +19 -2
- umap/tests/test_views.py +1 -1
- umap/urls.py +1 -0
- umap/utils.py +8 -1
- umap/views.py +5 -0
- {umap_project-3.3.2.dist-info → umap_project-3.4.0.dist-info}/METADATA +15 -15
- {umap_project-3.3.2.dist-info → umap_project-3.4.0.dist-info}/RECORD +240 -236
- umap/static/umap/js/modules/facets.js +0 -164
- umap/tests/integration/test_facets_browser.py +0 -279
- {umap_project-3.3.2.dist-info → umap_project-3.4.0.dist-info}/WHEEL +0 -0
- {umap_project-3.3.2.dist-info → umap_project-3.4.0.dist-info}/entry_points.txt +0 -0
- {umap_project-3.3.2.dist-info → umap_project-3.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -7,7 +7,7 @@ export class DataLayerManager extends Object {
|
|
|
7
7
|
active() {
|
|
8
8
|
return Object.values(this)
|
|
9
9
|
.filter((datalayer) => !datalayer.isDeleted)
|
|
10
|
-
.sort((a, b) => a.rank
|
|
10
|
+
.sort((a, b) => a.rank - b.rank)
|
|
11
11
|
}
|
|
12
12
|
reverse() {
|
|
13
13
|
return this.active().reverse()
|
|
@@ -59,6 +59,7 @@ export class FeatureManager extends Map {
|
|
|
59
59
|
if (this.has(feature.id)) {
|
|
60
60
|
console.error('Duplicate id', feature, this.get(feature.id))
|
|
61
61
|
feature.id = Utils.generateId()
|
|
62
|
+
feature.datalayer._migrated = true
|
|
62
63
|
}
|
|
63
64
|
this.set(feature.id, feature)
|
|
64
65
|
}
|
|
@@ -3,6 +3,7 @@ import { uMapAlert as Alert } from '../components/alerts/alert.js'
|
|
|
3
3
|
import { MutatingForm } from './form/builder.js'
|
|
4
4
|
import { translate } from './i18n.js'
|
|
5
5
|
import * as Utils from './utils.js'
|
|
6
|
+
import * as DOMUtils from './domutils.js'
|
|
6
7
|
|
|
7
8
|
// Dedicated object so we can deal with a separate dirty status, and thus
|
|
8
9
|
// call the endpoint only when needed, saving one call at each save.
|
|
@@ -42,12 +43,42 @@ export class MapPermissions {
|
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
isAnonymousMap() {
|
|
45
|
-
return !this.
|
|
46
|
+
return !this.properties.owner
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
isDraft() {
|
|
50
|
+
return this.properties.share_status === 0
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
userIsAuth() {
|
|
54
|
+
return Boolean(this._umap.properties.user?.id)
|
|
46
55
|
}
|
|
47
56
|
|
|
48
57
|
_editAnonymous(container) {
|
|
49
|
-
const fields = []
|
|
50
58
|
if (this.isOwner()) {
|
|
59
|
+
// 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.
|
|
60
|
+
// Note: real check is made on the back office anyway.
|
|
61
|
+
const template = `
|
|
62
|
+
<div class="anonymous soft-round aplat">
|
|
63
|
+
<h4><i class="icon icon-16 icon-anonymous"></i> ${translate('Anonymous map')}</h4>
|
|
64
|
+
<div data-ref="copiableInput"></div>
|
|
65
|
+
<p data-ref="p" hidden><button type="button" data-ref="button">${translate('Attach the map to my account')}</button></p>
|
|
66
|
+
</div>
|
|
67
|
+
`
|
|
68
|
+
const [root, { button, copiableInput, p }] = Utils.loadTemplateWithRefs(template)
|
|
69
|
+
container.appendChild(root)
|
|
70
|
+
if (this.properties.anonymous_edit_url) {
|
|
71
|
+
DOMUtils.copiableInput(
|
|
72
|
+
copiableInput,
|
|
73
|
+
translate('Secret edit link:'),
|
|
74
|
+
this.properties.anonymous_edit_url
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
if (this.userIsAuth()) {
|
|
78
|
+
button.addEventListener('click', () => this.attach())
|
|
79
|
+
p.hidden = false
|
|
80
|
+
}
|
|
81
|
+
const fields = []
|
|
51
82
|
fields.push([
|
|
52
83
|
'properties.edit_status',
|
|
53
84
|
{
|
|
@@ -67,31 +98,6 @@ export class MapPermissions {
|
|
|
67
98
|
const builder = new MutatingForm(this, fields)
|
|
68
99
|
const form = builder.build()
|
|
69
100
|
container.appendChild(form)
|
|
70
|
-
|
|
71
|
-
if (this.properties.anonymous_edit_url) {
|
|
72
|
-
DomUtil.createCopiableInput(
|
|
73
|
-
container,
|
|
74
|
-
translate('Secret edit link:'),
|
|
75
|
-
this.properties.anonymous_edit_url
|
|
76
|
-
)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (this._umap.properties.user?.id) {
|
|
80
|
-
// 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.
|
|
81
|
-
// Note: real check is made on the back office anyway.
|
|
82
|
-
const advancedActions = DomUtil.createFieldset(
|
|
83
|
-
container,
|
|
84
|
-
translate('Advanced actions')
|
|
85
|
-
)
|
|
86
|
-
const advancedButtons = DomUtil.create('div', 'button-bar', advancedActions)
|
|
87
|
-
DomUtil.createButton(
|
|
88
|
-
'button',
|
|
89
|
-
advancedButtons,
|
|
90
|
-
translate('Attach the map to my account'),
|
|
91
|
-
this.attach,
|
|
92
|
-
this
|
|
93
|
-
)
|
|
94
|
-
}
|
|
95
101
|
}
|
|
96
102
|
}
|
|
97
103
|
|
|
@@ -187,6 +193,8 @@ export class MapPermissions {
|
|
|
187
193
|
const [data, response, error] = await this._umap.server.post(this.getAttachUrl())
|
|
188
194
|
if (!error) {
|
|
189
195
|
this.properties.owner = this._umap.properties.user
|
|
196
|
+
this._umap.properties.user.is_owner = true
|
|
197
|
+
this.render()
|
|
190
198
|
Alert.success(translate('Map has been attached to your account'))
|
|
191
199
|
this._umap.editPanel.close()
|
|
192
200
|
}
|
|
@@ -238,6 +246,10 @@ export class MapPermissions {
|
|
|
238
246
|
)
|
|
239
247
|
}
|
|
240
248
|
|
|
249
|
+
pull() {
|
|
250
|
+
this.setProperties(this._umap.properties.permissions)
|
|
251
|
+
}
|
|
252
|
+
|
|
241
253
|
getShareStatusDisplay() {
|
|
242
254
|
if (this._umap.properties.share_statuses) {
|
|
243
255
|
return Object.fromEntries(this._umap.properties.share_statuses)[
|
|
@@ -245,10 +257,6 @@ export class MapPermissions {
|
|
|
245
257
|
]
|
|
246
258
|
}
|
|
247
259
|
}
|
|
248
|
-
|
|
249
|
-
isDraft() {
|
|
250
|
-
return this.properties.share_status === 0
|
|
251
|
-
}
|
|
252
260
|
}
|
|
253
261
|
|
|
254
262
|
export class DataLayerPermissions {
|
|
@@ -112,7 +112,9 @@ export const PermanentCreditsControl = Control.extend({
|
|
|
112
112
|
const container = Utils.loadTemplate(
|
|
113
113
|
`<div class="umap-permanent-credits-container text">${Utils.toHTML(map.options.permanentCredit)}</div>`
|
|
114
114
|
)
|
|
115
|
-
const background = map.
|
|
115
|
+
const background = map._umap.getProperty('permanentCreditBackground')
|
|
116
|
+
? '#FFFFFFB0'
|
|
117
|
+
: ''
|
|
116
118
|
container.style.backgroundColor = background
|
|
117
119
|
return container
|
|
118
120
|
},
|
|
@@ -164,7 +166,7 @@ export const DataLayersControl = BaseButton.extend({
|
|
|
164
166
|
},
|
|
165
167
|
|
|
166
168
|
afterAdd: function (container) {
|
|
167
|
-
Utils.toggleBadge(container, this._umap.browser?.
|
|
169
|
+
Utils.toggleBadge(container, this._umap.browser?.hasActiveFilters())
|
|
168
170
|
},
|
|
169
171
|
|
|
170
172
|
onClick: function () {
|
|
@@ -177,7 +179,7 @@ export const CaptionControl = BaseButton.extend({
|
|
|
177
179
|
position: 'topleft',
|
|
178
180
|
className: 'umap-control-caption',
|
|
179
181
|
title: translate('About'),
|
|
180
|
-
icon: 'icon-
|
|
182
|
+
icon: 'icon-info',
|
|
181
183
|
},
|
|
182
184
|
|
|
183
185
|
onClick: function () {
|
|
@@ -242,13 +244,13 @@ export const SearchControl = BaseButton.extend({
|
|
|
242
244
|
const [container, { input, resultsContainer }] =
|
|
243
245
|
Utils.loadTemplateWithRefs(template)
|
|
244
246
|
const id = Math.random()
|
|
247
|
+
this.search = new U.Search(
|
|
248
|
+
this._umap._leafletMap,
|
|
249
|
+
input,
|
|
250
|
+
this.layer,
|
|
251
|
+
this.photonOptions
|
|
252
|
+
)
|
|
245
253
|
this._umap.panel.open({ content: container }).then(() => {
|
|
246
|
-
this.search = new U.Search(
|
|
247
|
-
this._umap._leafletMap,
|
|
248
|
-
input,
|
|
249
|
-
this.layer,
|
|
250
|
-
this.photonOptions
|
|
251
|
-
)
|
|
252
254
|
this.search.on('ajax:send', () => {
|
|
253
255
|
this._umap.fire('dataloading', { id: id })
|
|
254
256
|
})
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DivIcon,
|
|
3
|
-
DomEvent,
|
|
4
|
-
DomUtil,
|
|
5
|
-
Icon,
|
|
6
|
-
Point,
|
|
7
|
-
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
|
1
|
+
import { DivIcon, Icon, Point } from '../../../vendors/leaflet/leaflet-src.esm.js'
|
|
8
2
|
import { SCHEMA } from '../schema.js'
|
|
9
3
|
import * as Utils from '../utils.js'
|
|
4
|
+
import * as DOMUtils from '../domutils.js'
|
|
10
5
|
|
|
11
6
|
export function getClass(name) {
|
|
12
7
|
switch (name) {
|
|
@@ -299,7 +294,7 @@ export function setContrast(icon, parent, src, bgcolor) {
|
|
|
299
294
|
*/
|
|
300
295
|
if (!icon) return
|
|
301
296
|
|
|
302
|
-
if (
|
|
297
|
+
if (DOMUtils.contrastedColor(parent, bgcolor)) {
|
|
303
298
|
// Decide whether to switch svg to white or not, but do it
|
|
304
299
|
// only for internal SVG, as invert could do weird things
|
|
305
300
|
if (src.endsWith('.svg') && src !== SCHEMA.iconUrl.default) {
|
|
@@ -6,7 +6,7 @@ export const LayerMixin = {
|
|
|
6
6
|
browsable: true,
|
|
7
7
|
|
|
8
8
|
onInit: function (leafletMap) {
|
|
9
|
-
|
|
9
|
+
leafletMap.on('zoomend', this.onZoomEnd, this)
|
|
10
10
|
},
|
|
11
11
|
|
|
12
12
|
onDelete: function (leafletMap) {
|
|
@@ -48,12 +48,12 @@ export const LayerMixin = {
|
|
|
48
48
|
|
|
49
49
|
onMoveEnd: function () {
|
|
50
50
|
if (this.datalayer.hasDynamicData() && this.datalayer.showAtZoom()) {
|
|
51
|
-
this.datalayer.
|
|
51
|
+
this.datalayer.fetchData()
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
|
|
55
55
|
onZoomEnd() {
|
|
56
|
-
if (this.datalayer.
|
|
56
|
+
if (!this.datalayer.autoVisibility) return
|
|
57
57
|
if (!this.datalayer.showAtZoom() && this.datalayer.isVisible()) {
|
|
58
58
|
this.datalayer.hide()
|
|
59
59
|
}
|
|
@@ -2,11 +2,12 @@ import colorbrewer from '../../../../vendors/colorbrewer/colorbrewer.js'
|
|
|
2
2
|
import { DomUtil, FeatureGroup } from '../../../../vendors/leaflet/leaflet-src.esm.js'
|
|
3
3
|
import { translate } from '../../i18n.js'
|
|
4
4
|
import * as Utils from '../../utils.js'
|
|
5
|
+
import * as DOMUtils from '../../domutils.js'
|
|
5
6
|
import { CircleMarker } from '../ui.js'
|
|
6
7
|
import { LayerMixin } from './base.js'
|
|
7
8
|
|
|
8
9
|
// Layer where each feature color is relative to the others,
|
|
9
|
-
// so we need all features before
|
|
10
|
+
// so we need all features before being able to set one
|
|
10
11
|
// feature layer
|
|
11
12
|
const ClassifiedMixin = {
|
|
12
13
|
initialize: function (datalayer) {
|
|
@@ -76,15 +77,21 @@ const ClassifiedMixin = {
|
|
|
76
77
|
|
|
77
78
|
renderLegend: function (container) {
|
|
78
79
|
if (!this.datalayer.isLoaded()) return
|
|
79
|
-
const
|
|
80
|
+
const ul = Utils.loadTemplate('<ul></ul>')
|
|
80
81
|
const items = this.getLegendItems()
|
|
81
82
|
for (const [color, label] of items) {
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
83
|
+
const rgbColor = DOMUtils.hexToRGB(color)
|
|
84
|
+
const opacity = this.datalayer.getOption('fillOpacity')
|
|
85
|
+
const bgColor = `rgba(${rgbColor.join(',')}, ${opacity})`
|
|
86
|
+
const li = Utils.loadTemplate(`
|
|
87
|
+
<li>
|
|
88
|
+
<span class="datalayer-color" style="background-color: ${bgColor};"></span>
|
|
89
|
+
<span>${label}</span>
|
|
90
|
+
</li>
|
|
91
|
+
`)
|
|
92
|
+
ul.appendChild(li)
|
|
87
93
|
}
|
|
94
|
+
container.appendChild(ul)
|
|
88
95
|
},
|
|
89
96
|
|
|
90
97
|
getColorSchemes: function (classes) {
|
|
@@ -198,7 +205,7 @@ export const Choropleth = FeatureGroup.extend({
|
|
|
198
205
|
'properties.choropleth.property',
|
|
199
206
|
{
|
|
200
207
|
handler: 'Select',
|
|
201
|
-
selectOptions: this.datalayer.
|
|
208
|
+
selectOptions: this.datalayer.fields.keys(),
|
|
202
209
|
label: translate('Choropleth property value'),
|
|
203
210
|
},
|
|
204
211
|
],
|
|
@@ -307,7 +314,7 @@ export const Circles = FeatureGroup.extend({
|
|
|
307
314
|
'properties.circles.property',
|
|
308
315
|
{
|
|
309
316
|
handler: 'Select',
|
|
310
|
-
selectOptions: this.datalayer.
|
|
317
|
+
selectOptions: this.datalayer.fields.keys(),
|
|
311
318
|
label: translate('Property name to compute circles'),
|
|
312
319
|
},
|
|
313
320
|
],
|
|
@@ -384,7 +391,7 @@ export const Categorized = FeatureGroup.extend({
|
|
|
384
391
|
|
|
385
392
|
_getValue: function (feature) {
|
|
386
393
|
const key =
|
|
387
|
-
this.datalayer.properties.categorized.property || this.datalayer.
|
|
394
|
+
this.datalayer.properties.categorized.property || this.datalayer.fields.keys()[0]
|
|
388
395
|
return feature.properties[key]
|
|
389
396
|
},
|
|
390
397
|
|
|
@@ -437,7 +444,7 @@ export const Categorized = FeatureGroup.extend({
|
|
|
437
444
|
'properties.categorized.property',
|
|
438
445
|
{
|
|
439
446
|
handler: 'Select',
|
|
440
|
-
selectOptions: this.datalayer.
|
|
447
|
+
selectOptions: this.datalayer.fields.keys(),
|
|
441
448
|
label: translate('Category property'),
|
|
442
449
|
},
|
|
443
450
|
],
|
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
Marker,
|
|
6
6
|
Rectangle,
|
|
7
7
|
Polyline,
|
|
8
|
-
DomUtil,
|
|
9
8
|
latLngBounds,
|
|
10
9
|
} from '../../../../vendors/leaflet/leaflet-src.esm.js'
|
|
11
10
|
import { translate } from '../../i18n.js'
|
|
12
11
|
import * as Utils from '../../utils.js'
|
|
12
|
+
import * as DOMUtils from '../../domutils.js'
|
|
13
13
|
import { Cluster as ClusterIcon } from '../icon.js'
|
|
14
14
|
import { LayerMixin } from './base.js'
|
|
15
15
|
|
|
@@ -21,7 +21,7 @@ const MarkerCluster = Marker.extend({
|
|
|
21
21
|
const bgColor = this.options.icon.options.color
|
|
22
22
|
const textColor = this.options.icon.options.textColor
|
|
23
23
|
counter.style.color =
|
|
24
|
-
textColor ||
|
|
24
|
+
textColor || DOMUtils.textColorFromBackgroundColor(counter, bgColor)
|
|
25
25
|
},
|
|
26
26
|
|
|
27
27
|
computeCoverage() {
|
|
@@ -186,22 +186,24 @@ export const Cluster = FeatureGroup.extend({
|
|
|
186
186
|
return this
|
|
187
187
|
},
|
|
188
188
|
|
|
189
|
+
removeLayer: function (layer) {
|
|
190
|
+
if (!layer.getLatLng) return FeatureGroup.prototype.removeLayer.call(this, layer)
|
|
191
|
+
this._bucket = this._bucket.filter((el) => el !== layer)
|
|
192
|
+
return this
|
|
193
|
+
},
|
|
194
|
+
|
|
189
195
|
onAdd: function (leafletMap) {
|
|
190
196
|
this.on('click', this.onClick)
|
|
191
197
|
this.on('mouseover', this.onMouseOver)
|
|
192
198
|
this.on('mouseout', this.onMouseOut)
|
|
193
199
|
this.compute()
|
|
194
200
|
LayerMixin.onAdd.call(this, leafletMap)
|
|
195
|
-
leafletMap.on('moveend', this.onMoveEnd, this)
|
|
196
|
-
leafletMap.on('zoomend', this.onZoomEnd, this)
|
|
197
201
|
this.addClusters()
|
|
198
202
|
leafletMap.addLayer(this._group)
|
|
199
203
|
return FeatureGroup.prototype.onAdd.call(this, leafletMap)
|
|
200
204
|
},
|
|
201
205
|
|
|
202
206
|
onRemove: function (leafletMap) {
|
|
203
|
-
leafletMap.off('zoomend', this.onZoomEnd, this)
|
|
204
|
-
leafletMap.off('moveend', this.onMoveEnd, this)
|
|
205
207
|
this.off('click', this.onClick)
|
|
206
208
|
this.off('mouseover', this.onMouseOver)
|
|
207
209
|
this.off('mouseout', this.onMouseOut)
|
|
@@ -212,12 +214,18 @@ export const Cluster = FeatureGroup.extend({
|
|
|
212
214
|
},
|
|
213
215
|
|
|
214
216
|
onZoomEnd: function () {
|
|
217
|
+
LayerMixin.onZoomEnd.call(this)
|
|
215
218
|
this.removeClusters()
|
|
216
219
|
},
|
|
217
220
|
|
|
218
221
|
onMoveEnd: function () {
|
|
219
|
-
|
|
220
|
-
|
|
222
|
+
LayerMixin.onMoveEnd.call(this)
|
|
223
|
+
// In case of dynamic data, the LayerMixin.onMoveEnd
|
|
224
|
+
// call with fetch the data and then call the compute
|
|
225
|
+
if (!this.datalayer.hasDynamicData()) {
|
|
226
|
+
this.compute()
|
|
227
|
+
this.addClusters()
|
|
228
|
+
}
|
|
221
229
|
},
|
|
222
230
|
|
|
223
231
|
showCoverage(cluster) {
|
|
@@ -228,7 +236,9 @@ export const Cluster = FeatureGroup.extend({
|
|
|
228
236
|
},
|
|
229
237
|
|
|
230
238
|
hideCoverage() {
|
|
231
|
-
if (this._shownCoverage
|
|
239
|
+
if (this._shownCoverage && this._map) {
|
|
240
|
+
this._map.removeLayer(this._shownCoverage)
|
|
241
|
+
}
|
|
232
242
|
},
|
|
233
243
|
|
|
234
244
|
onMouseOver(event) {
|
|
@@ -253,7 +263,7 @@ export const Cluster = FeatureGroup.extend({
|
|
|
253
263
|
'properties.cluster.radius',
|
|
254
264
|
{
|
|
255
265
|
handler: 'Range',
|
|
256
|
-
min:
|
|
266
|
+
min: 10,
|
|
257
267
|
max: 200,
|
|
258
268
|
step: 10,
|
|
259
269
|
placeholder: translate('Clustering radius'),
|
|
@@ -271,6 +281,8 @@ export const Cluster = FeatureGroup.extend({
|
|
|
271
281
|
],
|
|
272
282
|
|
|
273
283
|
onEdit: function (field, builder) {
|
|
274
|
-
if (field === 'properties.cluster.radius'
|
|
284
|
+
if (field === 'properties.cluster.radius' || field === 'properties.color') {
|
|
285
|
+
this.redraw()
|
|
286
|
+
}
|
|
275
287
|
},
|
|
276
288
|
})
|
|
@@ -68,27 +68,32 @@ export const Heat = L.HeatLayer.extend({
|
|
|
68
68
|
return latLngBounds(this._latlngs)
|
|
69
69
|
},
|
|
70
70
|
|
|
71
|
-
getEditableProperties: ()
|
|
72
|
-
[
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
71
|
+
getEditableProperties: function () {
|
|
72
|
+
return [
|
|
73
|
+
[
|
|
74
|
+
'properties.heat.radius',
|
|
75
|
+
{
|
|
76
|
+
handler: 'Range',
|
|
77
|
+
min: 10,
|
|
78
|
+
max: 100,
|
|
79
|
+
step: 5,
|
|
80
|
+
label: translate('Heatmap radius'),
|
|
81
|
+
helpText: translate('Override heatmap radius (default 25)'),
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
[
|
|
85
|
+
'properties.heat.intensityProperty',
|
|
86
|
+
{
|
|
87
|
+
handler: 'Select',
|
|
88
|
+
selectOptions: [
|
|
89
|
+
['', translate('Select field to compute intensity')],
|
|
90
|
+
...this.datalayer.fields.keys(),
|
|
91
|
+
],
|
|
92
|
+
helpText: translate('Optional intensity field to compute heatmap'),
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
]
|
|
96
|
+
},
|
|
92
97
|
|
|
93
98
|
onEdit: function (field, builder) {
|
|
94
99
|
if (field === 'properties.heat.intensityProperty') {
|
|
@@ -97,6 +102,7 @@ export const Heat = L.HeatLayer.extend({
|
|
|
97
102
|
}
|
|
98
103
|
if (field === 'properties.heat.radius') {
|
|
99
104
|
this.options.radius = this.datalayer.properties.heat.radius
|
|
105
|
+
this.redraw()
|
|
100
106
|
}
|
|
101
107
|
this._updateOptions()
|
|
102
108
|
},
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
import { getLocale, translate } from '../i18n.js'
|
|
7
7
|
import { Request } from '../request.js'
|
|
8
8
|
import * as Utils from '../utils.js'
|
|
9
|
+
import * as DOMUtils from '../domutils.js'
|
|
9
10
|
import * as Icon from './icon.js'
|
|
10
11
|
|
|
11
12
|
export default async function loadTemplate(name, feature, container) {
|
|
@@ -107,29 +108,20 @@ export const TitleMixin = (Base) =>
|
|
|
107
108
|
}
|
|
108
109
|
|
|
109
110
|
class Table extends TitleMixin(PopupTemplate) {
|
|
110
|
-
|
|
111
|
-
// TODO, manage links (url, mailto, wikipedia...)
|
|
112
|
-
const value = Utils.escapeHTML(feature.properties[key]).trim()
|
|
113
|
-
if (value.indexOf('http') === 0) {
|
|
114
|
-
return `<a href="${value}" target="_blank">${value}</a>`
|
|
115
|
-
}
|
|
116
|
-
return value
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
makeRow(feature, key) {
|
|
111
|
+
makeRow(feature, field) {
|
|
120
112
|
return Utils.loadTemplate(
|
|
121
|
-
`<tr><th>${key}</th><td>${
|
|
113
|
+
`<tr><th>${field.key}</th><td>${field.render(feature.properties[field.key])}</td></tr>`
|
|
122
114
|
)
|
|
123
115
|
}
|
|
124
116
|
|
|
125
117
|
async renderBody(feature) {
|
|
126
118
|
const table = document.createElement('table')
|
|
127
119
|
|
|
128
|
-
for (const
|
|
129
|
-
if (
|
|
120
|
+
for (const field of feature.fields) {
|
|
121
|
+
if (U.LABEL_KEYS.includes(field.key)) {
|
|
130
122
|
continue
|
|
131
123
|
}
|
|
132
|
-
table.appendChild(this.makeRow(feature,
|
|
124
|
+
table.appendChild(this.makeRow(feature, field))
|
|
133
125
|
}
|
|
134
126
|
return table
|
|
135
127
|
}
|
|
@@ -171,7 +163,7 @@ class OSM extends PopupTemplate {
|
|
|
171
163
|
const icon = Icon.makeElement(iconUrl, title)
|
|
172
164
|
DomUtil.addClass(icon, 'icon')
|
|
173
165
|
Icon.setContrast(icon, title, iconUrl, color)
|
|
174
|
-
if (
|
|
166
|
+
if (DOMUtils.contrastedColor(title, color)) title.style.color = 'white'
|
|
175
167
|
DomUtil.add('span', '', title, this.getName(feature))
|
|
176
168
|
return title
|
|
177
169
|
}
|
|
@@ -180,7 +172,7 @@ class OSM extends PopupTemplate {
|
|
|
180
172
|
const props = feature.properties
|
|
181
173
|
const locale = getLocale()
|
|
182
174
|
if (locale && props[`name:${locale}`]) return props[`name:${locale}`]
|
|
183
|
-
return props.name
|
|
175
|
+
return props.name || feature.getDisplayName()
|
|
184
176
|
}
|
|
185
177
|
|
|
186
178
|
async renderBody(feature) {
|
|
@@ -192,7 +184,7 @@ class OSM extends PopupTemplate {
|
|
|
192
184
|
const row = DomUtil.add('address', 'address', body)
|
|
193
185
|
const number = props['addr:housenumber']
|
|
194
186
|
if (number) {
|
|
195
|
-
// Poor way to deal with international forms of
|
|
187
|
+
// Poor way to deal with international forms of writing addresses
|
|
196
188
|
DomUtil.add('span', '', row, `${translate('No.')}: ${number}`)
|
|
197
189
|
DomUtil.add('span', '', row, `${translate('Street')}: ${street}`)
|
|
198
190
|
} else {
|
|
@@ -230,11 +222,31 @@ class OSM extends PopupTemplate {
|
|
|
230
222
|
)
|
|
231
223
|
)
|
|
232
224
|
}
|
|
225
|
+
if (props.image) {
|
|
226
|
+
body.appendChild(
|
|
227
|
+
Utils.loadTemplate(`<div><img src="${props.image}" alt="" /></div>`)
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
if (props.mapillary) {
|
|
231
|
+
body.appendChild(
|
|
232
|
+
Utils.loadTemplate(
|
|
233
|
+
`<div><a href="https://www.mapillary.com/app/?focus=photo&pKey=${props.mapillary}" target="_blank">${translate('Mapillary')}<i class="icon icon-16 icon-external-link"></i></a></div>`
|
|
234
|
+
)
|
|
235
|
+
)
|
|
236
|
+
}
|
|
233
237
|
const wikipedia = props[`wikipedia:${locale}`] || props.wikipedia
|
|
234
238
|
if (wikipedia) {
|
|
235
239
|
body.appendChild(
|
|
236
240
|
Utils.loadTemplate(
|
|
237
|
-
`<div
|
|
241
|
+
`<div><a href="https://wikipedia.org/wiki/${wikipedia}" target="_blank">${translate('Wikipedia')}<i class="icon icon-16 icon-external-link"></i></a></div>`
|
|
242
|
+
)
|
|
243
|
+
)
|
|
244
|
+
}
|
|
245
|
+
const wikidata = props[`wikidata:${locale}`] || props.wikidata
|
|
246
|
+
if (wikidata) {
|
|
247
|
+
body.appendChild(
|
|
248
|
+
Utils.loadTemplate(
|
|
249
|
+
`<div><a href="https://www.wikidata.org/wiki/${wikidata}" target="_blank">${translate('Wikidata')}<i class="icon icon-16 icon-external-link"></i></a></div>`
|
|
238
250
|
)
|
|
239
251
|
)
|
|
240
252
|
}
|
|
@@ -242,7 +254,7 @@ class OSM extends PopupTemplate {
|
|
|
242
254
|
if (id) {
|
|
243
255
|
body.appendChild(
|
|
244
256
|
Utils.loadTemplate(
|
|
245
|
-
`<div class="osm-link"><a href="https://www.openstreetmap.org/${id}">${translate('See on OpenStreetMap')}
|
|
257
|
+
`<div class="osm-link"><a href="https://www.openstreetmap.org/${id}">${translate('See on OpenStreetMap')}<i class="icon icon-16 icon-external-link"></i></a></div>`
|
|
246
258
|
)
|
|
247
259
|
)
|
|
248
260
|
}
|
|
@@ -257,7 +269,7 @@ class Wikipedia extends PopupTemplate {
|
|
|
257
269
|
if (wikipedia && _WIKIPEDIA_CACHE[wikipedia]) return _WIKIPEDIA_CACHE[wikipedia]
|
|
258
270
|
// Wikipedia value should be in form of "{locale}:{title}", according to https://wiki.openstreetmap.org/wiki/Key:wikipedia
|
|
259
271
|
const [locale, page] = wikipedia.split(':')
|
|
260
|
-
const url = `https://${locale}.wikipedia.org/w/api.php?action=query&format=json&origin=*&pithumbsize=500&prop=extracts|pageimages&titles=${page}`
|
|
272
|
+
const url = `https://${locale}.wikipedia.org/w/api.php?action=query&format=json&origin=*&pithumbsize=500&exintro=1&prop=extracts|pageimages&titles=${page}`
|
|
261
273
|
const request = new Request()
|
|
262
274
|
const response = await request.get(url)
|
|
263
275
|
if (response?.ok) {
|
|
@@ -277,9 +289,21 @@ class Wikipedia extends PopupTemplate {
|
|
|
277
289
|
const title = page.title || feature.getDisplayName()
|
|
278
290
|
const extract = page.extract || ''
|
|
279
291
|
const thumbnail = page.thumbnail?.source
|
|
280
|
-
const [content, { image }] = Utils.loadTemplateWithRefs(
|
|
281
|
-
|
|
282
|
-
|
|
292
|
+
const [content, { image }] = Utils.loadTemplateWithRefs(`
|
|
293
|
+
<div>
|
|
294
|
+
<h3>${Utils.escapeHTML(title)}</h3>
|
|
295
|
+
<img data-ref="image" hidden src="" />
|
|
296
|
+
<p>
|
|
297
|
+
${Utils.escapeHTML(extract)}
|
|
298
|
+
</p>
|
|
299
|
+
<p>
|
|
300
|
+
© ${translate('Wikipedia contributors')} •
|
|
301
|
+
<a href="https://wikipedia.org/wiki/${wikipedia}" target="_blank">
|
|
302
|
+
${translate('See on Wikipedia')}
|
|
303
|
+
<i class="icon icon-16 icon-external-link"></i>
|
|
304
|
+
</a>
|
|
305
|
+
</p>
|
|
306
|
+
</div>`)
|
|
283
307
|
if (thumbnail) {
|
|
284
308
|
image.src = thumbnail
|
|
285
309
|
image.hidden = false
|
|
@@ -349,6 +373,9 @@ class Route extends TitleMixin(PopupTemplate) {
|
|
|
349
373
|
color: 'orange',
|
|
350
374
|
}).addTo(map)
|
|
351
375
|
})
|
|
376
|
+
if (feature.properties.description) {
|
|
377
|
+
root.appendChild(Utils.loadTemplate(`<p>${feature.properties.description}</p>`))
|
|
378
|
+
}
|
|
352
379
|
return root
|
|
353
380
|
}
|
|
354
381
|
}
|