umap-project 3.1.2__py3-none-any.whl → 3.3.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/locale/en/LC_MESSAGES/django.mo +0 -0
- umap/locale/en/LC_MESSAGES/django.po +22 -18
- umap/locale/fr/LC_MESSAGES/django.mo +0 -0
- umap/locale/fr/LC_MESSAGES/django.po +21 -17
- umap/management/commands/export_pictogram.py +29 -0
- umap/management/commands/migrate_to_S3.py +5 -1
- umap/management/commands/purge_old_versions.py +8 -6
- umap/settings/__init__.py +21 -0
- umap/settings/base.py +3 -0
- umap/static/umap/content.css +7 -2
- umap/static/umap/css/contextmenu.css +58 -2
- umap/static/umap/css/form.css +175 -45
- umap/static/umap/css/icon.css +97 -3
- umap/static/umap/css/panel.css +31 -1
- umap/static/umap/img/16-white.svg +21 -40
- umap/static/umap/img/16.svg +1 -1
- umap/static/umap/img/24-white.svg +9 -9
- umap/static/umap/img/24.svg +23 -10
- umap/static/umap/img/source/16-white.svg +23 -41
- umap/static/umap/img/source/16.svg +1 -1
- umap/static/umap/img/source/24-white.svg +11 -11
- umap/static/umap/img/source/24.svg +25 -12
- umap/static/umap/js/modules/browser.js +1 -1
- umap/static/umap/js/modules/caption.js +8 -0
- umap/static/umap/js/modules/data/features.js +331 -202
- umap/static/umap/js/modules/data/layer.js +263 -152
- umap/static/umap/js/modules/facets.js +2 -2
- umap/static/umap/js/modules/form/builder.js +11 -7
- umap/static/umap/js/modules/form/fields.js +66 -26
- umap/static/umap/js/modules/formatter.js +78 -28
- umap/static/umap/js/modules/importer.js +6 -1
- umap/static/umap/js/modules/importers/opendata.js +138 -33
- umap/static/umap/js/modules/importers/openrouteservice.js +140 -0
- umap/static/umap/js/modules/managers.js +67 -0
- umap/static/umap/js/modules/printer.js +107 -0
- umap/static/umap/js/modules/rendering/controls.js +78 -2
- umap/static/umap/js/modules/rendering/icon.js +116 -87
- umap/static/umap/js/modules/rendering/layers/classified.js +8 -7
- umap/static/umap/js/modules/rendering/layers/cluster.js +199 -63
- umap/static/umap/js/modules/rendering/map.js +6 -2
- umap/static/umap/js/modules/rendering/template.js +71 -1
- umap/static/umap/js/modules/rendering/ui.js +111 -34
- umap/static/umap/js/modules/rules.js +76 -23
- umap/static/umap/js/modules/schema.js +27 -0
- umap/static/umap/js/modules/share.js +19 -12
- umap/static/umap/js/modules/slideshow.js +1 -1
- umap/static/umap/js/modules/sync/updaters.js +1 -6
- umap/static/umap/js/modules/tableeditor.js +13 -37
- umap/static/umap/js/modules/templates.js +7 -6
- umap/static/umap/js/modules/ui/bar.js +6 -1
- umap/static/umap/js/modules/ui/base.js +24 -9
- umap/static/umap/js/modules/ui/contextmenu.js +17 -7
- umap/static/umap/js/modules/ui/dialog.js +7 -4
- umap/static/umap/js/modules/ui/panel.js +7 -0
- umap/static/umap/js/modules/umap.js +84 -67
- umap/static/umap/js/modules/utils.js +8 -7
- umap/static/umap/js/umap.controls.js +22 -57
- umap/static/umap/locale/am_ET.js +81 -9
- umap/static/umap/locale/am_ET.json +81 -9
- umap/static/umap/locale/ar.js +81 -9
- umap/static/umap/locale/ar.json +81 -9
- umap/static/umap/locale/ast.js +81 -9
- umap/static/umap/locale/ast.json +81 -9
- umap/static/umap/locale/bg.js +81 -9
- umap/static/umap/locale/bg.json +81 -9
- umap/static/umap/locale/br.js +68 -29
- umap/static/umap/locale/br.json +68 -29
- umap/static/umap/locale/ca.js +88 -16
- umap/static/umap/locale/ca.json +88 -16
- umap/static/umap/locale/cs_CZ.js +81 -9
- umap/static/umap/locale/cs_CZ.json +81 -9
- umap/static/umap/locale/da.js +48 -9
- umap/static/umap/locale/da.json +48 -9
- umap/static/umap/locale/de.js +48 -9
- umap/static/umap/locale/de.json +48 -9
- umap/static/umap/locale/el.js +58 -13
- umap/static/umap/locale/el.json +58 -13
- umap/static/umap/locale/en.js +48 -9
- umap/static/umap/locale/en.json +48 -9
- umap/static/umap/locale/en_US.json +81 -9
- umap/static/umap/locale/es.js +48 -9
- umap/static/umap/locale/es.json +48 -9
- umap/static/umap/locale/et.js +81 -9
- umap/static/umap/locale/et.json +81 -9
- umap/static/umap/locale/eu.js +97 -25
- umap/static/umap/locale/eu.json +97 -25
- umap/static/umap/locale/fa_IR.js +81 -9
- umap/static/umap/locale/fa_IR.json +81 -9
- umap/static/umap/locale/fi.js +81 -9
- umap/static/umap/locale/fi.json +81 -9
- umap/static/umap/locale/fr.js +48 -9
- umap/static/umap/locale/fr.json +48 -9
- umap/static/umap/locale/gl.js +81 -9
- umap/static/umap/locale/gl.json +81 -9
- umap/static/umap/locale/he.js +81 -9
- umap/static/umap/locale/he.json +81 -9
- umap/static/umap/locale/hr.js +81 -9
- umap/static/umap/locale/hr.json +81 -9
- umap/static/umap/locale/hu.js +72 -27
- umap/static/umap/locale/hu.json +72 -27
- umap/static/umap/locale/id.js +81 -9
- umap/static/umap/locale/id.json +81 -9
- umap/static/umap/locale/is.js +81 -9
- umap/static/umap/locale/is.json +81 -9
- umap/static/umap/locale/it.js +48 -9
- umap/static/umap/locale/it.json +48 -9
- umap/static/umap/locale/ja.js +81 -9
- umap/static/umap/locale/ja.json +81 -9
- umap/static/umap/locale/ko.js +81 -9
- umap/static/umap/locale/ko.json +81 -9
- umap/static/umap/locale/lt.js +81 -9
- umap/static/umap/locale/lt.json +81 -9
- umap/static/umap/locale/ms.js +81 -9
- umap/static/umap/locale/ms.json +81 -9
- umap/static/umap/locale/nl.js +48 -9
- umap/static/umap/locale/nl.json +48 -9
- umap/static/umap/locale/no.js +81 -9
- umap/static/umap/locale/no.json +81 -9
- umap/static/umap/locale/pl.js +81 -9
- umap/static/umap/locale/pl.json +81 -9
- umap/static/umap/locale/pl_PL.json +81 -9
- umap/static/umap/locale/pt.js +81 -9
- umap/static/umap/locale/pt.json +81 -9
- umap/static/umap/locale/pt_BR.js +91 -19
- umap/static/umap/locale/pt_BR.json +91 -19
- umap/static/umap/locale/pt_PT.js +81 -9
- umap/static/umap/locale/pt_PT.json +81 -9
- umap/static/umap/locale/ro.js +81 -9
- umap/static/umap/locale/ro.json +81 -9
- umap/static/umap/locale/ru.js +81 -9
- umap/static/umap/locale/ru.json +81 -9
- umap/static/umap/locale/sk_SK.js +81 -9
- umap/static/umap/locale/sk_SK.json +81 -9
- umap/static/umap/locale/sl.js +81 -9
- umap/static/umap/locale/sl.json +81 -9
- umap/static/umap/locale/sr.js +81 -9
- umap/static/umap/locale/sr.json +81 -9
- umap/static/umap/locale/sv.js +81 -9
- umap/static/umap/locale/sv.json +81 -9
- umap/static/umap/locale/th_TH.js +81 -9
- umap/static/umap/locale/th_TH.json +81 -9
- umap/static/umap/locale/tr.js +81 -9
- umap/static/umap/locale/tr.json +81 -9
- umap/static/umap/locale/uk_UA.js +81 -9
- umap/static/umap/locale/uk_UA.json +81 -9
- umap/static/umap/locale/vi.js +81 -9
- umap/static/umap/locale/vi.json +81 -9
- umap/static/umap/locale/vi_VN.json +81 -9
- umap/static/umap/locale/zh.js +81 -9
- umap/static/umap/locale/zh.json +81 -9
- umap/static/umap/locale/zh_CN.json +81 -9
- umap/static/umap/locale/zh_TW.Big5.json +81 -9
- umap/static/umap/locale/zh_TW.js +98 -26
- umap/static/umap/locale/zh_TW.json +98 -26
- umap/static/umap/map.css +325 -102
- umap/static/umap/vars.css +1 -0
- umap/static/umap/vendors/betterknown/betterknown.mjs +287 -0
- umap/static/umap/vendors/editable/Leaflet.Editable.js +3 -1
- umap/static/umap/vendors/openrouteservice/ors-js-client.js +521 -0
- umap/static/umap/vendors/openrouteservice/ors-js-client.js.map +1 -0
- umap/static/umap/vendors/simple-elevation-chart/elevation.js +63 -0
- umap/static/umap/vendors/simple-elevation-chart/elevation.svg +8 -0
- umap/static/umap/vendors/snapdom/snapdom.min.mjs +3 -0
- umap/storage/fs.py +3 -2
- umap/storage/staticfiles.py +12 -0
- umap/templates/base.html +4 -1
- umap/templates/umap/css.html +0 -4
- umap/templates/umap/js.html +1 -3
- umap/tests/base.py +9 -1
- umap/tests/integration/test_basics.py +3 -1
- umap/tests/integration/test_conditional_rules.py +79 -37
- umap/tests/integration/test_datalayer.py +1 -1
- umap/tests/integration/test_draw_polygon.py +3 -5
- umap/tests/integration/test_draw_polyline.py +4 -6
- umap/tests/integration/test_draw_route.py +178 -0
- umap/tests/integration/test_edit_datalayer.py +1 -1
- umap/tests/integration/test_edit_map.py +1 -1
- umap/tests/integration/test_edit_marker.py +8 -8
- umap/tests/integration/test_edit_polygon.py +2 -2
- umap/tests/integration/test_export_map.py +84 -10
- umap/tests/integration/test_import.py +140 -0
- umap/tests/integration/test_map_preview.py +1 -1
- umap/tests/integration/test_optimistic_merge.py +72 -12
- umap/tests/integration/test_share.py +1 -1
- umap/tests/integration/test_tableeditor.py +10 -7
- umap/tests/integration/test_websocket_sync.py +4 -4
- umap/utils.py +37 -0
- umap/views.py +18 -2
- umap_project-3.3.0.dist-info/METADATA +76 -0
- {umap_project-3.1.2.dist-info → umap_project-3.3.0.dist-info}/RECORD +194 -188
- umap/static/umap/vendors/markercluster/MarkerCluster.Default.css +0 -60
- umap/static/umap/vendors/markercluster/MarkerCluster.css +0 -14
- umap/static/umap/vendors/markercluster/leaflet.markercluster.js +0 -2
- umap/static/umap/vendors/markercluster/leaflet.markercluster.js.map +0 -1
- umap_project-3.1.2.dist-info/METADATA +0 -68
- {umap_project-3.1.2.dist-info → umap_project-3.3.0.dist-info}/WHEEL +0 -0
- {umap_project-3.1.2.dist-info → umap_project-3.3.0.dist-info}/entry_points.txt +0 -0
- {umap_project-3.1.2.dist-info → umap_project-3.3.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -81,7 +81,7 @@ export class DataLayerUpdater extends BaseUpdater {
|
|
|
81
81
|
export class FeatureUpdater extends BaseUpdater {
|
|
82
82
|
getFeatureFromMetadata({ id, layerId }) {
|
|
83
83
|
const datalayer = this.getDataLayerFromID(layerId)
|
|
84
|
-
return datalayer.
|
|
84
|
+
return datalayer.features.get(id)
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
// Create or update an object at a specific position
|
|
@@ -109,11 +109,6 @@ export class FeatureUpdater extends BaseUpdater {
|
|
|
109
109
|
feature.geometry = value
|
|
110
110
|
} else {
|
|
111
111
|
Utils.setObjectValue(feature, key, value)
|
|
112
|
-
if (key.startsWith('properties')) {
|
|
113
|
-
feature.datalayer.indexProperties(feature)
|
|
114
|
-
const name = key.replace('properties.', '')
|
|
115
|
-
feature.datalayer.checkIndexForProperty(name)
|
|
116
|
-
}
|
|
117
112
|
}
|
|
118
113
|
|
|
119
114
|
feature.render([key])
|
|
@@ -74,10 +74,10 @@ export default class TableEditor extends WithTemplate {
|
|
|
74
74
|
const th = loadTemplate('<th><input type="checkbox" /></th>')
|
|
75
75
|
const checkbox = th.firstChild
|
|
76
76
|
this.elements.header.appendChild(th)
|
|
77
|
-
for (const
|
|
77
|
+
for (const field of this.datalayer.fields) {
|
|
78
78
|
this.elements.header.appendChild(
|
|
79
79
|
loadTemplate(
|
|
80
|
-
`<th>${
|
|
80
|
+
`<th>${field.key}<button data-property="${field.key}" class="flat" aria-label="${translate('Advanced actions')}">…</button></th>`
|
|
81
81
|
)
|
|
82
82
|
)
|
|
83
83
|
}
|
|
@@ -91,56 +91,32 @@ export default class TableEditor extends WithTemplate {
|
|
|
91
91
|
const bounds = this._leafletMap.getBounds()
|
|
92
92
|
const inBbox = this._umap.browser.options.inBbox
|
|
93
93
|
let html = ''
|
|
94
|
-
this.datalayer.
|
|
94
|
+
this.datalayer.features.forEach((feature) => {
|
|
95
95
|
if (feature.isFiltered()) return
|
|
96
96
|
if (inBbox && !feature.isOnScreen(bounds)) return
|
|
97
|
-
const tds = this.
|
|
98
|
-
(
|
|
99
|
-
`<td tabindex="0" data-property="${
|
|
97
|
+
const tds = this.datalayer.fields.map(
|
|
98
|
+
(field) =>
|
|
99
|
+
`<td tabindex="0" data-property="${field.key}">${feature.properties[field.key] ?? ''}</td>`
|
|
100
100
|
)
|
|
101
101
|
html += `<tr data-feature="${feature.id}"><th><input type="checkbox" /></th>${tds.join('')}</tr>`
|
|
102
102
|
})
|
|
103
103
|
this.elements.body.innerHTML = html
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
resetProperties() {
|
|
107
|
-
this.properties = this.datalayer.allProperties()
|
|
108
|
-
if (this.properties.length === 0) {
|
|
109
|
-
this.properties = [U.DEFAULT_LABEL_KEY, 'description']
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
106
|
renameProperty(property) {
|
|
114
|
-
this.
|
|
115
|
-
.prompt(translate('Please enter the new name of this property'))
|
|
116
|
-
.then(({ prompt }) => {
|
|
117
|
-
if (!prompt || !this.datalayer.validateName(prompt)) return
|
|
118
|
-
this.datalayer.renameProperty(property, prompt)
|
|
119
|
-
this.open()
|
|
120
|
-
})
|
|
107
|
+
this.datalayer.askForRenameProperty(property).then(() => this.open())
|
|
121
108
|
}
|
|
122
109
|
|
|
123
110
|
deleteProperty(property) {
|
|
124
|
-
this.
|
|
125
|
-
.confirm(
|
|
126
|
-
translate('Are you sure you want to delete this property on all the features?')
|
|
127
|
-
)
|
|
128
|
-
.then(() => {
|
|
129
|
-
this.datalayer.deleteProperty(property)
|
|
130
|
-
this.resetProperties()
|
|
131
|
-
this.open()
|
|
132
|
-
})
|
|
111
|
+
this.datalayer.confirmDeleteProperty(property).then(() => this.open())
|
|
133
112
|
}
|
|
134
113
|
|
|
135
114
|
addProperty() {
|
|
136
|
-
this.datalayer.addProperty().then(() =>
|
|
137
|
-
this.open()
|
|
138
|
-
})
|
|
115
|
+
this.datalayer.addProperty().then(() => this.open())
|
|
139
116
|
}
|
|
140
117
|
|
|
141
118
|
open() {
|
|
142
119
|
const id = 'tableeditor:edit'
|
|
143
|
-
this.resetProperties()
|
|
144
120
|
this.renderHeaders()
|
|
145
121
|
this.elements.body.innerHTML = ''
|
|
146
122
|
this.renderBody()
|
|
@@ -149,7 +125,7 @@ export default class TableEditor extends WithTemplate {
|
|
|
149
125
|
if (!this.datalayer.isRemoteLayer()) {
|
|
150
126
|
const addButton = loadTemplate(`
|
|
151
127
|
<button class="flat" type="button" data-ref="add">
|
|
152
|
-
<i class="icon icon-16 icon-add"></i>${translate('Add a new
|
|
128
|
+
<i class="icon icon-16 icon-add"></i>${translate('Add a new field')}
|
|
153
129
|
</button>`)
|
|
154
130
|
addButton.addEventListener('click', () => this.addProperty())
|
|
155
131
|
actions.push(addButton)
|
|
@@ -181,10 +157,10 @@ export default class TableEditor extends WithTemplate {
|
|
|
181
157
|
const property = cell.dataset.property
|
|
182
158
|
const field = `properties.${property}`
|
|
183
159
|
const tr = event.target.closest('tr')
|
|
184
|
-
const feature = this.datalayer.
|
|
160
|
+
const feature = this.datalayer.features.get(tr.dataset.feature)
|
|
185
161
|
const handler = property === 'description' ? 'Textarea' : 'Input'
|
|
186
162
|
const builder = new MutatingForm(feature, [[field, { handler }]], {
|
|
187
|
-
id: `umap-feature-properties_${
|
|
163
|
+
id: `umap-feature-properties_${feature.id}`,
|
|
188
164
|
})
|
|
189
165
|
cell.innerHTML = ''
|
|
190
166
|
cell.appendChild(builder.build())
|
|
@@ -293,7 +269,7 @@ export default class TableEditor extends WithTemplate {
|
|
|
293
269
|
this.datalayer.hide()
|
|
294
270
|
for (const row of selectedRows) {
|
|
295
271
|
const id = row.dataset.feature
|
|
296
|
-
const feature = this.datalayer.
|
|
272
|
+
const feature = this.datalayer.features.get(id)
|
|
297
273
|
feature.del()
|
|
298
274
|
}
|
|
299
275
|
this.datalayer.show()
|
|
@@ -60,20 +60,21 @@ export default class TemplateImporter {
|
|
|
60
60
|
break
|
|
61
61
|
}
|
|
62
62
|
body.textContent = message
|
|
63
|
+
return
|
|
63
64
|
}
|
|
65
|
+
const ul = Utils.loadTemplate('<ul></ul>')
|
|
66
|
+
body.appendChild(ul)
|
|
64
67
|
for (const template of data.templates) {
|
|
65
68
|
const item = Utils.loadTemplate(
|
|
66
|
-
`<
|
|
67
|
-
<dt>
|
|
69
|
+
`<li>
|
|
68
70
|
<label>
|
|
69
71
|
<input type="radio" value="${template.id}" name="template" />${template.name}
|
|
70
72
|
<a href="${template.url}" target="_blank"><nobr>${translate('Explore')}<i class="icon icon-16 icon-external-link"></i></nobr></a>
|
|
71
73
|
</label>
|
|
72
|
-
</
|
|
73
|
-
|
|
74
|
-
</dl>`
|
|
74
|
+
</li>
|
|
75
|
+
`
|
|
75
76
|
)
|
|
76
|
-
|
|
77
|
+
ul.appendChild(item)
|
|
77
78
|
}
|
|
78
79
|
tabs.querySelectorAll('button').forEach((el) => el.classList.remove('on'))
|
|
79
80
|
tabs.querySelector(`[data-value="${source}"]`).classList.add('on')
|
|
@@ -213,7 +213,9 @@ export class BottomBar extends WithTemplate {
|
|
|
213
213
|
const selected = select.options[select.selectedIndex].value
|
|
214
214
|
if (!selected) return
|
|
215
215
|
this._umap.datalayers.active().map((datalayer) => {
|
|
216
|
-
|
|
216
|
+
if (datalayer.properties.inCaption !== false) {
|
|
217
|
+
datalayer.toggle(datalayer.id === selected)
|
|
218
|
+
}
|
|
217
219
|
})
|
|
218
220
|
})
|
|
219
221
|
this.redraw()
|
|
@@ -263,6 +265,7 @@ const EDIT_BAR_TEMPLATE = `
|
|
|
263
265
|
<li data-ref="multipolygon" hidden>
|
|
264
266
|
<button type="button" title="${translate('Add a polygon to the current multi')}"><i class="icon icon-24 icon-multipolygon"></i></button>
|
|
265
267
|
</li>
|
|
268
|
+
<li data-ref="route" hidden><button type="button" data-getstarted title="${translate('Draw along routes')}"><i class="icon icon-24 icon-route"></i></button></li>
|
|
266
269
|
<hr>
|
|
267
270
|
<li data-ref="caption" hidden><button data-getstarted type="button" title="${translate('Edit map name and caption')}"><i class="icon icon-24 icon-caption"></i></button></li>
|
|
268
271
|
<li data-ref="import" hidden><button type="button"><i class="icon icon-24 icon-upload"></i></button></li>
|
|
@@ -293,6 +296,7 @@ export class EditBar extends WithTemplate {
|
|
|
293
296
|
this._onClick('multiline', () => this._umap.editedFeature.ui.editor.newShape())
|
|
294
297
|
this._onClick('polygon', () => this._leafletMap.editTools.startPolygon())
|
|
295
298
|
this._onClick('multipolygon', () => this._umap.editedFeature.ui.editor.newShape())
|
|
299
|
+
this._onClick('route', () => this._leafletMap.editTools.startRoute())
|
|
296
300
|
this._onClick('caption', () => this._umap.editCaption())
|
|
297
301
|
this._onClick('import', () => this._umap.importer.open())
|
|
298
302
|
this._onClick('templates', () => this.templateIimporter.open())
|
|
@@ -321,6 +325,7 @@ export class EditBar extends WithTemplate {
|
|
|
321
325
|
this.elements.center.hidden = this._umap.properties.editMode !== 'advanced'
|
|
322
326
|
this.elements.permissions.hidden = this._umap.properties.editMode !== 'advanced'
|
|
323
327
|
this.elements.settings.hidden = this._umap.properties.editMode !== 'advanced'
|
|
328
|
+
this.elements.route.hidden = !this._umap.properties.ORSAPIKey
|
|
324
329
|
}
|
|
325
330
|
|
|
326
331
|
_addTitle(ref, label) {
|
|
@@ -12,9 +12,19 @@ export class Positioned {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
toggleClassPosition(position) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const positions = [
|
|
16
|
+
'bottom',
|
|
17
|
+
'top',
|
|
18
|
+
'left',
|
|
19
|
+
'right',
|
|
20
|
+
'bottom-right',
|
|
21
|
+
'bottom-left',
|
|
22
|
+
'top-right',
|
|
23
|
+
'top-left',
|
|
24
|
+
]
|
|
25
|
+
for (const known of positions) {
|
|
26
|
+
this.container.classList.toggle(`tooltip-${known}`, position === known)
|
|
27
|
+
}
|
|
18
28
|
}
|
|
19
29
|
|
|
20
30
|
anchorTop(el) {
|
|
@@ -39,7 +49,6 @@ export class Positioned {
|
|
|
39
49
|
anchorRight(el) {
|
|
40
50
|
this.toggleClassPosition('right')
|
|
41
51
|
const coords = this.getPosition(el)
|
|
42
|
-
console.log(coords)
|
|
43
52
|
this.setPosition({
|
|
44
53
|
left: coords.right + 11,
|
|
45
54
|
top: coords.top,
|
|
@@ -71,18 +80,24 @@ export class Positioned {
|
|
|
71
80
|
}
|
|
72
81
|
|
|
73
82
|
computePosition([x, y]) {
|
|
83
|
+
let tooltip = ''
|
|
74
84
|
let left
|
|
75
85
|
let top
|
|
76
|
-
if (x < window.innerWidth / 2) {
|
|
77
|
-
left = x
|
|
78
|
-
} else {
|
|
79
|
-
left = x - this.container.offsetWidth
|
|
80
|
-
}
|
|
81
86
|
if (y < window.innerHeight / 2) {
|
|
82
87
|
top = Math.min(y, window.innerHeight - this.container.offsetHeight)
|
|
88
|
+
tooltip += 'top'
|
|
83
89
|
} else {
|
|
84
90
|
top = Math.max(0, y - this.container.offsetHeight)
|
|
91
|
+
tooltip += 'bottom'
|
|
92
|
+
}
|
|
93
|
+
if (x < window.innerWidth / 2) {
|
|
94
|
+
left = x
|
|
95
|
+
tooltip += '-left'
|
|
96
|
+
} else {
|
|
97
|
+
left = x - this.container.offsetWidth
|
|
98
|
+
tooltip += '-right'
|
|
85
99
|
}
|
|
100
|
+
this.toggleClassPosition(tooltip)
|
|
86
101
|
this.setPosition({ left, top })
|
|
87
102
|
}
|
|
88
103
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { loadTemplate } from '../utils.js'
|
|
1
|
+
import { loadTemplate, loadTemplateWithRefs } from '../utils.js'
|
|
2
2
|
import { Positioned } from './base.js'
|
|
3
3
|
|
|
4
4
|
export default class ContextMenu extends Positioned {
|
|
@@ -29,16 +29,21 @@ export default class ContextMenu extends Positioned {
|
|
|
29
29
|
this.openAt([coords.left, coords.bottom], items)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
this.container.innerHTML = ''
|
|
32
|
+
addItems(items, container) {
|
|
34
33
|
for (const item of items) {
|
|
35
34
|
if (item === '-') {
|
|
36
|
-
|
|
35
|
+
container.appendChild(document.createElement('hr'))
|
|
36
|
+
} else if (item.items) {
|
|
37
|
+
const [li, { bar }] = loadTemplateWithRefs(
|
|
38
|
+
`<li class="dark"><ul data-ref=bar class="icon-bar"></ul></li>`
|
|
39
|
+
)
|
|
40
|
+
this.addItems(item.items, bar)
|
|
41
|
+
container.appendChild(li)
|
|
37
42
|
} else if (typeof item.action === 'string') {
|
|
38
43
|
const li = loadTemplate(
|
|
39
44
|
`<li class="${item.className || ''}"><a tabindex="0" href="${item.action}">${item.label}</a></li>`
|
|
40
45
|
)
|
|
41
|
-
|
|
46
|
+
container.appendChild(li)
|
|
42
47
|
} else {
|
|
43
48
|
let content = item.label || ''
|
|
44
49
|
if (item.icon) {
|
|
@@ -51,9 +56,14 @@ export default class ContextMenu extends Positioned {
|
|
|
51
56
|
this.close()
|
|
52
57
|
item.action()
|
|
53
58
|
})
|
|
54
|
-
|
|
59
|
+
container.appendChild(li)
|
|
55
60
|
}
|
|
56
61
|
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
openAt([left, top], items) {
|
|
65
|
+
this.container.innerHTML = ''
|
|
66
|
+
this.addItems(items, this.container)
|
|
57
67
|
// When adding contextmenu below the map container, clicking on any link will send the
|
|
58
68
|
// "focusout" element on link click, preventing to trigger the click action
|
|
59
69
|
const parent = document
|
|
@@ -65,7 +75,7 @@ export default class ContextMenu extends Positioned {
|
|
|
65
75
|
} else {
|
|
66
76
|
this.computePosition([left, top])
|
|
67
77
|
}
|
|
68
|
-
this.container.querySelector('
|
|
78
|
+
this.container.querySelector('button, a').focus()
|
|
69
79
|
this.container.addEventListener(
|
|
70
80
|
'keydown',
|
|
71
81
|
(event) => {
|
|
@@ -37,7 +37,8 @@ export default class Dialog extends WithTemplate {
|
|
|
37
37
|
this.init()
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
collectFormData(
|
|
40
|
+
collectFormData() {
|
|
41
|
+
const formData = new FormData(this.elements.form)
|
|
41
42
|
const object = {}
|
|
42
43
|
formData.forEach((value, key) => {
|
|
43
44
|
if (!Reflect.has(object, key)) {
|
|
@@ -145,6 +146,10 @@ export default class Dialog extends WithTemplate {
|
|
|
145
146
|
return this.waitForUser()
|
|
146
147
|
}
|
|
147
148
|
|
|
149
|
+
on(...args) {
|
|
150
|
+
this.dialog.addEventListener(...args)
|
|
151
|
+
}
|
|
152
|
+
|
|
148
153
|
close() {
|
|
149
154
|
this.toggle(false)
|
|
150
155
|
this.dialog.returnValue = undefined
|
|
@@ -171,9 +176,7 @@ export default class Dialog extends WithTemplate {
|
|
|
171
176
|
'close',
|
|
172
177
|
(event) => {
|
|
173
178
|
if (this.dialog.returnValue === 'accept') {
|
|
174
|
-
const value = this.hasFormData
|
|
175
|
-
? this.collectFormData(new FormData(this.elements.form))
|
|
176
|
-
: true
|
|
179
|
+
const value = this.hasFormData ? this.collectFormData() : true
|
|
177
180
|
resolve(value)
|
|
178
181
|
}
|
|
179
182
|
},
|
|
@@ -88,6 +88,13 @@ export class Panel {
|
|
|
88
88
|
this._leafletMap.invalidateSize({ pan: false })
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
+
scrollTo(selector) {
|
|
92
|
+
const fieldset = this.container.querySelector(selector)
|
|
93
|
+
if (!fieldset) return
|
|
94
|
+
fieldset.open = true
|
|
95
|
+
const { top, left } = fieldset.getBoundingClientRect()
|
|
96
|
+
this.container.scrollTo(left, top)
|
|
97
|
+
}
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
export class EditPanel extends Panel {
|
|
@@ -2,7 +2,6 @@ import {
|
|
|
2
2
|
DomUtil,
|
|
3
3
|
Util as LeafletUtil,
|
|
4
4
|
latLngBounds,
|
|
5
|
-
stamp,
|
|
6
5
|
} from '../../vendors/leaflet/leaflet-src.esm.js'
|
|
7
6
|
import {
|
|
8
7
|
uMapAlert as Alert,
|
|
@@ -34,6 +33,7 @@ import Tooltip from './ui/tooltip.js'
|
|
|
34
33
|
import URLs from './urls.js'
|
|
35
34
|
import * as Utils from './utils.js'
|
|
36
35
|
import { DataLayerManager } from './managers.js'
|
|
36
|
+
import { Importer as OpenRouteService } from './importers/openrouteservice.js'
|
|
37
37
|
|
|
38
38
|
export default class Umap {
|
|
39
39
|
constructor(element, geojson) {
|
|
@@ -129,7 +129,6 @@ export default class Umap {
|
|
|
129
129
|
)
|
|
130
130
|
this.tooltip = new Tooltip(this._leafletMap._controlContainer)
|
|
131
131
|
this.contextmenu = new ContextMenu()
|
|
132
|
-
this.editContextmenu = new ContextMenu({ className: 'dark', orientation: 'rows' })
|
|
133
132
|
this.server = new ServerRequest()
|
|
134
133
|
this.request = new Request()
|
|
135
134
|
this.facets = new Facets(this)
|
|
@@ -211,7 +210,7 @@ export default class Umap {
|
|
|
211
210
|
|
|
212
211
|
if (!this.properties.noControl) {
|
|
213
212
|
this.initShortcuts()
|
|
214
|
-
this._leafletMap.on('contextmenu', (
|
|
213
|
+
this._leafletMap.on('contextmenu', (event) => this.onContextMenu(event))
|
|
215
214
|
this.onceDataLoaded(this.setViewFromQueryString)
|
|
216
215
|
this.bottomBar.setup()
|
|
217
216
|
this.propagate()
|
|
@@ -262,6 +261,17 @@ export default class Umap {
|
|
|
262
261
|
return window.self !== window.top
|
|
263
262
|
}
|
|
264
263
|
|
|
264
|
+
get fields() {
|
|
265
|
+
if (!this.properties.fields) this.properties.fields = []
|
|
266
|
+
return this.properties.fields
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
get fieldKeys() {
|
|
270
|
+
return this.fields
|
|
271
|
+
.map((field) => field.key)
|
|
272
|
+
.concat(...this.datalayers.active().map((dl) => dl.fieldKeys))
|
|
273
|
+
}
|
|
274
|
+
|
|
265
275
|
setPropertiesFromQueryString() {
|
|
266
276
|
const asBoolean = (key) => {
|
|
267
277
|
const value = this.searchParams.get(key)
|
|
@@ -381,48 +391,28 @@ export default class Umap {
|
|
|
381
391
|
}
|
|
382
392
|
}
|
|
383
393
|
|
|
384
|
-
|
|
394
|
+
getOwnContextMenu(event) {
|
|
385
395
|
const items = []
|
|
386
|
-
if (this.
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
})
|
|
393
|
-
}
|
|
394
|
-
if (this.properties.enableMarkerDraw) {
|
|
395
|
-
items.push({
|
|
396
|
-
label: this.help.displayLabel('DRAW_MARKER'),
|
|
396
|
+
if (this.editEnabled) {
|
|
397
|
+
items.push({
|
|
398
|
+
items: [
|
|
399
|
+
{
|
|
400
|
+
title: this.help.displayLabel('DRAW_MARKER', false),
|
|
401
|
+
icon: 'icon-marker',
|
|
397
402
|
action: () => this._leafletMap.editTools.startMarker(),
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
label: this.help.displayLabel('DRAW_POLYGON'),
|
|
403
|
-
action: () => this._leafletMap.editTools.startPolygon(),
|
|
404
|
-
})
|
|
405
|
-
}
|
|
406
|
-
if (this.properties.enablePolygonDraw) {
|
|
407
|
-
items.push({
|
|
408
|
-
label: this.help.displayLabel('DRAW_LINE'),
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
title: this.help.displayLabel('DRAW_LINE', false),
|
|
406
|
+
icon: 'icon-polyline',
|
|
409
407
|
action: () => this._leafletMap.editTools.startPolyline(),
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
}
|
|
418
|
-
items.push({
|
|
419
|
-
label: this.help.displayLabel('TOGGLE_EDIT'),
|
|
420
|
-
action: () => this.enableEdit(),
|
|
421
|
-
})
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
if (items.length) {
|
|
425
|
-
items.push('-')
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
title: this.help.displayLabel('DRAW_POLYGON', false),
|
|
411
|
+
icon: 'icon-polygon',
|
|
412
|
+
action: () => this._leafletMap.editTools.startPolygon(),
|
|
413
|
+
},
|
|
414
|
+
],
|
|
415
|
+
})
|
|
426
416
|
}
|
|
427
417
|
items.push(
|
|
428
418
|
{
|
|
@@ -453,27 +443,32 @@ export default class Umap {
|
|
|
453
443
|
return items
|
|
454
444
|
}
|
|
455
445
|
|
|
456
|
-
|
|
446
|
+
getSharedContextMenu(event) {
|
|
457
447
|
const items = []
|
|
458
448
|
if (this.properties.urls.routing) {
|
|
459
|
-
items.push(
|
|
449
|
+
items.push({
|
|
460
450
|
label: translate('Directions from here'),
|
|
461
451
|
action: () => this.openExternalRouting(event),
|
|
462
452
|
})
|
|
463
453
|
}
|
|
454
|
+
if (this.properties.ORSAPIKey) {
|
|
455
|
+
items.push({
|
|
456
|
+
label: translate('Compute isochrone from here'),
|
|
457
|
+
action: () => this.askForIsochrone(event),
|
|
458
|
+
})
|
|
459
|
+
}
|
|
464
460
|
if (this.properties.urls.edit_in_osm) {
|
|
465
|
-
items.push(
|
|
461
|
+
items.push({
|
|
466
462
|
label: translate('Edit in OpenStreetMap'),
|
|
467
463
|
action: () => this.editInOSM(event),
|
|
468
464
|
})
|
|
469
465
|
}
|
|
466
|
+
if (items.length) items.unshift('-')
|
|
470
467
|
return items
|
|
471
468
|
}
|
|
472
469
|
|
|
473
470
|
onContextMenu(event) {
|
|
474
|
-
const items = this.
|
|
475
|
-
this.getSharedContextMenuItems(event)
|
|
476
|
-
)
|
|
471
|
+
const items = this.getOwnContextMenu(event).concat(this.getSharedContextMenu(event))
|
|
477
472
|
this.contextmenu.open(event.originalEvent, items)
|
|
478
473
|
}
|
|
479
474
|
|
|
@@ -503,6 +498,10 @@ export default class Umap {
|
|
|
503
498
|
return SCHEMA[key]?.default
|
|
504
499
|
}
|
|
505
500
|
|
|
501
|
+
getColor() {
|
|
502
|
+
return this.getProperty('color')
|
|
503
|
+
}
|
|
504
|
+
|
|
506
505
|
getOption(key, feature) {
|
|
507
506
|
// TODO: remove when field.js does not call blindly obj.getOption anymore
|
|
508
507
|
return this.getProperty(key, feature)
|
|
@@ -742,10 +741,6 @@ export default class Umap {
|
|
|
742
741
|
return Boolean(this.datalayers.count())
|
|
743
742
|
}
|
|
744
743
|
|
|
745
|
-
allProperties() {
|
|
746
|
-
return [].concat(...this.datalayers.active().map((dl) => dl.allProperties()))
|
|
747
|
-
}
|
|
748
|
-
|
|
749
744
|
sortedValues(property) {
|
|
750
745
|
return []
|
|
751
746
|
.concat(...this.datalayers.active().map((dl) => dl.sortedValues(property)))
|
|
@@ -853,6 +848,7 @@ export default class Umap {
|
|
|
853
848
|
const shapeOptions = [
|
|
854
849
|
'properties.color',
|
|
855
850
|
'properties.iconClass',
|
|
851
|
+
'properties.iconSize',
|
|
856
852
|
'properties.iconUrl',
|
|
857
853
|
'properties.iconOpacity',
|
|
858
854
|
'properties.opacity',
|
|
@@ -1266,20 +1262,6 @@ export default class Umap {
|
|
|
1266
1262
|
}
|
|
1267
1263
|
}
|
|
1268
1264
|
|
|
1269
|
-
toGeoJSON() {
|
|
1270
|
-
let features = []
|
|
1271
|
-
this.datalayers.active().map((datalayer) => {
|
|
1272
|
-
if (datalayer.isVisible()) {
|
|
1273
|
-
features = features.concat(datalayer.featuresToGeoJSON())
|
|
1274
|
-
}
|
|
1275
|
-
})
|
|
1276
|
-
const geojson = {
|
|
1277
|
-
type: 'FeatureCollection',
|
|
1278
|
-
features: features,
|
|
1279
|
-
}
|
|
1280
|
-
return geojson
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
1265
|
enableEdit() {
|
|
1284
1266
|
this.editBar.redraw()
|
|
1285
1267
|
document.body.classList.add('umap-edit-enabled')
|
|
@@ -1463,7 +1445,7 @@ export default class Umap {
|
|
|
1463
1445
|
|
|
1464
1446
|
eachFeature(callback) {
|
|
1465
1447
|
this.datalayers.browsable().map((datalayer) => {
|
|
1466
|
-
if (datalayer.isVisible()) datalayer.
|
|
1448
|
+
if (datalayer.isVisible()) datalayer.features.forEach(callback)
|
|
1467
1449
|
})
|
|
1468
1450
|
}
|
|
1469
1451
|
|
|
@@ -1519,6 +1501,7 @@ export default class Umap {
|
|
|
1519
1501
|
const oldRank = datalayer.rank
|
|
1520
1502
|
datalayer.rank = rank
|
|
1521
1503
|
datalayer.sync.update('options.rank', rank, oldRank)
|
|
1504
|
+
datalayer.redraw()
|
|
1522
1505
|
}
|
|
1523
1506
|
})
|
|
1524
1507
|
this.sync.commitBatch()
|
|
@@ -1735,6 +1718,12 @@ export default class Umap {
|
|
|
1735
1718
|
if (url) window.open(url)
|
|
1736
1719
|
}
|
|
1737
1720
|
|
|
1721
|
+
async askForIsochrone(event) {
|
|
1722
|
+
if (!this.properties.ORSAPIKey) return
|
|
1723
|
+
const importer = new OpenRouteService(this)
|
|
1724
|
+
importer.isochrone(event.latlng)
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1738
1727
|
setCenterAndZoom() {
|
|
1739
1728
|
this._setCenterAndZoom(true)
|
|
1740
1729
|
Alert.success(translate('The zoom and center have been modified.'))
|
|
@@ -1765,4 +1754,32 @@ export default class Umap {
|
|
|
1765
1754
|
redo() {
|
|
1766
1755
|
this.sync._undoManager.redo()
|
|
1767
1756
|
}
|
|
1757
|
+
|
|
1758
|
+
async screenshot() {
|
|
1759
|
+
const { snapdom, preCache } = await import('../../vendors/snapdom/snapdom.min.mjs')
|
|
1760
|
+
const el = document.querySelector('#map')
|
|
1761
|
+
await preCache(el)
|
|
1762
|
+
const result = await snapdom(el, {
|
|
1763
|
+
scale: 1,
|
|
1764
|
+
type: 'jpg',
|
|
1765
|
+
fast: false,
|
|
1766
|
+
exclude: [
|
|
1767
|
+
'.leaflet-control',
|
|
1768
|
+
'.umap-loader',
|
|
1769
|
+
'.panel',
|
|
1770
|
+
'.umap-caption-bar',
|
|
1771
|
+
'.umap-main-edit-toolbox',
|
|
1772
|
+
'.umap-edit-bar',
|
|
1773
|
+
],
|
|
1774
|
+
})
|
|
1775
|
+
return result
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
async openPrinter(action) {
|
|
1779
|
+
if (!this._printer) {
|
|
1780
|
+
const Printer = (await import('./printer.js')).default
|
|
1781
|
+
this._printer = new Printer(this)
|
|
1782
|
+
}
|
|
1783
|
+
this._printer.open(action)
|
|
1784
|
+
}
|
|
1768
1785
|
}
|
|
@@ -3,15 +3,16 @@ import { default as DOMPurifyInitializer } from '../../vendors/dompurify/purify.
|
|
|
3
3
|
/**
|
|
4
4
|
* Generate a pseudo-unique identifier (5 chars long, mixed-case alphanumeric)
|
|
5
5
|
*
|
|
6
|
-
* Here's the collision risk:
|
|
7
|
-
* - for 6 chars, 1 in 100 000
|
|
8
|
-
* - for 5 chars, 5 in 100 000
|
|
9
|
-
* - for 4 chars, 500 in 100 000
|
|
10
|
-
*
|
|
11
6
|
* @returns string
|
|
12
7
|
*/
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
const CHARACTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
|
9
|
+
export function generateId(length = 5) {
|
|
10
|
+
let result = ''
|
|
11
|
+
const charactersLength = CHARACTERS.length
|
|
12
|
+
for (let i = 0; i < length; i++) {
|
|
13
|
+
result += CHARACTERS.charAt(Math.floor(Math.random() * charactersLength))
|
|
14
|
+
}
|
|
15
|
+
return result
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
/**
|