umap-project 2.9.0b0__py3-none-any.whl → 2.9.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.
- umap/__init__.py +1 -1
- umap/admin.py +15 -2
- umap/locale/br/LC_MESSAGES/django.mo +0 -0
- umap/locale/br/LC_MESSAGES/django.po +111 -67
- umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
- umap/locale/cs_CZ/LC_MESSAGES/django.po +112 -67
- umap/locale/el/LC_MESSAGES/django.mo +0 -0
- umap/locale/el/LC_MESSAGES/django.po +132 -87
- umap/locale/en/LC_MESSAGES/django.po +11 -10
- umap/locale/es/LC_MESSAGES/django.mo +0 -0
- umap/locale/es/LC_MESSAGES/django.po +117 -71
- umap/locale/fr/LC_MESSAGES/django.mo +0 -0
- umap/locale/fr/LC_MESSAGES/django.po +11 -10
- umap/locale/gl/LC_MESSAGES/django.mo +0 -0
- umap/locale/gl/LC_MESSAGES/django.po +219 -173
- umap/locale/it/LC_MESSAGES/django.mo +0 -0
- umap/locale/it/LC_MESSAGES/django.po +145 -100
- umap/locale/nl/LC_MESSAGES/django.mo +0 -0
- umap/locale/nl/LC_MESSAGES/django.po +198 -152
- umap/locale/pt/LC_MESSAGES/django.mo +0 -0
- umap/locale/pt/LC_MESSAGES/django.po +118 -73
- umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
- umap/locale/zh_TW/LC_MESSAGES/django.po +112 -67
- umap/middleware.py +30 -1
- umap/models.py +20 -10
- umap/settings/base.py +2 -1
- umap/static/umap/base.css +4 -1
- umap/static/umap/css/bar.css +32 -0
- umap/static/umap/css/contextmenu.css +14 -2
- umap/static/umap/css/form.css +5 -10
- umap/static/umap/css/icon.css +39 -3
- umap/static/umap/css/panel.css +18 -1
- umap/static/umap/css/popup.css +0 -1
- umap/static/umap/img/16-white.svg +3 -3
- umap/static/umap/img/16.svg +1 -1
- umap/static/umap/img/24-white.svg +17 -16
- umap/static/umap/img/24.svg +29 -18
- umap/static/umap/img/providers/twitter-oauth2.png +0 -0
- umap/static/umap/img/source/16-white.svg +4 -4
- umap/static/umap/img/source/16.svg +1 -1
- umap/static/umap/img/source/24-white.svg +20 -18
- umap/static/umap/img/source/24.svg +30 -19
- umap/static/umap/js/modules/browser.js +2 -2
- umap/static/umap/js/modules/caption.js +4 -4
- umap/static/umap/js/modules/data/features.js +80 -32
- umap/static/umap/js/modules/data/layer.js +37 -50
- umap/static/umap/js/modules/form/builder.js +23 -22
- umap/static/umap/js/modules/form/fields.js +13 -5
- umap/static/umap/js/modules/formatter.js +6 -2
- umap/static/umap/js/modules/help.js +17 -23
- umap/static/umap/js/modules/importer.js +5 -2
- umap/static/umap/js/modules/permissions.js +6 -2
- umap/static/umap/js/modules/rendering/layers/classified.js +1 -1
- umap/static/umap/js/modules/rendering/map.js +1 -21
- umap/static/umap/js/modules/rendering/ui.js +20 -38
- umap/static/umap/js/modules/rules.js +1 -1
- umap/static/umap/js/modules/saving.js +5 -0
- umap/static/umap/js/modules/schema.js +4 -1
- umap/static/umap/js/modules/sync/engine.js +39 -14
- umap/static/umap/js/modules/sync/updaters.js +7 -6
- umap/static/umap/js/modules/sync/websocket.js +48 -40
- umap/static/umap/js/modules/ui/bar.js +84 -0
- umap/static/umap/js/modules/ui/contextmenu.js +9 -2
- umap/static/umap/js/modules/ui/panel.js +5 -1
- umap/static/umap/js/modules/umap.js +85 -44
- umap/static/umap/js/umap.controls.js +11 -341
- umap/static/umap/locale/am_ET.js +17 -5
- umap/static/umap/locale/am_ET.json +17 -5
- umap/static/umap/locale/ar.js +17 -5
- umap/static/umap/locale/ar.json +17 -5
- umap/static/umap/locale/ast.js +17 -5
- umap/static/umap/locale/ast.json +17 -5
- umap/static/umap/locale/bg.js +17 -5
- umap/static/umap/locale/bg.json +17 -5
- umap/static/umap/locale/br.js +20 -15
- umap/static/umap/locale/br.json +20 -15
- umap/static/umap/locale/ca.js +8 -4
- umap/static/umap/locale/ca.json +8 -4
- umap/static/umap/locale/cs_CZ.js +8 -4
- umap/static/umap/locale/cs_CZ.json +8 -4
- umap/static/umap/locale/da.js +17 -5
- umap/static/umap/locale/da.json +17 -5
- umap/static/umap/locale/de.js +8 -4
- umap/static/umap/locale/de.json +8 -4
- umap/static/umap/locale/el.js +54 -50
- umap/static/umap/locale/el.json +54 -50
- umap/static/umap/locale/en.js +9 -4
- umap/static/umap/locale/en.json +9 -4
- umap/static/umap/locale/en_US.json +17 -5
- umap/static/umap/locale/es.js +13 -9
- umap/static/umap/locale/es.json +13 -9
- umap/static/umap/locale/et.js +17 -5
- umap/static/umap/locale/et.json +17 -5
- umap/static/umap/locale/eu.js +8 -4
- umap/static/umap/locale/eu.json +8 -4
- umap/static/umap/locale/fa_IR.js +8 -4
- umap/static/umap/locale/fa_IR.json +8 -4
- umap/static/umap/locale/fi.js +17 -5
- umap/static/umap/locale/fi.json +17 -5
- umap/static/umap/locale/fr.js +9 -4
- umap/static/umap/locale/fr.json +9 -4
- umap/static/umap/locale/gl.js +13 -9
- umap/static/umap/locale/gl.json +13 -9
- umap/static/umap/locale/he.js +17 -5
- umap/static/umap/locale/he.json +17 -5
- umap/static/umap/locale/hr.js +17 -5
- umap/static/umap/locale/hr.json +17 -5
- umap/static/umap/locale/hu.js +8 -4
- umap/static/umap/locale/hu.json +8 -4
- umap/static/umap/locale/id.js +17 -5
- umap/static/umap/locale/id.json +17 -5
- umap/static/umap/locale/is.js +17 -5
- umap/static/umap/locale/is.json +17 -5
- umap/static/umap/locale/it.js +31 -27
- umap/static/umap/locale/it.json +31 -27
- umap/static/umap/locale/ja.js +17 -5
- umap/static/umap/locale/ja.json +17 -5
- umap/static/umap/locale/ko.js +17 -5
- umap/static/umap/locale/ko.json +17 -5
- umap/static/umap/locale/lt.js +17 -5
- umap/static/umap/locale/lt.json +17 -5
- umap/static/umap/locale/ms.js +8 -4
- umap/static/umap/locale/ms.json +8 -4
- umap/static/umap/locale/nl.js +132 -127
- umap/static/umap/locale/nl.json +132 -127
- umap/static/umap/locale/no.js +17 -5
- umap/static/umap/locale/no.json +17 -5
- umap/static/umap/locale/pl.js +8 -4
- umap/static/umap/locale/pl.json +8 -4
- umap/static/umap/locale/pl_PL.json +17 -5
- umap/static/umap/locale/pt.js +38 -33
- umap/static/umap/locale/pt.json +38 -33
- umap/static/umap/locale/pt_BR.js +17 -5
- umap/static/umap/locale/pt_BR.json +17 -5
- umap/static/umap/locale/pt_PT.js +8 -4
- umap/static/umap/locale/pt_PT.json +8 -4
- umap/static/umap/locale/ro.js +17 -5
- umap/static/umap/locale/ro.json +17 -5
- umap/static/umap/locale/ru.js +17 -5
- umap/static/umap/locale/ru.json +17 -5
- umap/static/umap/locale/sk_SK.js +17 -5
- umap/static/umap/locale/sk_SK.json +17 -5
- umap/static/umap/locale/sl.js +17 -5
- umap/static/umap/locale/sl.json +17 -5
- umap/static/umap/locale/sr.js +17 -5
- umap/static/umap/locale/sr.json +17 -5
- umap/static/umap/locale/sv.js +17 -5
- umap/static/umap/locale/sv.json +17 -5
- umap/static/umap/locale/th_TH.js +8 -4
- umap/static/umap/locale/th_TH.json +8 -4
- umap/static/umap/locale/tr.js +17 -5
- umap/static/umap/locale/tr.json +17 -5
- umap/static/umap/locale/uk_UA.js +17 -5
- umap/static/umap/locale/uk_UA.json +17 -5
- umap/static/umap/locale/vi.js +17 -5
- umap/static/umap/locale/vi.json +17 -5
- umap/static/umap/locale/vi_VN.json +17 -5
- umap/static/umap/locale/zh.js +17 -5
- umap/static/umap/locale/zh.json +17 -5
- umap/static/umap/locale/zh_CN.json +17 -5
- umap/static/umap/locale/zh_TW.Big5.json +17 -5
- umap/static/umap/locale/zh_TW.js +14 -10
- umap/static/umap/locale/zh_TW.json +14 -10
- umap/static/umap/map.css +17 -68
- umap/static/umap/nav.css +4 -0
- umap/static/umap/vars.css +1 -0
- umap/static/umap/vendors/dompurify/purify.es.js +138 -354
- umap/static/umap/vendors/dompurify/purify.es.mjs.map +1 -1
- umap/static/umap/vendors/editable/Leaflet.Editable.js +1 -0
- umap/sync/app.py +19 -13
- umap/sync/payloads.py +8 -1
- umap/templates/auth/user_form.html +2 -2
- umap/templates/umap/content_footer.html +1 -1
- umap/templates/umap/css.html +0 -2
- umap/templates/umap/js.html +0 -1
- umap/templates/umap/messages.html +5 -1
- umap/templates/umap/search_bar.html +1 -0
- umap/tests/integration/test_anonymous_owned_map.py +2 -2
- umap/tests/integration/test_basics.py +2 -5
- umap/tests/integration/test_categorized_layer.py +4 -8
- umap/tests/integration/test_choropleth.py +1 -1
- umap/tests/integration/test_conditional_rules.py +3 -3
- umap/tests/integration/test_draw_polygon.py +11 -19
- umap/tests/integration/test_draw_polyline.py +6 -14
- umap/tests/integration/test_edit_datalayer.py +10 -10
- umap/tests/integration/test_edit_map.py +27 -1
- umap/tests/integration/test_edit_marker.py +5 -5
- umap/tests/integration/test_edit_polygon.py +5 -5
- umap/tests/integration/test_features_id_generation.py +2 -6
- umap/tests/integration/test_import.py +93 -29
- umap/tests/integration/test_owned_map.py +1 -1
- umap/tests/integration/test_save.py +2 -2
- umap/tests/integration/test_tableeditor.py +7 -7
- umap/tests/integration/test_view_marker.py +10 -0
- umap/tests/integration/test_websocket_sync.py +128 -32
- umap/utils.py +4 -1
- umap/views.py +0 -9
- {umap_project-2.9.0b0.dist-info → umap_project-2.9.1.dist-info}/METADATA +13 -13
- {umap_project-2.9.0b0.dist-info → umap_project-2.9.1.dist-info}/RECORD +202 -204
- umap/static/umap/vendors/toolbar/leaflet.toolbar.css +0 -1
- umap/static/umap/vendors/toolbar/leaflet.toolbar.js +0 -1
- {umap_project-2.9.0b0.dist-info → umap_project-2.9.1.dist-info}/WHEEL +0 -0
- {umap_project-2.9.0b0.dist-info → umap_project-2.9.1.dist-info}/entry_points.txt +0 -0
- {umap_project-2.9.0b0.dist-info → umap_project-2.9.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -63,7 +63,7 @@ export class Form extends Utils.WithEvents {
|
|
|
63
63
|
try {
|
|
64
64
|
value = value[sub]
|
|
65
65
|
} catch {
|
|
66
|
-
console.
|
|
66
|
+
console.debug(field)
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
return value
|
|
@@ -142,49 +142,50 @@ export class MutatingForm extends Form {
|
|
|
142
142
|
slugKey: 'PropertyInput',
|
|
143
143
|
labelKey: 'PropertyInput',
|
|
144
144
|
}
|
|
145
|
-
for (const [key,
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
145
|
+
for (const [key, defaults] of Object.entries(SCHEMA)) {
|
|
146
|
+
const properties = Object.assign({}, defaults)
|
|
147
|
+
if (properties.type === Boolean) {
|
|
148
|
+
if (properties.nullable) properties.handler = 'NullableChoices'
|
|
149
|
+
else properties.handler = 'Switch'
|
|
150
|
+
} else if (properties.type === 'Text') {
|
|
151
|
+
properties.handler = 'Textarea'
|
|
152
|
+
} else if (properties.type === Number) {
|
|
153
|
+
if (properties.step) properties.handler = 'Range'
|
|
154
|
+
else properties.handler = 'IntInput'
|
|
155
|
+
} else if (properties.choices) {
|
|
156
|
+
const text_length = properties.choices.reduce(
|
|
156
157
|
(acc, [_, label]) => acc + label.length,
|
|
157
158
|
0
|
|
158
159
|
)
|
|
159
160
|
// Try to be smart and use MultiChoice only
|
|
160
161
|
// for choices where labels are shorts…
|
|
161
162
|
if (text_length < 40) {
|
|
162
|
-
|
|
163
|
+
properties.handler = 'MultiChoice'
|
|
163
164
|
} else {
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
properties.handler = 'Select'
|
|
166
|
+
properties.selectOptions = properties.choices
|
|
166
167
|
}
|
|
167
168
|
} else {
|
|
168
169
|
switch (key) {
|
|
169
170
|
case 'color':
|
|
170
171
|
case 'fillColor':
|
|
171
|
-
|
|
172
|
+
properties.handler = 'ColorPicker'
|
|
172
173
|
break
|
|
173
174
|
case 'iconUrl':
|
|
174
|
-
|
|
175
|
+
properties.handler = 'IconUrl'
|
|
175
176
|
break
|
|
176
177
|
case 'licence':
|
|
177
|
-
|
|
178
|
+
properties.handler = 'LicenceChooser'
|
|
178
179
|
break
|
|
179
180
|
}
|
|
180
181
|
}
|
|
181
182
|
|
|
182
183
|
if (customHandlers[key]) {
|
|
183
|
-
|
|
184
|
+
properties.handler = customHandlers[key]
|
|
184
185
|
}
|
|
185
186
|
// Input uses this key for its type attribute
|
|
186
|
-
delete
|
|
187
|
-
this.defaultProperties[key] =
|
|
187
|
+
delete properties.type
|
|
188
|
+
this.defaultProperties[key] = properties
|
|
188
189
|
}
|
|
189
190
|
}
|
|
190
191
|
|
|
@@ -202,7 +203,7 @@ export class MutatingForm extends Form {
|
|
|
202
203
|
getTemplate(helper) {
|
|
203
204
|
let template
|
|
204
205
|
if (helper.properties.inheritable) {
|
|
205
|
-
const extraClassName = helper.
|
|
206
|
+
const extraClassName = this.getter(helper.field) === undefined ? ' undefined' : ''
|
|
206
207
|
template = `
|
|
207
208
|
<div class="umap-field-${helper.name} formbox inheritable${extraClassName}">
|
|
208
209
|
<div class="header" data-ref=header>
|
|
@@ -80,11 +80,17 @@ class BaseElement {
|
|
|
80
80
|
this.input.value = ''
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
get(
|
|
84
|
-
|
|
83
|
+
get() {
|
|
84
|
+
let value
|
|
85
85
|
const path = this.field.split('.')
|
|
86
86
|
const key = path[path.length - 1]
|
|
87
|
-
|
|
87
|
+
if (!this.properties.inheritable) {
|
|
88
|
+
value = this.builder.getter(this.field)
|
|
89
|
+
} else {
|
|
90
|
+
value = this.obj.getOption(key)
|
|
91
|
+
}
|
|
92
|
+
if (value === undefined) return SCHEMA[key]?.default
|
|
93
|
+
return value
|
|
88
94
|
}
|
|
89
95
|
|
|
90
96
|
toHTML() {
|
|
@@ -1164,7 +1170,7 @@ Fields.MultiChoice = class extends BaseElement {
|
|
|
1164
1170
|
|
|
1165
1171
|
Fields.TernaryChoices = class extends Fields.MultiChoice {
|
|
1166
1172
|
getDefault() {
|
|
1167
|
-
return
|
|
1173
|
+
return null
|
|
1168
1174
|
}
|
|
1169
1175
|
|
|
1170
1176
|
toJS() {
|
|
@@ -1195,7 +1201,7 @@ Fields.NullableChoices = class extends Fields.TernaryChoices {
|
|
|
1195
1201
|
this.properties.choices || [
|
|
1196
1202
|
[true, translate('always')],
|
|
1197
1203
|
[false, translate('never')],
|
|
1198
|
-
[
|
|
1204
|
+
[null, translate('hidden')],
|
|
1199
1205
|
]
|
|
1200
1206
|
)
|
|
1201
1207
|
}
|
|
@@ -1251,6 +1257,7 @@ Fields.Range = class extends Fields.FloatInput {
|
|
|
1251
1257
|
|
|
1252
1258
|
Fields.ManageOwner = class extends BaseElement {
|
|
1253
1259
|
build() {
|
|
1260
|
+
super.build()
|
|
1254
1261
|
const options = {
|
|
1255
1262
|
className: 'edit-owner',
|
|
1256
1263
|
on_select: L.bind(this.onSelect, this),
|
|
@@ -1281,6 +1288,7 @@ Fields.ManageOwner = class extends BaseElement {
|
|
|
1281
1288
|
|
|
1282
1289
|
Fields.ManageEditors = class extends BaseElement {
|
|
1283
1290
|
build() {
|
|
1291
|
+
super.build()
|
|
1284
1292
|
const options = {
|
|
1285
1293
|
className: 'edit-editors',
|
|
1286
1294
|
on_select: L.bind(this.onSelect, this),
|
|
@@ -103,8 +103,12 @@ export class Formatter {
|
|
|
103
103
|
message: err[0].message,
|
|
104
104
|
})
|
|
105
105
|
}
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
if (str.split(/\r\n|\r|\n/).length <= 2) {
|
|
107
|
+
// Seems like a blank CSV, let's not warn
|
|
108
|
+
console.debug(err)
|
|
109
|
+
} else {
|
|
110
|
+
Alert.error(message, 10000)
|
|
111
|
+
}
|
|
108
112
|
}
|
|
109
113
|
if (result?.features.length) {
|
|
110
114
|
callback(result)
|
|
@@ -206,13 +206,23 @@ export default class Help {
|
|
|
206
206
|
|
|
207
207
|
// Special dynamic case. Do we still think this dialog is useful?
|
|
208
208
|
showGetStarted() {
|
|
209
|
-
const container =
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
209
|
+
const [container, { ul }] = Utils.loadTemplateWithRefs(`
|
|
210
|
+
<div>
|
|
211
|
+
<h3><i class="icon icon-16 icon-help"></i>${translate('Where do we go from here?')}</h3>
|
|
212
|
+
<ul data-ref=ul class="umap-getstarted"></ul>
|
|
213
|
+
</div>
|
|
214
|
+
`)
|
|
215
|
+
const elements = document.querySelectorAll('[data-getstarted]')
|
|
216
|
+
for (const el of elements) {
|
|
217
|
+
const [node, { button }] = Utils.loadTemplateWithRefs(
|
|
218
|
+
`<li><button data-ref=button type="button" title="${el.title}">${el.innerHTML}${el.title}</button></li>`
|
|
219
|
+
)
|
|
220
|
+
ul.appendChild(node)
|
|
221
|
+
button.addEventListener('click', () => {
|
|
222
|
+
el.click()
|
|
223
|
+
this.dialog.close()
|
|
224
|
+
})
|
|
225
|
+
}
|
|
216
226
|
this.dialog.open({ template: container })
|
|
217
227
|
}
|
|
218
228
|
|
|
@@ -233,22 +243,6 @@ export default class Help {
|
|
|
233
243
|
}
|
|
234
244
|
}
|
|
235
245
|
}
|
|
236
|
-
|
|
237
|
-
_buildEditEntry() {
|
|
238
|
-
const container = DomUtil.create('div', '')
|
|
239
|
-
const actionsContainer = DomUtil.create('ul', 'umap-edit-actions', container)
|
|
240
|
-
const addAction = (action) => {
|
|
241
|
-
const actionContainer = DomUtil.add('li', '', actionsContainer)
|
|
242
|
-
DomUtil.add('i', action.options.className, actionContainer)
|
|
243
|
-
DomUtil.add('span', '', actionContainer, action.options.tooltip)
|
|
244
|
-
DomEvent.on(actionContainer, 'click', action.addHooks, action)
|
|
245
|
-
DomEvent.on(actionContainer, 'click', this.dialog.close, this.dialog)
|
|
246
|
-
}
|
|
247
|
-
for (const action of Object.values(Help.MENU_ACTIONS)) {
|
|
248
|
-
addAction(action)
|
|
249
|
-
}
|
|
250
|
-
return container
|
|
251
|
-
}
|
|
252
246
|
}
|
|
253
247
|
|
|
254
248
|
Help.MENU_ACTIONS = {}
|
|
@@ -10,7 +10,7 @@ import Dialog from './ui/dialog.js'
|
|
|
10
10
|
import * as Utils from './utils.js'
|
|
11
11
|
|
|
12
12
|
const TEMPLATE = `
|
|
13
|
-
<div class="umap-
|
|
13
|
+
<div class="umap-import">
|
|
14
14
|
<h3><i class="icon icon-16 icon-upload"></i><span>${translate('Import data')}</span></h3>
|
|
15
15
|
<fieldset class="formbox">
|
|
16
16
|
<legend class="counter">${translate('Choose data')}</legend>
|
|
@@ -261,7 +261,10 @@ export default class Importer extends Utils.WithTemplate {
|
|
|
261
261
|
|
|
262
262
|
open() {
|
|
263
263
|
if (!this.container) this.build()
|
|
264
|
-
const onLoad = this._umap.editPanel.open({
|
|
264
|
+
const onLoad = this._umap.editPanel.open({
|
|
265
|
+
content: this.container,
|
|
266
|
+
highlight: 'import',
|
|
267
|
+
})
|
|
265
268
|
onLoad.then(() => this.onLoad())
|
|
266
269
|
}
|
|
267
270
|
|
|
@@ -166,12 +166,16 @@ export class MapPermissions extends ServerStored {
|
|
|
166
166
|
Alert.info(translate('Please save the map first'))
|
|
167
167
|
return
|
|
168
168
|
}
|
|
169
|
-
const container = DomUtil.create('div', 'permissions
|
|
169
|
+
const container = DomUtil.create('div', 'umap-edit-permissions')
|
|
170
170
|
DomUtil.createTitle(container, translate('Update permissions'), 'icon-key')
|
|
171
171
|
if (this.isAnonymousMap()) this._editAnonymous(container)
|
|
172
172
|
else this._editWithOwner(container)
|
|
173
173
|
this._editDatalayers(container)
|
|
174
|
-
this._umap.editPanel.open({
|
|
174
|
+
this._umap.editPanel.open({
|
|
175
|
+
content: container,
|
|
176
|
+
className: 'dark',
|
|
177
|
+
highlight: 'permissions',
|
|
178
|
+
})
|
|
175
179
|
}
|
|
176
180
|
|
|
177
181
|
async attach() {
|
|
@@ -75,7 +75,7 @@ const ClassifiedMixin = {
|
|
|
75
75
|
},
|
|
76
76
|
|
|
77
77
|
renderLegend: function (container) {
|
|
78
|
-
if (!this.datalayer.
|
|
78
|
+
if (!this.datalayer.isLoaded()) return
|
|
79
79
|
const parent = DomUtil.create('ul', '', container)
|
|
80
80
|
const items = this.getLegendItems()
|
|
81
81
|
for (const [color, label] of items) {
|
|
@@ -40,20 +40,6 @@ const ControlsMixin = {
|
|
|
40
40
|
|
|
41
41
|
if (this._umap.hasEditMode() && !this.options.noControl) {
|
|
42
42
|
new U.EditControl(this).addTo(this)
|
|
43
|
-
|
|
44
|
-
new U.DrawToolbar({ map: this }).addTo(this)
|
|
45
|
-
const editActions = [
|
|
46
|
-
U.EditCaptionAction,
|
|
47
|
-
U.ImportAction,
|
|
48
|
-
U.EditLayersAction,
|
|
49
|
-
U.ChangeTileLayerAction,
|
|
50
|
-
U.UpdateExtentAction,
|
|
51
|
-
U.UpdatePermsAction,
|
|
52
|
-
U.EditPropertiesAction,
|
|
53
|
-
]
|
|
54
|
-
if (this.options.editMode === 'advanced') {
|
|
55
|
-
new U.SettingsToolbar({ actions: editActions }).addTo(this)
|
|
56
|
-
}
|
|
57
43
|
}
|
|
58
44
|
this._controls.zoom = new Control.Zoom({
|
|
59
45
|
zoomInTitle: translate('Zoom in'),
|
|
@@ -231,7 +217,7 @@ const ManageTilelayerMixin = {
|
|
|
231
217
|
}
|
|
232
218
|
},
|
|
233
219
|
|
|
234
|
-
|
|
220
|
+
editTileLayers: function () {
|
|
235
221
|
if (this._controls.tilelayersChooser) {
|
|
236
222
|
this._controls.tilelayersChooser.openSwitcher({ edit: true })
|
|
237
223
|
}
|
|
@@ -264,7 +250,6 @@ export const LeafletMap = BaseMap.extend({
|
|
|
264
250
|
DomEvent.on(document.body, 'dataload', (event) =>
|
|
265
251
|
this.fire('dataload', event.detail)
|
|
266
252
|
)
|
|
267
|
-
this.on('click', this.closeInplaceToolbar)
|
|
268
253
|
}
|
|
269
254
|
|
|
270
255
|
this.on('baselayerchange', (e) => {
|
|
@@ -298,11 +283,6 @@ export const LeafletMap = BaseMap.extend({
|
|
|
298
283
|
this.handleLimitBounds()
|
|
299
284
|
},
|
|
300
285
|
|
|
301
|
-
closeInplaceToolbar: function () {
|
|
302
|
-
const toolbar = this._toolbars[L.Toolbar.Popup._toolbar_class_id]
|
|
303
|
-
if (toolbar) toolbar.remove()
|
|
304
|
-
},
|
|
305
|
-
|
|
306
286
|
latLng: (a, b, c) => {
|
|
307
287
|
// manage geojson case and call original method
|
|
308
288
|
if (!(a instanceof L.LatLng) && a.coordinates) {
|
|
@@ -29,12 +29,9 @@ const FeatureMixin = {
|
|
|
29
29
|
|
|
30
30
|
onRemove: function (map) {
|
|
31
31
|
this.parentClass.prototype.onRemove.call(this, map)
|
|
32
|
-
if (map.editedFeature === this.feature) {
|
|
33
|
-
this.feature._marked_for_deletion = true
|
|
32
|
+
if (map._umap.editedFeature === this.feature) {
|
|
34
33
|
this.feature.endEdit()
|
|
35
|
-
|
|
36
|
-
map.editPanel.close()
|
|
37
|
-
}
|
|
34
|
+
map._umap.editPanel.close()
|
|
38
35
|
}
|
|
39
36
|
},
|
|
40
37
|
|
|
@@ -47,6 +44,7 @@ const FeatureMixin = {
|
|
|
47
44
|
addInteractions: function () {
|
|
48
45
|
this.on('contextmenu editable:vertex:contextmenu', this.onContextMenu)
|
|
49
46
|
this.on('click', this.onClick)
|
|
47
|
+
this.on('editable:edited', this.onCommit)
|
|
50
48
|
},
|
|
51
49
|
|
|
52
50
|
onClick: function (event) {
|
|
@@ -59,15 +57,13 @@ const FeatureMixin = {
|
|
|
59
57
|
if (event.originalEvent.ctrlKey || event.originalEvent.metaKey) {
|
|
60
58
|
this.feature.datalayer.edit(event)
|
|
61
59
|
} else {
|
|
62
|
-
|
|
63
|
-
else this.feature.edit(event)
|
|
60
|
+
this.feature.toggleEditing(event)
|
|
64
61
|
}
|
|
65
62
|
} else if (!this._map.editTools?.drawing()) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}).addTo(this._map, this.feature, event.latlng)
|
|
63
|
+
this._map._umap.editContextmenu.open(
|
|
64
|
+
event.originalEvent,
|
|
65
|
+
this.feature.getInplaceEditMenu(event)
|
|
66
|
+
)
|
|
71
67
|
}
|
|
72
68
|
}
|
|
73
69
|
DomEvent.stop(event)
|
|
@@ -104,8 +100,6 @@ const FeatureMixin = {
|
|
|
104
100
|
this.feature.pullGeometry(false)
|
|
105
101
|
this.feature.onCommit()
|
|
106
102
|
},
|
|
107
|
-
|
|
108
|
-
getPopupToolbarAnchor: () => [0, 0],
|
|
109
103
|
}
|
|
110
104
|
|
|
111
105
|
const PointMixin = {
|
|
@@ -118,9 +112,8 @@ const PointMixin = {
|
|
|
118
112
|
this.on('dragend', (event) => {
|
|
119
113
|
this.isDirty = true
|
|
120
114
|
this.feature.edit(event)
|
|
121
|
-
this.feature.pullGeometry()
|
|
115
|
+
this.feature.pullGeometry(false)
|
|
122
116
|
})
|
|
123
|
-
this.on('editable:drawing:commit', this.onCommit)
|
|
124
117
|
if (!this.feature.isReadOnly()) this.on('mouseover', this._enableDragging)
|
|
125
118
|
this.on('mouseout', this._onMouseOut)
|
|
126
119
|
},
|
|
@@ -248,10 +241,6 @@ export const LeafletMarker = Marker.extend({
|
|
|
248
241
|
this._redraw()
|
|
249
242
|
this._resetZIndex()
|
|
250
243
|
},
|
|
251
|
-
|
|
252
|
-
getPopupToolbarAnchor: function () {
|
|
253
|
-
return this.options.icon.options.popupAnchor
|
|
254
|
-
},
|
|
255
244
|
})
|
|
256
245
|
|
|
257
246
|
const PathMixin = {
|
|
@@ -267,6 +256,8 @@ const PathMixin = {
|
|
|
267
256
|
},
|
|
268
257
|
|
|
269
258
|
makeGeometryEditable: function () {
|
|
259
|
+
// Feature has been removed since then?
|
|
260
|
+
if (!this._map) return
|
|
270
261
|
if (this._map._umap.editedFeature !== this.feature) {
|
|
271
262
|
this.disableEdit()
|
|
272
263
|
return
|
|
@@ -285,13 +276,17 @@ const PathMixin = {
|
|
|
285
276
|
|
|
286
277
|
addInteractions: function () {
|
|
287
278
|
FeatureMixin.addInteractions.call(this)
|
|
288
|
-
this.on('editable:disable', this.onCommit)
|
|
289
279
|
this.on('mouseover', this._onMouseOver)
|
|
290
280
|
this.on('drag editable:drag', this._onDrag)
|
|
291
281
|
this.on('popupopen', this.highlightPath)
|
|
292
282
|
this.on('popupclose', this._redraw)
|
|
293
283
|
},
|
|
294
284
|
|
|
285
|
+
bindTooltip: function (content, options) {
|
|
286
|
+
options.sticky = !options.permanent
|
|
287
|
+
this.parentClass.prototype.bindTooltip.call(this, content, options)
|
|
288
|
+
},
|
|
289
|
+
|
|
295
290
|
highlightPath: function () {
|
|
296
291
|
this.parentClass.prototype.setStyle.call(this, {
|
|
297
292
|
fillOpacity: Math.sqrt(this.feature.getDynamicOption('fillOpacity', 1.0)),
|
|
@@ -335,13 +330,11 @@ const PathMixin = {
|
|
|
335
330
|
this.resetTooltip()
|
|
336
331
|
},
|
|
337
332
|
|
|
338
|
-
getVertexActions: () => [U.DeleteVertexAction],
|
|
339
|
-
|
|
340
333
|
onVertexRawClick: function (event) {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
334
|
+
this._map._umap.editContextmenu.open(
|
|
335
|
+
event.originalEvent,
|
|
336
|
+
this.feature.getInplaceEditVertexMenu(event)
|
|
337
|
+
)
|
|
345
338
|
},
|
|
346
339
|
|
|
347
340
|
isolateShape: function (atLatLng) {
|
|
@@ -377,17 +370,6 @@ export const LeafletPolyline = Polyline.extend({
|
|
|
377
370
|
|
|
378
371
|
getClass: () => LeafletPolyline,
|
|
379
372
|
|
|
380
|
-
getVertexActions: function (event) {
|
|
381
|
-
const actions = PathMixin.getVertexActions.call(this, event)
|
|
382
|
-
const index = event.vertex.getIndex()
|
|
383
|
-
if (index === 0 || index === event.vertex.getLastIndex()) {
|
|
384
|
-
actions.push(U.ContinueLineAction)
|
|
385
|
-
} else {
|
|
386
|
-
actions.push(U.SplitLineAction)
|
|
387
|
-
}
|
|
388
|
-
return actions
|
|
389
|
-
},
|
|
390
|
-
|
|
391
373
|
getMeasure: function (shape) {
|
|
392
374
|
let shapes
|
|
393
375
|
if (shape) {
|
|
@@ -278,6 +278,7 @@ export const SCHEMA = {
|
|
|
278
278
|
impacts: ['ui'],
|
|
279
279
|
nullable: true,
|
|
280
280
|
label: translate('Display the locate control'),
|
|
281
|
+
default: null,
|
|
281
282
|
},
|
|
282
283
|
longCredit: {
|
|
283
284
|
type: 'Text',
|
|
@@ -290,6 +291,7 @@ export const SCHEMA = {
|
|
|
290
291
|
impacts: ['ui'],
|
|
291
292
|
nullable: true,
|
|
292
293
|
label: translate('Display the measure control'),
|
|
294
|
+
default: null,
|
|
293
295
|
},
|
|
294
296
|
mask: {
|
|
295
297
|
type: Boolean,
|
|
@@ -450,7 +452,7 @@ export const SCHEMA = {
|
|
|
450
452
|
choices: [
|
|
451
453
|
[true, translate('always')],
|
|
452
454
|
[false, translate('never')],
|
|
453
|
-
[
|
|
455
|
+
[null, translate('on hover')],
|
|
454
456
|
],
|
|
455
457
|
},
|
|
456
458
|
slideshow: {
|
|
@@ -507,6 +509,7 @@ export const SCHEMA = {
|
|
|
507
509
|
impacts: ['ui'],
|
|
508
510
|
nullable: true,
|
|
509
511
|
label: translate('Display the tile layers control'),
|
|
512
|
+
default: null,
|
|
510
513
|
},
|
|
511
514
|
toZoom: {
|
|
512
515
|
type: Number,
|
|
@@ -2,6 +2,7 @@ import * as Utils from '../utils.js'
|
|
|
2
2
|
import { HybridLogicalClock } from './hlc.js'
|
|
3
3
|
import { DataLayerUpdater, FeatureUpdater, MapUpdater } from './updaters.js'
|
|
4
4
|
import { WebSocketTransport } from './websocket.js'
|
|
5
|
+
import * as SaveManager from '../saving.js'
|
|
5
6
|
|
|
6
7
|
// Start reconnecting after 2 seconds, then double the delay each time
|
|
7
8
|
// maxing out at 32 seconds.
|
|
@@ -65,27 +66,35 @@ export class SyncEngine {
|
|
|
65
66
|
this.peerId = Utils.generateId()
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
get isOpen() {
|
|
70
|
+
return this.transport?.isOpen
|
|
71
|
+
}
|
|
72
|
+
|
|
68
73
|
async authenticate() {
|
|
74
|
+
if (this.isOpen) return
|
|
69
75
|
const websocketTokenURI = this._umap.urls.get('map_websocket_auth_token', {
|
|
70
76
|
map_id: this._umap.id,
|
|
71
77
|
})
|
|
72
78
|
|
|
73
79
|
const [response, _, error] = await this._umap.server.get(websocketTokenURI)
|
|
74
|
-
if (
|
|
75
|
-
this.
|
|
80
|
+
if (error) {
|
|
81
|
+
this.reconnect()
|
|
82
|
+
return
|
|
76
83
|
}
|
|
84
|
+
await this.start(response.token)
|
|
77
85
|
}
|
|
78
86
|
|
|
79
|
-
start(authToken) {
|
|
87
|
+
async start(authToken) {
|
|
80
88
|
const path = this._umap.urls.get('ws_sync', { map_id: this._umap.id })
|
|
81
89
|
const protocol = window.location.protocol === 'http:' ? 'ws:' : 'wss:'
|
|
82
|
-
this.transport = new WebSocketTransport(
|
|
90
|
+
this.transport = new WebSocketTransport(this)
|
|
91
|
+
await this.transport.connect(
|
|
83
92
|
`${protocol}//${window.location.host}${path}`,
|
|
84
93
|
authToken,
|
|
85
|
-
this,
|
|
86
94
|
this.peerId,
|
|
87
95
|
this._umap.properties.user?.name
|
|
88
96
|
)
|
|
97
|
+
this.onConnection()
|
|
89
98
|
}
|
|
90
99
|
|
|
91
100
|
stop() {
|
|
@@ -106,11 +115,11 @@ export class SyncEngine {
|
|
|
106
115
|
this.websocketConnected = false
|
|
107
116
|
this.updaters.map.update({ key: 'numberOfConnectedPeers' })
|
|
108
117
|
|
|
109
|
-
this._reconnectTimeout = setTimeout(() => {
|
|
118
|
+
this._reconnectTimeout = setTimeout(async () => {
|
|
110
119
|
if (this._reconnectDelay < MAX_RECONNECT_DELAY) {
|
|
111
120
|
this._reconnectDelay = this._reconnectDelay * RECONNECT_DELAY_FACTOR
|
|
112
121
|
}
|
|
113
|
-
this.authenticate()
|
|
122
|
+
await this.authenticate()
|
|
114
123
|
}, this._reconnectDelay)
|
|
115
124
|
}
|
|
116
125
|
upsert(subject, metadata, value) {
|
|
@@ -125,6 +134,16 @@ export class SyncEngine {
|
|
|
125
134
|
this._send({ verb: 'delete', subject, metadata, key })
|
|
126
135
|
}
|
|
127
136
|
|
|
137
|
+
saved() {
|
|
138
|
+
if (this.offline) return
|
|
139
|
+
if (this.transport) {
|
|
140
|
+
this.transport.send('SavedMessage', {
|
|
141
|
+
sender: this.peerId,
|
|
142
|
+
lastKnownHLC: this._operations.getLastKnownHLC(),
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
128
147
|
_send(inputMessage) {
|
|
129
148
|
const message = this._operations.addLocal(inputMessage)
|
|
130
149
|
|
|
@@ -168,6 +187,8 @@ export class SyncEngine {
|
|
|
168
187
|
} else if (payload.message.verb === 'ListOperationsResponse') {
|
|
169
188
|
this.onListOperationsResponse(payload)
|
|
170
189
|
}
|
|
190
|
+
} else if (kind === 'SavedMessage') {
|
|
191
|
+
this.onSavedMessage(payload)
|
|
171
192
|
} else {
|
|
172
193
|
throw new Error(`Received unknown message from the websocket server: ${kind}`)
|
|
173
194
|
}
|
|
@@ -182,6 +203,7 @@ export class SyncEngine {
|
|
|
182
203
|
*/
|
|
183
204
|
onOperationMessage(payload) {
|
|
184
205
|
if (payload.sender === this.peerId) return
|
|
206
|
+
debug('received operation', payload)
|
|
185
207
|
this._operations.storeRemoteOperations([payload])
|
|
186
208
|
this._applyOperation(payload)
|
|
187
209
|
}
|
|
@@ -245,7 +267,7 @@ export class SyncEngine {
|
|
|
245
267
|
* @param {*} operations The list of (encoded operations)
|
|
246
268
|
*/
|
|
247
269
|
onListOperationsResponse({ sender, message }) {
|
|
248
|
-
debug(`received operations from peer ${sender}`, message.operations)
|
|
270
|
+
debug(`received operations list from peer ${sender}`, message.operations)
|
|
249
271
|
|
|
250
272
|
if (message.operations.length === 0) return
|
|
251
273
|
|
|
@@ -280,6 +302,13 @@ export class SyncEngine {
|
|
|
280
302
|
// Else: apply
|
|
281
303
|
}
|
|
282
304
|
|
|
305
|
+
onSavedMessage({ sender, lastKnownHLC }) {
|
|
306
|
+
debug(`received saved message from peer ${sender}`, lastKnownHLC)
|
|
307
|
+
if (lastKnownHLC === this._operations.getLastKnownHLC() && SaveManager.isDirty) {
|
|
308
|
+
SaveManager.clear()
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
283
312
|
/**
|
|
284
313
|
* Send a message to another peer (via the transport layer)
|
|
285
314
|
*
|
|
@@ -350,7 +379,7 @@ export class Operations {
|
|
|
350
379
|
}
|
|
351
380
|
|
|
352
381
|
/**
|
|
353
|
-
* Tick the clock and
|
|
382
|
+
* Tick the clock and store the passed message in the operations list.
|
|
354
383
|
*
|
|
355
384
|
* @param {*} inputMessage
|
|
356
385
|
* @returns {*} clock-aware message
|
|
@@ -479,11 +508,7 @@ export class Operations {
|
|
|
479
508
|
* @return {bool} true if the two operations share the same context.
|
|
480
509
|
*/
|
|
481
510
|
static haveSameContext(local, remote) {
|
|
482
|
-
const shouldCheckKey =
|
|
483
|
-
local.hasOwnProperty('key') &&
|
|
484
|
-
remote.hasOwnProperty('key') &&
|
|
485
|
-
typeof local.key !== 'undefined' &&
|
|
486
|
-
typeof remote.key !== 'undefined'
|
|
511
|
+
const shouldCheckKey = local.key !== undefined && remote.key !== undefined
|
|
487
512
|
|
|
488
513
|
return (
|
|
489
514
|
Utils.deepEqual(local.subject, remote.subject) &&
|
|
@@ -54,10 +54,11 @@ export class MapUpdater extends BaseUpdater {
|
|
|
54
54
|
export class DataLayerUpdater extends BaseUpdater {
|
|
55
55
|
upsert({ value }) {
|
|
56
56
|
// Upsert only happens when a new datalayer is created.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
try {
|
|
58
|
+
this.getDataLayerFromID(value.id)
|
|
59
|
+
} catch {
|
|
60
|
+
this._umap.createDataLayer(value, false)
|
|
61
|
+
}
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
update({ key, metadata, value }) {
|
|
@@ -92,7 +93,7 @@ export class FeatureUpdater extends BaseUpdater {
|
|
|
92
93
|
upsert({ metadata, value }) {
|
|
93
94
|
const { id, layerId } = metadata
|
|
94
95
|
const datalayer = this.getDataLayerFromID(layerId)
|
|
95
|
-
const feature = this.getFeatureFromMetadata(metadata
|
|
96
|
+
const feature = this.getFeatureFromMetadata(metadata)
|
|
96
97
|
|
|
97
98
|
if (feature) {
|
|
98
99
|
feature.geometry = value.geometry
|
|
@@ -109,7 +110,7 @@ export class FeatureUpdater extends BaseUpdater {
|
|
|
109
110
|
return
|
|
110
111
|
}
|
|
111
112
|
if (key === 'geometry') {
|
|
112
|
-
const feature = this.getFeatureFromMetadata(metadata
|
|
113
|
+
const feature = this.getFeatureFromMetadata(metadata)
|
|
113
114
|
feature.geometry = value
|
|
114
115
|
} else {
|
|
115
116
|
this.updateObjectValue(feature, key, value)
|