umap-project 2.3.1__py3-none-any.whl → 2.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.

Potentially problematic release.


This version of umap-project might be problematic. Click here for more details.

Files changed (204) hide show
  1. umap/__init__.py +1 -1
  2. umap/locale/en/LC_MESSAGES/django.po +81 -31
  3. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  4. umap/locale/fr/LC_MESSAGES/django.po +117 -66
  5. umap/management/commands/run_websocket_server.py +23 -0
  6. umap/models.py +6 -1
  7. umap/settings/base.py +11 -3
  8. umap/static/umap/base.css +64 -184
  9. umap/static/umap/content.css +3 -2
  10. umap/static/umap/css/dialog.css +18 -0
  11. umap/static/umap/css/icon.css +8 -0
  12. umap/static/umap/css/importers.css +51 -0
  13. umap/static/umap/css/panel.css +18 -57
  14. umap/static/umap/css/tooltip.css +59 -0
  15. umap/static/umap/css/window.css +35 -0
  16. umap/static/umap/img/16-white.svg +1 -3
  17. umap/static/umap/img/alert-icon-error.svg +8 -0
  18. umap/static/umap/img/alert-icon-info.svg +4 -0
  19. umap/static/umap/img/alert-icon-success.svg +3 -0
  20. umap/static/umap/img/icon-external-link.svg +3 -0
  21. umap/static/umap/img/importers/communesfr.svg +5 -0
  22. umap/static/umap/img/importers/datasets.svg +13 -0
  23. umap/static/umap/img/importers/geodatamine.svg +10 -0
  24. umap/static/umap/img/importers/overpass.svg +7 -0
  25. umap/static/umap/img/importers/random.svg +18 -0
  26. umap/static/umap/img/importers/random1.svg +4 -0
  27. umap/static/umap/img/importers/random2.svg +4 -0
  28. umap/static/umap/img/source/16-white.svg +2 -4
  29. umap/static/umap/js/components/alerts/alert.css +160 -0
  30. umap/static/umap/js/components/alerts/alert.js +169 -0
  31. umap/static/umap/js/components/base.js +54 -0
  32. umap/static/umap/js/modules/autocomplete.js +347 -0
  33. umap/static/umap/js/modules/browser.js +6 -6
  34. umap/static/umap/js/modules/caption.js +5 -4
  35. umap/static/umap/js/modules/global.js +36 -12
  36. umap/static/umap/js/modules/help.js +255 -0
  37. umap/static/umap/js/modules/importer.js +308 -0
  38. umap/static/umap/js/modules/importers/communesfr.js +44 -0
  39. umap/static/umap/js/modules/importers/datasets.js +42 -0
  40. umap/static/umap/js/modules/importers/geodatamine.js +95 -0
  41. umap/static/umap/js/modules/importers/overpass.js +84 -0
  42. umap/static/umap/js/modules/request.js +12 -14
  43. umap/static/umap/js/modules/rules.js +241 -0
  44. umap/static/umap/js/modules/schema.js +63 -14
  45. umap/static/umap/js/modules/sync/engine.js +93 -0
  46. umap/static/umap/js/modules/sync/updaters.js +109 -0
  47. umap/static/umap/js/modules/sync/websocket.js +25 -0
  48. umap/static/umap/js/modules/ui/dialog.js +52 -0
  49. umap/static/umap/js/modules/{panel.js → ui/panel.js} +25 -14
  50. umap/static/umap/js/modules/ui/tooltip.js +116 -0
  51. umap/static/umap/js/modules/utils.js +25 -18
  52. umap/static/umap/js/umap.controls.js +13 -14
  53. umap/static/umap/js/umap.core.js +1 -324
  54. umap/static/umap/js/umap.features.js +77 -29
  55. umap/static/umap/js/umap.forms.js +9 -13
  56. umap/static/umap/js/umap.js +254 -215
  57. umap/static/umap/js/umap.layer.js +152 -74
  58. umap/static/umap/js/umap.permissions.js +5 -9
  59. umap/static/umap/js/umap.popup.js +1 -1
  60. umap/static/umap/js/umap.tableeditor.js +8 -8
  61. umap/static/umap/locale/am_ET.js +51 -16
  62. umap/static/umap/locale/am_ET.json +51 -16
  63. umap/static/umap/locale/ar.js +51 -16
  64. umap/static/umap/locale/ar.json +51 -16
  65. umap/static/umap/locale/ast.js +51 -16
  66. umap/static/umap/locale/ast.json +51 -16
  67. umap/static/umap/locale/bg.js +51 -16
  68. umap/static/umap/locale/bg.json +51 -16
  69. umap/static/umap/locale/br.js +55 -20
  70. umap/static/umap/locale/br.json +55 -20
  71. umap/static/umap/locale/ca.js +51 -16
  72. umap/static/umap/locale/ca.json +51 -16
  73. umap/static/umap/locale/cs_CZ.js +93 -58
  74. umap/static/umap/locale/cs_CZ.json +93 -58
  75. umap/static/umap/locale/da.js +51 -16
  76. umap/static/umap/locale/da.json +51 -16
  77. umap/static/umap/locale/de.js +56 -21
  78. umap/static/umap/locale/de.json +56 -21
  79. umap/static/umap/locale/el.js +51 -16
  80. umap/static/umap/locale/el.json +51 -16
  81. umap/static/umap/locale/en.js +52 -16
  82. umap/static/umap/locale/en.json +52 -16
  83. umap/static/umap/locale/en_US.json +51 -16
  84. umap/static/umap/locale/es.js +51 -16
  85. umap/static/umap/locale/es.json +51 -16
  86. umap/static/umap/locale/et.js +51 -16
  87. umap/static/umap/locale/et.json +51 -16
  88. umap/static/umap/locale/eu.js +51 -16
  89. umap/static/umap/locale/eu.json +51 -16
  90. umap/static/umap/locale/fa_IR.js +51 -16
  91. umap/static/umap/locale/fa_IR.json +51 -16
  92. umap/static/umap/locale/fi.js +51 -16
  93. umap/static/umap/locale/fi.json +51 -16
  94. umap/static/umap/locale/fr.js +61 -25
  95. umap/static/umap/locale/fr.json +61 -25
  96. umap/static/umap/locale/gl.js +51 -16
  97. umap/static/umap/locale/gl.json +51 -16
  98. umap/static/umap/locale/he.js +51 -16
  99. umap/static/umap/locale/he.json +51 -16
  100. umap/static/umap/locale/hr.js +51 -16
  101. umap/static/umap/locale/hr.json +51 -16
  102. umap/static/umap/locale/hu.js +51 -16
  103. umap/static/umap/locale/hu.json +51 -16
  104. umap/static/umap/locale/id.js +51 -16
  105. umap/static/umap/locale/id.json +51 -16
  106. umap/static/umap/locale/is.js +51 -16
  107. umap/static/umap/locale/is.json +51 -16
  108. umap/static/umap/locale/it.js +51 -16
  109. umap/static/umap/locale/it.json +51 -16
  110. umap/static/umap/locale/ja.js +51 -16
  111. umap/static/umap/locale/ja.json +51 -16
  112. umap/static/umap/locale/ko.js +51 -16
  113. umap/static/umap/locale/ko.json +51 -16
  114. umap/static/umap/locale/lt.js +51 -16
  115. umap/static/umap/locale/lt.json +51 -16
  116. umap/static/umap/locale/ms.js +51 -16
  117. umap/static/umap/locale/ms.json +51 -16
  118. umap/static/umap/locale/nl.js +51 -16
  119. umap/static/umap/locale/nl.json +51 -16
  120. umap/static/umap/locale/no.js +51 -16
  121. umap/static/umap/locale/no.json +51 -16
  122. umap/static/umap/locale/pl.js +93 -58
  123. umap/static/umap/locale/pl.json +93 -58
  124. umap/static/umap/locale/pl_PL.json +51 -16
  125. umap/static/umap/locale/pt.js +215 -180
  126. umap/static/umap/locale/pt.json +215 -180
  127. umap/static/umap/locale/pt_BR.js +51 -16
  128. umap/static/umap/locale/pt_BR.json +51 -16
  129. umap/static/umap/locale/pt_PT.js +51 -16
  130. umap/static/umap/locale/pt_PT.json +51 -16
  131. umap/static/umap/locale/ro.js +51 -16
  132. umap/static/umap/locale/ro.json +51 -16
  133. umap/static/umap/locale/ru.js +51 -16
  134. umap/static/umap/locale/ru.json +51 -16
  135. umap/static/umap/locale/si.js +51 -16
  136. umap/static/umap/locale/si.json +51 -16
  137. umap/static/umap/locale/sk_SK.js +51 -16
  138. umap/static/umap/locale/sk_SK.json +51 -16
  139. umap/static/umap/locale/sl.js +51 -16
  140. umap/static/umap/locale/sl.json +51 -16
  141. umap/static/umap/locale/sr.js +51 -16
  142. umap/static/umap/locale/sr.json +51 -16
  143. umap/static/umap/locale/sv.js +51 -16
  144. umap/static/umap/locale/sv.json +51 -16
  145. umap/static/umap/locale/th_TH.js +51 -16
  146. umap/static/umap/locale/th_TH.json +51 -16
  147. umap/static/umap/locale/tr.js +51 -16
  148. umap/static/umap/locale/tr.json +51 -16
  149. umap/static/umap/locale/uk_UA.js +51 -16
  150. umap/static/umap/locale/uk_UA.json +51 -16
  151. umap/static/umap/locale/vi.js +51 -16
  152. umap/static/umap/locale/vi.json +51 -16
  153. umap/static/umap/locale/vi_VN.json +51 -16
  154. umap/static/umap/locale/zh.js +51 -16
  155. umap/static/umap/locale/zh.json +51 -16
  156. umap/static/umap/locale/zh_CN.json +51 -16
  157. umap/static/umap/locale/zh_TW.Big5.json +51 -16
  158. umap/static/umap/locale/zh_TW.js +51 -16
  159. umap/static/umap/locale/zh_TW.json +51 -16
  160. umap/static/umap/map.css +40 -53
  161. umap/static/umap/unittests/sync.js +105 -0
  162. umap/static/umap/unittests/utils.js +78 -36
  163. umap/static/umap/vars.css +19 -1
  164. umap/static/umap/vendors/formbuilder/Leaflet.FormBuilder.js +2 -2
  165. umap/templates/umap/components/alerts/alert.html +89 -0
  166. umap/templates/umap/content.html +4 -3
  167. umap/templates/umap/css.html +4 -0
  168. umap/templates/umap/home.html +3 -0
  169. umap/templates/umap/js.html +0 -3
  170. umap/templates/umap/map_init.html +2 -8
  171. umap/templates/umap/messages.html +9 -11
  172. umap/templates/umap/search.html +3 -0
  173. umap/tests/base.py +2 -0
  174. umap/tests/integration/conftest.py +30 -0
  175. umap/tests/integration/test_anonymous_owned_map.py +8 -13
  176. umap/tests/integration/test_browser.py +77 -4
  177. umap/tests/integration/test_conditional_rules.py +201 -0
  178. umap/tests/integration/test_dashboard.py +1 -1
  179. umap/tests/integration/test_datalayer.py +2 -3
  180. umap/tests/integration/test_edit_datalayer.py +4 -4
  181. umap/tests/integration/test_edit_map.py +1 -1
  182. umap/tests/integration/test_facets_browser.py +3 -3
  183. umap/tests/integration/test_import.py +185 -49
  184. umap/tests/integration/test_map.py +31 -2
  185. umap/tests/integration/{test_collaborative_editing.py → test_optimistic_merge.py} +7 -7
  186. umap/tests/integration/test_owned_map.py +1 -1
  187. umap/tests/integration/test_picto.py +2 -2
  188. umap/tests/integration/test_statics.py +1 -1
  189. umap/tests/integration/test_view_marker.py +2 -2
  190. umap/tests/integration/test_websocket_sync.py +283 -0
  191. umap/tests/settings.py +5 -0
  192. umap/tests/test_datalayer_views.py +0 -1
  193. umap/tests/test_views.py +53 -0
  194. umap/urls.py +5 -0
  195. umap/views.py +40 -11
  196. umap/websocket_server.py +92 -0
  197. {umap_project-2.3.1.dist-info → umap_project-2.4.0.dist-info}/METADATA +10 -8
  198. {umap_project-2.3.1.dist-info → umap_project-2.4.0.dist-info}/RECORD +201 -167
  199. umap/static/umap/js/umap.autocomplete.js +0 -341
  200. umap/static/umap/js/umap.importer.js +0 -187
  201. umap/static/umap/js/umap.ui.js +0 -190
  202. {umap_project-2.3.1.dist-info → umap_project-2.4.0.dist-info}/WHEEL +0 -0
  203. {umap_project-2.3.1.dist-info → umap_project-2.4.0.dist-info}/entry_points.txt +0 -0
  204. {umap_project-2.3.1.dist-info → umap_project-2.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -139,7 +139,7 @@ L.DomUtil.createButtonIcon = (parent, className, title, size = 16) => {
139
139
 
140
140
  L.DomUtil.createTitle = (parent, text, className, tag = 'h3') => {
141
141
  const title = L.DomUtil.create(tag, '', parent)
142
- L.DomUtil.createIcon(title, className)
142
+ if (className) L.DomUtil.createIcon(title, className)
143
143
  L.DomUtil.add('span', '', title, text)
144
144
  return title
145
145
  }
@@ -245,329 +245,6 @@ L.DomEvent.once = (el, types, fn, context) => {
245
245
  return L.DomEvent.on(el, types, fn, context).on(el, types, handler, context)
246
246
  }
247
247
 
248
- /*
249
- * Global events
250
- */
251
- U.Keys = {
252
- LEFT: 37,
253
- UP: 38,
254
- RIGHT: 39,
255
- DOWN: 40,
256
- TAB: 9,
257
- ENTER: 13,
258
- ESC: 27,
259
- APPLE: 91,
260
- SHIFT: 16,
261
- ALT: 17,
262
- CTRL: 18,
263
- E: 69,
264
- F: 70,
265
- H: 72,
266
- I: 73,
267
- L: 76,
268
- M: 77,
269
- O: 79,
270
- P: 80,
271
- S: 83,
272
- Z: 90,
273
- }
274
-
275
- U.Help = L.Class.extend({
276
- SHORTCUTS: {
277
- DRAW_MARKER: {
278
- shortcut: 'Modifier+M',
279
- label: L._('Draw a marker'),
280
- },
281
- DRAW_LINE: {
282
- shortcut: 'Modifier+L',
283
- label: L._('Draw a polyline'),
284
- },
285
- DRAW_POLYGON: {
286
- shortcut: 'Modifier+P',
287
- label: L._('Draw a polygon'),
288
- },
289
- TOGGLE_EDIT: {
290
- shortcut: 'Modifier+E',
291
- label: L._('Toggle edit mode'),
292
- },
293
- STOP_EDIT: {
294
- shortcut: 'Modifier+E',
295
- label: L._('Stop editing'),
296
- },
297
- SAVE_MAP: {
298
- shortcut: 'Modifier+S',
299
- label: L._('Save map'),
300
- },
301
- IMPORT_PANEL: {
302
- shortcut: 'Modifier+I',
303
- label: L._('Import data'),
304
- },
305
- SEARCH: {
306
- shortcut: 'Modifier+F',
307
- label: L._('Search location'),
308
- },
309
- CANCEL: {
310
- shortcut: 'Modifier+Z',
311
- label: L._('Cancel edits'),
312
- },
313
- PREVIEW: {
314
- shortcut: 'Modifier+E',
315
- label: L._('Back to preview'),
316
- },
317
- SAVE: {
318
- shortcut: 'Modifier+S',
319
- label: L._('Save current edits'),
320
- },
321
- EDIT_FEATURE_LAYER: {
322
- shortcut: 'Modifier+⇧+Click',
323
- label: L._("Edit feature's layer"),
324
- },
325
- CONTINUE_LINE: {
326
- shortcut: 'Modifier+Click',
327
- label: L._('Continue line'),
328
- },
329
- },
330
-
331
- displayLabel: function (action, withKbdTag = true) {
332
- let { shortcut, label } = this.SHORTCUTS[action]
333
- const modifier = this.isMacOS ? 'Cmd' : 'Ctrl'
334
- shortcut = shortcut.replace('Modifier', modifier)
335
- if (withKbdTag) {
336
- shortcut = shortcut
337
- .split('+')
338
- .map((el) => `<kbd>${el}</kbd>`)
339
- .join('+')
340
- label += ` ${shortcut}`
341
- } else {
342
- label += ` (${shortcut})`
343
- }
344
- return label
345
- },
346
-
347
- initialize: function (map) {
348
- this.map = map
349
- this.box = L.DomUtil.create(
350
- 'div',
351
- 'umap-help-box with-transition dark',
352
- document.body
353
- )
354
- const closeButton = L.DomUtil.createButton(
355
- 'umap-close-link',
356
- this.box,
357
- '',
358
- this.hide,
359
- this
360
- )
361
- L.DomUtil.add('i', 'umap-close-icon', closeButton)
362
- const label = L.DomUtil.create('span', '', closeButton)
363
- label.title = label.textContent = L._('Close')
364
- this.content = L.DomUtil.create('div', 'umap-help-content', this.box)
365
- this.isMacOS = /mac/i.test(
366
- // eslint-disable-next-line compat/compat -- Fallback available.
367
- navigator.userAgentData ? navigator.userAgentData.platform : navigator.platform
368
- )
369
- },
370
-
371
- onKeyDown: function (e) {
372
- const key = e.keyCode,
373
- ESC = 27
374
- if (key === ESC) {
375
- this.hide()
376
- }
377
- },
378
-
379
- show: function () {
380
- this.content.innerHTML = ''
381
- for (let i = 0, name; i < arguments.length; i++) {
382
- name = arguments[i]
383
- L.DomUtil.add('div', 'umap-help-entry', this.content, this.resolve(name))
384
- }
385
- L.DomUtil.addClass(document.body, 'umap-help-on')
386
- },
387
-
388
- hide: function () {
389
- L.DomUtil.removeClass(document.body, 'umap-help-on')
390
- },
391
-
392
- visible: function () {
393
- return L.DomUtil.hasClass(document.body, 'umap-help-on')
394
- },
395
-
396
- resolve: function (name) {
397
- return typeof this[name] === 'function' ? this[name]() : this[name]
398
- },
399
-
400
- button: function (container, entries, classname) {
401
- const helpButton = L.DomUtil.createButton(
402
- classname || 'umap-help-button',
403
- container,
404
- L._('Help')
405
- )
406
- if (entries) {
407
- L.DomEvent.on(helpButton, 'click', L.DomEvent.stop).on(
408
- helpButton,
409
- 'click',
410
- function (e) {
411
- const args = typeof entries === 'string' ? [entries] : entries
412
- this.show.apply(this, args)
413
- },
414
- this
415
- )
416
- }
417
- return helpButton
418
- },
419
-
420
- link: function (container, entries) {
421
- const helpButton = this.button(container, entries, 'umap-help-link')
422
- helpButton.textContent = L._('Help')
423
- return helpButton
424
- },
425
-
426
- edit: function () {
427
- const container = L.DomUtil.create('div', ''),
428
- self = this,
429
- title = L.DomUtil.create('h3', '', container),
430
- actionsContainer = L.DomUtil.create('ul', 'umap-edit-actions', container)
431
- const addAction = (action) => {
432
- const actionContainer = L.DomUtil.add('li', '', actionsContainer)
433
- L.DomUtil.add('i', action.options.className, actionContainer),
434
- L.DomUtil.add('span', '', actionContainer, action.options.tooltip)
435
- L.DomEvent.on(actionContainer, 'click', action.addHooks, action)
436
- L.DomEvent.on(actionContainer, 'click', self.hide, self)
437
- }
438
- title.textContent = L._('Where do we go from here?')
439
- for (const id in this.map.helpMenuActions) {
440
- addAction(this.map.helpMenuActions[id])
441
- }
442
- return container
443
- },
444
-
445
- importFormats: function () {
446
- const container = L.DomUtil.create('div')
447
- L.DomUtil.add('h3', '', container, 'GeojSON')
448
- L.DomUtil.add('p', '', container, L._('All properties are imported.'))
449
- L.DomUtil.add('h3', '', container, 'GPX')
450
- L.DomUtil.add('p', '', container, `${L._('Properties imported:')}name, desc`)
451
- L.DomUtil.add('h3', '', container, 'KML')
452
- L.DomUtil.add('p', '', container, `${L._('Properties imported:')}name, description`)
453
- L.DomUtil.add('h3', '', container, 'CSV')
454
- L.DomUtil.add(
455
- 'p',
456
- '',
457
- container,
458
- L._(
459
- 'Comma, tab or semi-colon separated values. SRS WGS84 is implied. Only Point geometries are imported. The import will look at the column headers for any mention of «lat» and «lon» at the begining of the header, case insensitive. All other column are imported as properties.'
460
- )
461
- )
462
- L.DomUtil.add('h3', '', container, 'uMap')
463
- L.DomUtil.add(
464
- 'p',
465
- '',
466
- container,
467
- L._('Imports all umap data, including layers and settings.')
468
- )
469
- return container
470
- },
471
-
472
- textFormatting: function () {
473
- const container = L.DomUtil.create('div'),
474
- title = L.DomUtil.add('h3', '', container, L._('Text formatting')),
475
- elements = L.DomUtil.create('ul', '', container)
476
- L.DomUtil.add('li', '', elements, L._('*single star for italic*'))
477
- L.DomUtil.add('li', '', elements, L._('**double star for bold**'))
478
- L.DomUtil.add('li', '', elements, L._('# one hash for main heading'))
479
- L.DomUtil.add('li', '', elements, L._('## two hashes for second heading'))
480
- L.DomUtil.add('li', '', elements, L._('### three hashes for third heading'))
481
- L.DomUtil.add('li', '', elements, L._('Simple link: [[http://example.com]]'))
482
- L.DomUtil.add(
483
- 'li',
484
- '',
485
- elements,
486
- L._('Link with text: [[http://example.com|text of the link]]')
487
- )
488
- L.DomUtil.add('li', '', elements, L._('Image: {{http://image.url.com}}'))
489
- L.DomUtil.add(
490
- 'li',
491
- '',
492
- elements,
493
- L._('Image with custom width (in px): {{http://image.url.com|width}}')
494
- )
495
- L.DomUtil.add('li', '', elements, L._('Iframe: {{{http://iframe.url.com}}}'))
496
- L.DomUtil.add(
497
- 'li',
498
- '',
499
- elements,
500
- L._('Iframe with custom height (in px): {{{http://iframe.url.com|height}}}')
501
- )
502
- L.DomUtil.add(
503
- 'li',
504
- '',
505
- elements,
506
- L._(
507
- 'Iframe with custom height and width (in px): {{{http://iframe.url.com|height*width}}}'
508
- )
509
- )
510
- L.DomUtil.add('li', '', elements, L._('--- for a horizontal rule'))
511
- return container
512
- },
513
-
514
- dynamicProperties: function () {
515
- const container = L.DomUtil.create('div')
516
- L.DomUtil.add('h3', '', container, L._('Dynamic properties'))
517
- L.DomUtil.add(
518
- 'p',
519
- '',
520
- container,
521
- L._(
522
- 'Use placeholders with feature properties between brackets, eg. &#123;name&#125;, they will be dynamically replaced by the corresponding values.'
523
- )
524
- )
525
- return container
526
- },
527
-
528
- formatURL: `${L._(
529
- 'Supported variables that will be dynamically replaced'
530
- )}: {bbox}, {lat}, {lng}, {zoom}, {east}, {north}..., {left}, {top}..., locale, lang`,
531
- colorValue: L._('Must be a valid CSS value (eg.: DarkBlue or #123456)'),
532
- smoothFactor: L._(
533
- 'How much to simplify the polyline on each zoom level (more = better performance and smoother look, less = more accurate)'
534
- ),
535
- dashArray: L._(
536
- 'A comma separated list of numbers that defines the stroke dash pattern. Ex.: "5, 10, 15".'
537
- ),
538
- zoomTo: L._('Zoom level for automatic zooms'),
539
- labelKey: L._(
540
- 'The name of the property to use as feature label (eg.: "nom"). You can also use properties inside brackets to use more than one or mix with static content (eg.: "&lcub;name&rcub; in &lcub;place&rcub;")'
541
- ),
542
- stroke: L._('Whether to display or not polygons paths.'),
543
- fill: L._('Whether to fill polygons with color.'),
544
- fillColor: L._('Optional. Same as color if not set.'),
545
- shortCredit: L._('Will be displayed in the bottom right corner of the map'),
546
- longCredit: L._('Will be visible in the caption of the map'),
547
- permanentCredit: L._(
548
- 'Will be permanently visible in the bottom left corner of the map'
549
- ),
550
- sortKey: L._(
551
- 'Comma separated list of properties to use for sorting features. To reverse the sort, put a minus sign (-) before. Eg. mykey,-otherkey.'
552
- ),
553
- slugKey: L._('The name of the property to use as feature unique identifier.'),
554
- filterKey: L._(
555
- 'Comma separated list of properties to use when filtering features by text input'
556
- ),
557
- facetKey: L._(
558
- 'Comma separated list of properties to use for filters (eg.: mykey,otherkey). To control label, add it after a | (eg.: mykey|My Key,otherkey|Other Key). To control input field type, add it after another | (eg.: mykey|My Key|checkbox,otherkey|Other Key|datetime). Allowed values for the input field type are checkbox (default), radio, number, date and datetime.'
559
- ),
560
- interactive: L._(
561
- 'If false, the polygon or line will act as a part of the underlying map.'
562
- ),
563
- outlink: L._('Define link to open in a new window on polygon click.'),
564
- dynamicRemoteData: L._('Fetch data each time map view changes.'),
565
- proxyRemoteData: L._("To use if remote server doesn't allow cross domain (slower)"),
566
- browsable: L._(
567
- 'Set it to false to hide this layer from the slideshow, the data browser, the popup navigation…'
568
- ),
569
- })
570
-
571
248
  L.LatLng.prototype.isValid = function () {
572
249
  return (
573
250
  isFinite(this.lat) &&
@@ -1,25 +1,61 @@
1
1
  U.FeatureMixin = {
2
2
  staticOptions: { mainColor: 'color' },
3
3
 
4
- initialize: function (map, latlng, options) {
4
+ getSyncMetadata: function () {
5
+ return {
6
+ subject: 'feature',
7
+ metadata: {
8
+ id: this.id,
9
+ layerId: this.datalayer?.id || null,
10
+ featureType: this.getClassName(),
11
+ },
12
+ }
13
+ },
14
+
15
+ onCommit: function () {
16
+ // When the layer is a remote layer, we don't want to sync the creation of the
17
+ // points via the websocket, as the other peers will get them themselves.
18
+ if (this.datalayer.isRemoteLayer()) return
19
+ this.sync.upsert(this.toGeoJSON())
20
+ },
21
+
22
+ getGeometry: function () {
23
+ return this.toGeoJSON().geometry
24
+ },
25
+
26
+ syncDelete: function () {
27
+ this.sync.delete()
28
+ },
29
+
30
+ initialize: function (map, latlng, options, id) {
5
31
  this.map = map
32
+ this.sync = map.sync_engine.proxy(this)
33
+
6
34
  if (typeof options === 'undefined') {
7
35
  options = {}
8
36
  }
9
37
  // DataLayer the marker belongs to
10
38
  this.datalayer = options.datalayer || null
11
39
  this.properties = { _umap_options: {} }
12
- let geojson_id
40
+
13
41
  if (options.geojson) {
14
42
  this.populate(options.geojson)
15
- geojson_id = options.geojson.id
16
43
  }
17
44
 
18
- // Each feature needs an unique identifier
19
- if (U.Utils.checkId(geojson_id)) {
20
- this.id = geojson_id
45
+ if (id) {
46
+ this.id = id
21
47
  } else {
22
- this.id = U.Utils.generateId()
48
+ let geojson_id
49
+ if (options.geojson) {
50
+ geojson_id = options.geojson.id
51
+ }
52
+
53
+ // Each feature needs an unique identifier
54
+ if (U.Utils.checkId(geojson_id)) {
55
+ this.id = geojson_id
56
+ } else {
57
+ this.id = U.Utils.generateId()
58
+ }
23
59
  }
24
60
  let isDirty = false
25
61
  const self = this
@@ -98,6 +134,7 @@ U.FeatureMixin = {
98
134
  this.view()
99
135
  }
100
136
  }
137
+ this._redraw()
101
138
  },
102
139
 
103
140
  openPopup: function () {
@@ -107,7 +144,11 @@ U.FeatureMixin = {
107
144
  edit: function (e) {
108
145
  if (!this.map.editEnabled || this.isReadOnly()) return
109
146
  const container = L.DomUtil.create('div', 'umap-feature-container')
110
- L.DomUtil.createTitle(container, L._('Feature properties'), this.getClassName())
147
+ L.DomUtil.createTitle(
148
+ container,
149
+ L._('Feature properties'),
150
+ `icon-${this.getClassName()}`
151
+ )
111
152
 
112
153
  let builder = new U.FormBuilder(
113
154
  this,
@@ -134,7 +175,6 @@ U.FeatureMixin = {
134
175
  properties.unshift('properties.name')
135
176
  builder = new U.FormBuilder(this, properties, {
136
177
  id: 'umap-feature-properties',
137
- callback: this._redraw, // In case we have dynamic options…
138
178
  })
139
179
  container.appendChild(builder.build())
140
180
  this.appendEditFieldsets(container)
@@ -149,7 +189,7 @@ U.FeatureMixin = {
149
189
  },
150
190
 
151
191
  getAdvancedEditActions: function (container) {
152
- const deleteButton = L.DomUtil.createButton(
192
+ L.DomUtil.createButton(
153
193
  'button umap-delete',
154
194
  container,
155
195
  L._('Delete'),
@@ -165,7 +205,6 @@ U.FeatureMixin = {
165
205
  const optionsFields = this.getShapeOptions()
166
206
  let builder = new U.FormBuilder(this, optionsFields, {
167
207
  id: 'umap-feature-shape-properties',
168
- callback: this._redraw,
169
208
  })
170
209
  const shapeProperties = L.DomUtil.createFieldset(container, L._('Shape properties'))
171
210
  shapeProperties.appendChild(builder.build())
@@ -173,7 +212,6 @@ U.FeatureMixin = {
173
212
  const advancedOptions = this.getAdvancedOptions()
174
213
  builder = new U.FormBuilder(this, advancedOptions, {
175
214
  id: 'umap-feature-advanced-properties',
176
- callback: this._redraw,
177
215
  })
178
216
  const advancedProperties = L.DomUtil.createFieldset(
179
217
  container,
@@ -182,9 +220,7 @@ U.FeatureMixin = {
182
220
  advancedProperties.appendChild(builder.build())
183
221
 
184
222
  const interactionOptions = this.getInteractionOptions()
185
- builder = new U.FormBuilder(this, interactionOptions, {
186
- callback: this._redraw,
187
- })
223
+ builder = new U.FormBuilder(this, interactionOptions)
188
224
  const popupFieldset = L.DomUtil.createFieldset(
189
225
  container,
190
226
  L._('Interaction options')
@@ -240,13 +276,14 @@ U.FeatureMixin = {
240
276
  }
241
277
  return false
242
278
  },
243
-
244
- del: function () {
279
+ del: function (sync) {
245
280
  this.isDirty = true
246
281
  this.map.closePopup()
247
282
  if (this.datalayer) {
248
283
  this.datalayer.removeLayer(this)
249
284
  this.disconnectFromDataLayer(this.datalayer)
285
+
286
+ if (sync !== false) this.syncDelete()
250
287
  }
251
288
  },
252
289
 
@@ -495,7 +532,7 @@ U.FeatureMixin = {
495
532
  },
496
533
 
497
534
  isFiltered: function () {
498
- const filterKeys = this.map.getFilterKeys()
535
+ const filterKeys = this.datalayer.getFilterKeys()
499
536
  const filter = this.map.browser.options.filter
500
537
  if (filter && !this.matchFilter(filter, filterKeys)) return true
501
538
  if (!this.matchFacets()) return true
@@ -504,6 +541,10 @@ U.FeatureMixin = {
504
541
 
505
542
  matchFilter: function (filter, keys) {
506
543
  filter = filter.toLowerCase()
544
+ if (U.Utils.hasVar(keys)) {
545
+ return this.getDisplayName().toLowerCase().indexOf(filter) !== -1
546
+ }
547
+ keys = keys.split(',')
507
548
  for (let i = 0, value; i < keys.length; i++) {
508
549
  value = (this.properties[keys[i]] || '') + ''
509
550
  if (value.toLowerCase().indexOf(filter) !== -1) return true
@@ -549,7 +590,10 @@ U.FeatureMixin = {
549
590
  },
550
591
 
551
592
  clone: function () {
552
- const layer = this.datalayer.geojsonToFeatures(this.toGeoJSON())
593
+ const geoJSON = this.toGeoJSON()
594
+ delete geoJSON.id
595
+ delete geoJSON.properties.id
596
+ const layer = this.datalayer.geojsonToFeatures(geoJSON)
553
597
  layer.isDirty = true
554
598
  layer.edit()
555
599
  return layer
@@ -562,7 +606,7 @@ U.FeatureMixin = {
562
606
  if (locale) properties.locale = locale
563
607
  if (L.lang) properties.lang = L.lang
564
608
  properties.rank = this.getRank() + 1
565
- if (this.hasGeom()) {
609
+ if (this._map && this.hasGeom()) {
566
610
  center = this.getCenter()
567
611
  properties.lat = center.lat
568
612
  properties.lon = center.lng
@@ -602,9 +646,11 @@ U.Marker = L.Marker.extend({
602
646
  function (e) {
603
647
  this.isDirty = true
604
648
  this.edit(e)
649
+ this.sync.update('geometry', this.getGeometry())
605
650
  },
606
651
  this
607
652
  )
653
+ this.on('editable:drawing:commit', this.onCommit)
608
654
  if (!this.isReadOnly()) this.on('mouseover', this._enableDragging)
609
655
  this.on('mouseout', this._onMouseOut)
610
656
  this._popupHandlersAdded = true // prevent Leaflet from binding event on bindPopup
@@ -726,14 +772,10 @@ U.Marker = L.Marker.extend({
726
772
  const builder = new U.FormBuilder(this, coordinatesOptions, {
727
773
  callback: function () {
728
774
  if (!this._latlng.isValid()) {
729
- this.map.ui.alert({
730
- content: L._('Invalid latitude or longitude'),
731
- level: 'error',
732
- })
775
+ U.Alert.error(L._('Invalid latitude or longitude'))
733
776
  builder.resetField('_latlng.lat')
734
777
  builder.resetField('_latlng.lng')
735
778
  }
736
- this._redraw()
737
779
  this.zoomTo({ easing: false })
738
780
  },
739
781
  callbackContext: this,
@@ -878,14 +920,15 @@ U.PathMixin = {
878
920
 
879
921
  _onMouseOver: function () {
880
922
  if (this.map.measureTools && this.map.measureTools.enabled()) {
881
- this.map.ui.tooltip({ content: this.getMeasure(), anchor: this })
923
+ this.map.tooltip.open({ content: this.getMeasure(), anchor: this })
882
924
  } else if (this.map.editEnabled && !this.map.editedFeature) {
883
- this.map.ui.tooltip({ content: L._('Click to edit'), anchor: this })
925
+ this.map.tooltip.open({ content: L._('Click to edit'), anchor: this })
884
926
  }
885
927
  },
886
928
 
887
929
  addInteractions: function () {
888
930
  U.FeatureMixin.addInteractions.call(this)
931
+ this.on('editable:disable', this.onCommit)
889
932
  this.on('mouseover', this._onMouseOver)
890
933
  this.on('edit', this.makeDirty)
891
934
  this.on('drag editable:drag', this._onDrag)
@@ -928,7 +971,7 @@ U.PathMixin = {
928
971
  items.push({
929
972
  text: L._('Display measure'),
930
973
  callback: function () {
931
- this.map.ui.alert({ content: this.getMeasure(), level: 'info' })
974
+ U.Alert.info(this.getMeasure())
932
975
  },
933
976
  context: this,
934
977
  })
@@ -1086,6 +1129,9 @@ U.Polyline = L.Polyline.extend({
1086
1129
  geojson.geometry.coordinates = [
1087
1130
  U.Utils.flattenCoordinates(geojson.geometry.coordinates),
1088
1131
  ]
1132
+
1133
+ delete geojson.id // delete the copied id, a new one will be generated.
1134
+
1089
1135
  const polygon = this.datalayer.geojsonToFeatures(geojson)
1090
1136
  polygon.edit()
1091
1137
  this.del()
@@ -1093,7 +1139,7 @@ U.Polyline = L.Polyline.extend({
1093
1139
 
1094
1140
  getAdvancedEditActions: function (container) {
1095
1141
  U.FeatureMixin.getAdvancedEditActions.call(this, container)
1096
- const toPolygon = L.DomUtil.createButton(
1142
+ L.DomUtil.createButton(
1097
1143
  'button umap-to-polygon',
1098
1144
  container,
1099
1145
  L._('Transform to polygon'),
@@ -1223,6 +1269,8 @@ U.Polygon = L.Polygon.extend({
1223
1269
 
1224
1270
  toPolyline: function () {
1225
1271
  const geojson = this.toGeoJSON()
1272
+ delete geojson.id
1273
+ delete geojson.properties.id
1226
1274
  geojson.geometry.type = 'LineString'
1227
1275
  geojson.geometry.coordinates = U.Utils.flattenCoordinates(
1228
1276
  geojson.geometry.coordinates
@@ -78,7 +78,7 @@ L.FormBuilder.Element.include({
78
78
  info,
79
79
  'mouseover',
80
80
  function () {
81
- this.builder.map.ui.tooltip({
81
+ this.builder.map.tooltip.open({
82
82
  anchor: info,
83
83
  content: this.options.helpTooltip,
84
84
  position: 'top',
@@ -340,15 +340,6 @@ L.FormBuilder.TextColorPicker = L.FormBuilder.ColorPicker.extend({
340
340
  ],
341
341
  })
342
342
 
343
- L.FormBuilder.ProxyTTLSelect = L.FormBuilder.Select.extend({
344
- selectOptions: [
345
- [undefined, L._('No cache')],
346
- ['300', L._('5 min')],
347
- ['3600', L._('1 hour')],
348
- ['86400', L._('1 day')],
349
- ],
350
- })
351
-
352
343
  L.FormBuilder.LayerTypeChooser = L.FormBuilder.Select.extend({
353
344
  getOptions: function () {
354
345
  const layer_classes = [
@@ -1067,7 +1058,7 @@ L.FormBuilder.ManageOwner = L.FormBuilder.Element.extend({
1067
1058
  className: 'edit-owner',
1068
1059
  on_select: L.bind(this.onSelect, this),
1069
1060
  }
1070
- this.autocomplete = new U.AutoComplete.Ajax.Select(this.parentNode, options)
1061
+ this.autocomplete = new U.AjaxAutocomplete(this.parentNode, options)
1071
1062
  const owner = this.toHTML()
1072
1063
  if (owner)
1073
1064
  this.autocomplete.displaySelected({
@@ -1096,7 +1087,7 @@ L.FormBuilder.ManageEditors = L.FormBuilder.Element.extend({
1096
1087
  on_select: L.bind(this.onSelect, this),
1097
1088
  on_unselect: L.bind(this.onUnselect, this),
1098
1089
  }
1099
- this.autocomplete = new U.AutoComplete.Ajax.SelectMultiple(this.parentNode, options)
1090
+ this.autocomplete = new U.AjaxAutocompleteMultiple(this.parentNode, options)
1100
1091
  this._values = this.toHTML()
1101
1092
  if (this._values)
1102
1093
  for (let i = 0; i < this._values.length; i++)
@@ -1185,7 +1176,12 @@ U.FormBuilder = L.FormBuilder.extend({
1185
1176
  setter: function (field, value) {
1186
1177
  L.FormBuilder.prototype.setter.call(this, field, value)
1187
1178
  this.obj.isDirty = true
1188
- if ('render' in this.obj) this.obj.render([field], this)
1179
+ if ('render' in this.obj) {
1180
+ this.obj.render([field], this)
1181
+ }
1182
+ if ('sync' in this.obj) {
1183
+ this.obj.sync.update(field, value)
1184
+ }
1189
1185
  },
1190
1186
 
1191
1187
  finish: function () {