umap-project 2.3.1__py3-none-any.whl → 2.4.0b0__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.
Files changed (210) hide show
  1. umap/.DS_Store +0 -0
  2. umap/__init__.py +1 -1
  3. umap/locale/en/LC_MESSAGES/django.po +81 -31
  4. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  5. umap/locale/fr/LC_MESSAGES/django.po +109 -59
  6. umap/management/commands/run_websocket_server.py +23 -0
  7. umap/models.py +6 -1
  8. umap/settings/base.py +11 -3
  9. umap/static/.DS_Store +0 -0
  10. umap/static/umap/.DS_Store +0 -0
  11. umap/static/umap/base.css +53 -162
  12. umap/static/umap/content.css +3 -2
  13. umap/static/umap/css/dialog.css +18 -0
  14. umap/static/umap/css/icon.css +8 -0
  15. umap/static/umap/css/importers.css +44 -0
  16. umap/static/umap/css/panel.css +19 -57
  17. umap/static/umap/css/tooltip.css +59 -0
  18. umap/static/umap/css/window.css +35 -0
  19. umap/static/umap/favicons/.DS_Store +0 -0
  20. umap/static/umap/fonts/.DS_Store +0 -0
  21. umap/static/umap/img/.DS_Store +0 -0
  22. umap/static/umap/img/alert-icon-error.svg +8 -0
  23. umap/static/umap/img/alert-icon-info.svg +4 -0
  24. umap/static/umap/img/alert-icon-success.svg +3 -0
  25. umap/static/umap/img/icon-external-link.svg +3 -0
  26. umap/static/umap/img/importers/communesfr.svg +5 -0
  27. umap/static/umap/img/importers/datasets.svg +13 -0
  28. umap/static/umap/img/importers/geodatamine.svg +10 -0
  29. umap/static/umap/img/importers/overpass.svg +7 -0
  30. umap/static/umap/img/importers/random.svg +18 -0
  31. umap/static/umap/img/importers/random1.svg +4 -0
  32. umap/static/umap/img/importers/random2.svg +4 -0
  33. umap/static/umap/img/source/.DS_Store +0 -0
  34. umap/static/umap/js/components/alerts/alert.css +160 -0
  35. umap/static/umap/js/components/alerts/alert.js +169 -0
  36. umap/static/umap/js/components/base.js +54 -0
  37. umap/static/umap/js/modules/autocomplete.js +347 -0
  38. umap/static/umap/js/modules/browser.js +1 -1
  39. umap/static/umap/js/modules/caption.js +4 -3
  40. umap/static/umap/js/modules/global.js +36 -12
  41. umap/static/umap/js/modules/help.js +255 -0
  42. umap/static/umap/js/modules/importer.js +280 -0
  43. umap/static/umap/js/modules/importers/communesfr.js +44 -0
  44. umap/static/umap/js/modules/importers/datasets.js +41 -0
  45. umap/static/umap/js/modules/importers/geodatamine.js +95 -0
  46. umap/static/umap/js/modules/importers/overpass.js +84 -0
  47. umap/static/umap/js/modules/request.js +12 -14
  48. umap/static/umap/js/modules/rules.js +241 -0
  49. umap/static/umap/js/modules/schema.js +63 -14
  50. umap/static/umap/js/modules/sync/engine.js +93 -0
  51. umap/static/umap/js/modules/sync/updaters.js +109 -0
  52. umap/static/umap/js/modules/sync/websocket.js +25 -0
  53. umap/static/umap/js/modules/ui/dialog.js +52 -0
  54. umap/static/umap/js/modules/{panel.js → ui/panel.js} +25 -14
  55. umap/static/umap/js/modules/ui/tooltip.js +116 -0
  56. umap/static/umap/js/modules/utils.js +25 -18
  57. umap/static/umap/js/umap.controls.js +13 -14
  58. umap/static/umap/js/umap.core.js +1 -324
  59. umap/static/umap/js/umap.features.js +67 -27
  60. umap/static/umap/js/umap.forms.js +9 -13
  61. umap/static/umap/js/umap.js +220 -180
  62. umap/static/umap/js/umap.layer.js +142 -74
  63. umap/static/umap/js/umap.permissions.js +5 -9
  64. umap/static/umap/js/umap.tableeditor.js +8 -8
  65. umap/static/umap/locale/am_ET.js +51 -16
  66. umap/static/umap/locale/am_ET.json +51 -16
  67. umap/static/umap/locale/ar.js +51 -16
  68. umap/static/umap/locale/ar.json +51 -16
  69. umap/static/umap/locale/ast.js +51 -16
  70. umap/static/umap/locale/ast.json +51 -16
  71. umap/static/umap/locale/bg.js +51 -16
  72. umap/static/umap/locale/bg.json +51 -16
  73. umap/static/umap/locale/br.js +55 -20
  74. umap/static/umap/locale/br.json +55 -20
  75. umap/static/umap/locale/ca.js +51 -16
  76. umap/static/umap/locale/ca.json +51 -16
  77. umap/static/umap/locale/cs_CZ.js +93 -58
  78. umap/static/umap/locale/cs_CZ.json +93 -58
  79. umap/static/umap/locale/da.js +51 -16
  80. umap/static/umap/locale/da.json +51 -16
  81. umap/static/umap/locale/de.js +56 -21
  82. umap/static/umap/locale/de.json +56 -21
  83. umap/static/umap/locale/el.js +51 -16
  84. umap/static/umap/locale/el.json +51 -16
  85. umap/static/umap/locale/en.js +51 -16
  86. umap/static/umap/locale/en.json +51 -16
  87. umap/static/umap/locale/en_US.json +51 -16
  88. umap/static/umap/locale/es.js +51 -16
  89. umap/static/umap/locale/es.json +51 -16
  90. umap/static/umap/locale/et.js +51 -16
  91. umap/static/umap/locale/et.json +51 -16
  92. umap/static/umap/locale/eu.js +51 -16
  93. umap/static/umap/locale/eu.json +51 -16
  94. umap/static/umap/locale/fa_IR.js +51 -16
  95. umap/static/umap/locale/fa_IR.json +51 -16
  96. umap/static/umap/locale/fi.js +51 -16
  97. umap/static/umap/locale/fi.json +51 -16
  98. umap/static/umap/locale/fr.js +52 -17
  99. umap/static/umap/locale/fr.json +52 -17
  100. umap/static/umap/locale/gl.js +51 -16
  101. umap/static/umap/locale/gl.json +51 -16
  102. umap/static/umap/locale/he.js +51 -16
  103. umap/static/umap/locale/he.json +51 -16
  104. umap/static/umap/locale/hr.js +51 -16
  105. umap/static/umap/locale/hr.json +51 -16
  106. umap/static/umap/locale/hu.js +51 -16
  107. umap/static/umap/locale/hu.json +51 -16
  108. umap/static/umap/locale/id.js +51 -16
  109. umap/static/umap/locale/id.json +51 -16
  110. umap/static/umap/locale/is.js +51 -16
  111. umap/static/umap/locale/is.json +51 -16
  112. umap/static/umap/locale/it.js +51 -16
  113. umap/static/umap/locale/it.json +51 -16
  114. umap/static/umap/locale/ja.js +51 -16
  115. umap/static/umap/locale/ja.json +51 -16
  116. umap/static/umap/locale/ko.js +51 -16
  117. umap/static/umap/locale/ko.json +51 -16
  118. umap/static/umap/locale/lt.js +51 -16
  119. umap/static/umap/locale/lt.json +51 -16
  120. umap/static/umap/locale/ms.js +51 -16
  121. umap/static/umap/locale/ms.json +51 -16
  122. umap/static/umap/locale/nl.js +51 -16
  123. umap/static/umap/locale/nl.json +51 -16
  124. umap/static/umap/locale/no.js +51 -16
  125. umap/static/umap/locale/no.json +51 -16
  126. umap/static/umap/locale/pl.js +93 -58
  127. umap/static/umap/locale/pl.json +93 -58
  128. umap/static/umap/locale/pl_PL.json +51 -16
  129. umap/static/umap/locale/pt.js +215 -180
  130. umap/static/umap/locale/pt.json +215 -180
  131. umap/static/umap/locale/pt_BR.js +51 -16
  132. umap/static/umap/locale/pt_BR.json +51 -16
  133. umap/static/umap/locale/pt_PT.js +51 -16
  134. umap/static/umap/locale/pt_PT.json +51 -16
  135. umap/static/umap/locale/ro.js +51 -16
  136. umap/static/umap/locale/ro.json +51 -16
  137. umap/static/umap/locale/ru.js +51 -16
  138. umap/static/umap/locale/ru.json +51 -16
  139. umap/static/umap/locale/si.js +51 -16
  140. umap/static/umap/locale/si.json +51 -16
  141. umap/static/umap/locale/sk_SK.js +51 -16
  142. umap/static/umap/locale/sk_SK.json +51 -16
  143. umap/static/umap/locale/sl.js +51 -16
  144. umap/static/umap/locale/sl.json +51 -16
  145. umap/static/umap/locale/sr.js +51 -16
  146. umap/static/umap/locale/sr.json +51 -16
  147. umap/static/umap/locale/sv.js +51 -16
  148. umap/static/umap/locale/sv.json +51 -16
  149. umap/static/umap/locale/th_TH.js +51 -16
  150. umap/static/umap/locale/th_TH.json +51 -16
  151. umap/static/umap/locale/tr.js +51 -16
  152. umap/static/umap/locale/tr.json +51 -16
  153. umap/static/umap/locale/uk_UA.js +51 -16
  154. umap/static/umap/locale/uk_UA.json +51 -16
  155. umap/static/umap/locale/vi.js +51 -16
  156. umap/static/umap/locale/vi.json +51 -16
  157. umap/static/umap/locale/vi_VN.json +51 -16
  158. umap/static/umap/locale/zh.js +51 -16
  159. umap/static/umap/locale/zh.json +51 -16
  160. umap/static/umap/locale/zh_CN.json +51 -16
  161. umap/static/umap/locale/zh_TW.Big5.json +51 -16
  162. umap/static/umap/locale/zh_TW.js +51 -16
  163. umap/static/umap/locale/zh_TW.json +51 -16
  164. umap/static/umap/map.css +27 -41
  165. umap/static/umap/unittests/sync.js +105 -0
  166. umap/static/umap/unittests/utils.js +76 -34
  167. umap/static/umap/vars.css +18 -1
  168. umap/static/umap/vendors/dompurify/purify.es.js +5 -59
  169. umap/static/umap/vendors/dompurify/purify.es.mjs.map +1 -1
  170. umap/templates/umap/components/alerts/alert.html +89 -0
  171. umap/templates/umap/content.html +4 -3
  172. umap/templates/umap/css.html +4 -0
  173. umap/templates/umap/home.html +3 -0
  174. umap/templates/umap/js.html +0 -3
  175. umap/templates/umap/map_init.html +2 -8
  176. umap/templates/umap/messages.html +9 -11
  177. umap/templates/umap/search.html +3 -0
  178. umap/tests/.DS_Store +0 -0
  179. umap/tests/base.py +2 -0
  180. umap/tests/integration/.DS_Store +0 -0
  181. umap/tests/integration/conftest.py +30 -0
  182. umap/tests/integration/test_anonymous_owned_map.py +8 -13
  183. umap/tests/integration/test_browser.py +1 -1
  184. umap/tests/integration/test_conditional_rules.py +201 -0
  185. umap/tests/integration/test_dashboard.py +1 -1
  186. umap/tests/integration/test_datalayer.py +2 -3
  187. umap/tests/integration/test_edit_datalayer.py +4 -4
  188. umap/tests/integration/test_edit_map.py +1 -1
  189. umap/tests/integration/test_facets_browser.py +3 -3
  190. umap/tests/integration/test_import.py +138 -49
  191. umap/tests/integration/test_map.py +2 -2
  192. umap/tests/integration/{test_collaborative_editing.py → test_optimistic_merge.py} +7 -7
  193. umap/tests/integration/test_owned_map.py +1 -1
  194. umap/tests/integration/test_picto.py +2 -2
  195. umap/tests/integration/test_statics.py +1 -1
  196. umap/tests/integration/test_websocket_sync.py +283 -0
  197. umap/tests/settings.py +5 -0
  198. umap/tests/test_datalayer_views.py +0 -1
  199. umap/tests/test_views.py +53 -0
  200. umap/urls.py +5 -0
  201. umap/views.py +40 -11
  202. umap/websocket_server.py +92 -0
  203. {umap_project-2.3.1.dist-info → umap_project-2.4.0b0.dist-info}/METADATA +11 -9
  204. {umap_project-2.3.1.dist-info → umap_project-2.4.0b0.dist-info}/RECORD +207 -164
  205. {umap_project-2.3.1.dist-info → umap_project-2.4.0b0.dist-info}/WHEEL +1 -1
  206. umap/static/umap/js/umap.autocomplete.js +0 -341
  207. umap/static/umap/js/umap.importer.js +0 -187
  208. umap/static/umap/js/umap.ui.js +0 -190
  209. {umap_project-2.3.1.dist-info → umap_project-2.4.0b0.dist-info}/entry_points.txt +0 -0
  210. {umap_project-2.3.1.dist-info → umap_project-2.4.0b0.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,7 @@ 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(container, L._('Feature properties'), `icon-${this.getClassName()}`)
111
148
 
112
149
  let builder = new U.FormBuilder(
113
150
  this,
@@ -134,7 +171,6 @@ U.FeatureMixin = {
134
171
  properties.unshift('properties.name')
135
172
  builder = new U.FormBuilder(this, properties, {
136
173
  id: 'umap-feature-properties',
137
- callback: this._redraw, // In case we have dynamic options…
138
174
  })
139
175
  container.appendChild(builder.build())
140
176
  this.appendEditFieldsets(container)
@@ -149,7 +185,7 @@ U.FeatureMixin = {
149
185
  },
150
186
 
151
187
  getAdvancedEditActions: function (container) {
152
- const deleteButton = L.DomUtil.createButton(
188
+ L.DomUtil.createButton(
153
189
  'button umap-delete',
154
190
  container,
155
191
  L._('Delete'),
@@ -165,7 +201,6 @@ U.FeatureMixin = {
165
201
  const optionsFields = this.getShapeOptions()
166
202
  let builder = new U.FormBuilder(this, optionsFields, {
167
203
  id: 'umap-feature-shape-properties',
168
- callback: this._redraw,
169
204
  })
170
205
  const shapeProperties = L.DomUtil.createFieldset(container, L._('Shape properties'))
171
206
  shapeProperties.appendChild(builder.build())
@@ -173,7 +208,6 @@ U.FeatureMixin = {
173
208
  const advancedOptions = this.getAdvancedOptions()
174
209
  builder = new U.FormBuilder(this, advancedOptions, {
175
210
  id: 'umap-feature-advanced-properties',
176
- callback: this._redraw,
177
211
  })
178
212
  const advancedProperties = L.DomUtil.createFieldset(
179
213
  container,
@@ -182,9 +216,7 @@ U.FeatureMixin = {
182
216
  advancedProperties.appendChild(builder.build())
183
217
 
184
218
  const interactionOptions = this.getInteractionOptions()
185
- builder = new U.FormBuilder(this, interactionOptions, {
186
- callback: this._redraw,
187
- })
219
+ builder = new U.FormBuilder(this, interactionOptions)
188
220
  const popupFieldset = L.DomUtil.createFieldset(
189
221
  container,
190
222
  L._('Interaction options')
@@ -240,13 +272,14 @@ U.FeatureMixin = {
240
272
  }
241
273
  return false
242
274
  },
243
-
244
- del: function () {
275
+ del: function (sync) {
245
276
  this.isDirty = true
246
277
  this.map.closePopup()
247
278
  if (this.datalayer) {
248
279
  this.datalayer.removeLayer(this)
249
280
  this.disconnectFromDataLayer(this.datalayer)
281
+
282
+ if (sync !== false) this.syncDelete()
250
283
  }
251
284
  },
252
285
 
@@ -549,7 +582,10 @@ U.FeatureMixin = {
549
582
  },
550
583
 
551
584
  clone: function () {
552
- const layer = this.datalayer.geojsonToFeatures(this.toGeoJSON())
585
+ const geoJSON = this.toGeoJSON()
586
+ delete geoJSON.id
587
+ delete geoJSON.properties.id
588
+ const layer = this.datalayer.geojsonToFeatures(geoJSON)
553
589
  layer.isDirty = true
554
590
  layer.edit()
555
591
  return layer
@@ -602,9 +638,11 @@ U.Marker = L.Marker.extend({
602
638
  function (e) {
603
639
  this.isDirty = true
604
640
  this.edit(e)
641
+ this.sync.update('geometry', this.getGeometry())
605
642
  },
606
643
  this
607
644
  )
645
+ this.on('editable:drawing:commit', this.onCommit)
608
646
  if (!this.isReadOnly()) this.on('mouseover', this._enableDragging)
609
647
  this.on('mouseout', this._onMouseOut)
610
648
  this._popupHandlersAdded = true // prevent Leaflet from binding event on bindPopup
@@ -726,14 +764,10 @@ U.Marker = L.Marker.extend({
726
764
  const builder = new U.FormBuilder(this, coordinatesOptions, {
727
765
  callback: function () {
728
766
  if (!this._latlng.isValid()) {
729
- this.map.ui.alert({
730
- content: L._('Invalid latitude or longitude'),
731
- level: 'error',
732
- })
767
+ U.Alert.error(L._('Invalid latitude or longitude'))
733
768
  builder.resetField('_latlng.lat')
734
769
  builder.resetField('_latlng.lng')
735
770
  }
736
- this._redraw()
737
771
  this.zoomTo({ easing: false })
738
772
  },
739
773
  callbackContext: this,
@@ -878,14 +912,15 @@ U.PathMixin = {
878
912
 
879
913
  _onMouseOver: function () {
880
914
  if (this.map.measureTools && this.map.measureTools.enabled()) {
881
- this.map.ui.tooltip({ content: this.getMeasure(), anchor: this })
915
+ this.map.tooltip.open({ content: this.getMeasure(), anchor: this })
882
916
  } else if (this.map.editEnabled && !this.map.editedFeature) {
883
- this.map.ui.tooltip({ content: L._('Click to edit'), anchor: this })
917
+ this.map.tooltip.open({ content: L._('Click to edit'), anchor: this })
884
918
  }
885
919
  },
886
920
 
887
921
  addInteractions: function () {
888
922
  U.FeatureMixin.addInteractions.call(this)
923
+ this.on('editable:disable', this.onCommit)
889
924
  this.on('mouseover', this._onMouseOver)
890
925
  this.on('edit', this.makeDirty)
891
926
  this.on('drag editable:drag', this._onDrag)
@@ -928,7 +963,7 @@ U.PathMixin = {
928
963
  items.push({
929
964
  text: L._('Display measure'),
930
965
  callback: function () {
931
- this.map.ui.alert({ content: this.getMeasure(), level: 'info' })
966
+ U.Alert.info(this.getMeasure())
932
967
  },
933
968
  context: this,
934
969
  })
@@ -1086,6 +1121,9 @@ U.Polyline = L.Polyline.extend({
1086
1121
  geojson.geometry.coordinates = [
1087
1122
  U.Utils.flattenCoordinates(geojson.geometry.coordinates),
1088
1123
  ]
1124
+
1125
+ delete geojson.id // delete the copied id, a new one will be generated.
1126
+
1089
1127
  const polygon = this.datalayer.geojsonToFeatures(geojson)
1090
1128
  polygon.edit()
1091
1129
  this.del()
@@ -1093,7 +1131,7 @@ U.Polyline = L.Polyline.extend({
1093
1131
 
1094
1132
  getAdvancedEditActions: function (container) {
1095
1133
  U.FeatureMixin.getAdvancedEditActions.call(this, container)
1096
- const toPolygon = L.DomUtil.createButton(
1134
+ L.DomUtil.createButton(
1097
1135
  'button umap-to-polygon',
1098
1136
  container,
1099
1137
  L._('Transform to polygon'),
@@ -1223,6 +1261,8 @@ U.Polygon = L.Polygon.extend({
1223
1261
 
1224
1262
  toPolyline: function () {
1225
1263
  const geojson = this.toGeoJSON()
1264
+ delete geojson.id
1265
+ delete geojson.properties.id
1226
1266
  geojson.geometry.type = 'LineString'
1227
1267
  geojson.geometry.coordinates = U.Utils.flattenCoordinates(
1228
1268
  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 () {