umap-project 2.6.3__py3-none-any.whl → 2.7.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 (137) hide show
  1. umap/__init__.py +1 -1
  2. umap/admin.py +64 -1
  3. umap/asgi.py +15 -0
  4. umap/context_processors.py +1 -0
  5. umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  6. umap/locale/cs_CZ/LC_MESSAGES/django.po +96 -92
  7. umap/locale/de/LC_MESSAGES/django.mo +0 -0
  8. umap/locale/de/LC_MESSAGES/django.po +19 -18
  9. umap/locale/en/LC_MESSAGES/django.po +47 -43
  10. umap/locale/es/LC_MESSAGES/django.mo +0 -0
  11. umap/locale/es/LC_MESSAGES/django.po +134 -128
  12. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  13. umap/locale/fr/LC_MESSAGES/django.po +51 -47
  14. umap/locale/pt/LC_MESSAGES/django.mo +0 -0
  15. umap/locale/pt/LC_MESSAGES/django.po +64 -60
  16. umap/management/commands/clean_tilelayer.py +152 -0
  17. umap/management/commands/purge_purgatory.py +28 -0
  18. umap/models.py +27 -2
  19. umap/settings/base.py +3 -1
  20. umap/static/umap/base.css +4 -4
  21. umap/static/umap/css/contextmenu.css +6 -1
  22. umap/static/umap/css/icon.css +7 -2
  23. umap/static/umap/css/importers.css +4 -0
  24. umap/static/umap/img/16-white.svg +9 -2
  25. umap/static/umap/img/16.svg +1 -181
  26. umap/static/umap/img/24-white.svg +1 -0
  27. umap/static/umap/img/24.svg +1 -0
  28. umap/static/umap/img/importers/cadastrefr.svg +23 -0
  29. umap/static/umap/img/source/16-white.svg +10 -3
  30. umap/static/umap/img/source/16.svg +753 -197
  31. umap/static/umap/img/source/24-white.svg +3 -2
  32. umap/static/umap/img/source/24.svg +3 -2
  33. umap/static/umap/js/modules/autocomplete.js +7 -3
  34. umap/static/umap/js/modules/browser.js +54 -1
  35. umap/static/umap/js/modules/caption.js +16 -5
  36. umap/static/umap/js/modules/data/features.js +176 -2
  37. umap/static/umap/js/modules/data/layer.js +57 -40
  38. umap/static/umap/js/modules/formatter.js +3 -2
  39. umap/static/umap/js/modules/global.js +2 -0
  40. umap/static/umap/js/modules/importer.js +3 -0
  41. umap/static/umap/js/modules/importers/cadastrefr.js +62 -0
  42. umap/static/umap/js/modules/importers/communesfr.js +15 -3
  43. umap/static/umap/js/modules/permissions.js +123 -93
  44. umap/static/umap/js/modules/rendering/layers/classified.js +2 -0
  45. umap/static/umap/js/modules/rendering/ui.js +60 -213
  46. umap/static/umap/js/modules/share.js +1 -3
  47. umap/static/umap/js/modules/slideshow.js +1 -1
  48. umap/static/umap/js/modules/sync/engine.js +371 -14
  49. umap/static/umap/js/modules/sync/hlc.js +106 -0
  50. umap/static/umap/js/modules/sync/updaters.js +18 -6
  51. umap/static/umap/js/modules/sync/websocket.js +1 -1
  52. umap/static/umap/js/modules/tableeditor.js +1 -1
  53. umap/static/umap/js/modules/ui/base.js +2 -2
  54. umap/static/umap/js/modules/ui/contextmenu.js +51 -18
  55. umap/static/umap/js/modules/urls.js +5 -1
  56. umap/static/umap/js/modules/utils.js +28 -4
  57. umap/static/umap/js/umap.controls.js +73 -52
  58. umap/static/umap/js/umap.core.js +3 -3
  59. umap/static/umap/js/umap.forms.js +3 -1
  60. umap/static/umap/js/umap.js +115 -124
  61. umap/static/umap/locale/br.js +13 -4
  62. umap/static/umap/locale/br.json +13 -4
  63. umap/static/umap/locale/ca.js +28 -15
  64. umap/static/umap/locale/ca.json +28 -15
  65. umap/static/umap/locale/cs_CZ.js +87 -78
  66. umap/static/umap/locale/cs_CZ.json +87 -78
  67. umap/static/umap/locale/de.js +17 -8
  68. umap/static/umap/locale/de.json +17 -8
  69. umap/static/umap/locale/en.js +13 -2
  70. umap/static/umap/locale/en.json +13 -2
  71. umap/static/umap/locale/es.js +330 -319
  72. umap/static/umap/locale/es.json +330 -319
  73. umap/static/umap/locale/eu.js +10 -3
  74. umap/static/umap/locale/eu.json +10 -3
  75. umap/static/umap/locale/fa_IR.js +11 -4
  76. umap/static/umap/locale/fa_IR.json +11 -4
  77. umap/static/umap/locale/fr.js +15 -4
  78. umap/static/umap/locale/fr.json +15 -4
  79. umap/static/umap/locale/hu.js +10 -3
  80. umap/static/umap/locale/hu.json +10 -3
  81. umap/static/umap/locale/pt.js +17 -8
  82. umap/static/umap/locale/pt.json +17 -8
  83. umap/static/umap/locale/pt_PT.js +13 -4
  84. umap/static/umap/locale/pt_PT.json +13 -4
  85. umap/static/umap/locale/zh_TW.js +13 -4
  86. umap/static/umap/locale/zh_TW.json +13 -4
  87. umap/static/umap/map.css +44 -29
  88. umap/static/umap/unittests/hlc.js +165 -0
  89. umap/static/umap/unittests/sync.js +321 -15
  90. umap/static/umap/unittests/utils.js +47 -0
  91. umap/static/umap/vars.css +2 -1
  92. umap/static/umap/vendors/colorbrewer/colorbrewer.js +309 -317
  93. umap/static/umap/vendors/dompurify/purify.es.js +15 -16
  94. umap/static/umap/vendors/dompurify/purify.es.mjs.map +1 -1
  95. umap/static/umap/vendors/georsstogeojson/GeoRSSToGeoJSON.js +111 -80
  96. umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.js +2 -2
  97. umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.js.map +1 -1
  98. umap/static/umap/vendors/simple-statistics/simple-statistics.min.js +1 -1
  99. umap/static/umap/vendors/simple-statistics/simple-statistics.min.js.map +1 -1
  100. umap/templates/umap/css.html +0 -2
  101. umap/templates/umap/dashboard_menu.html +4 -2
  102. umap/templates/umap/js.html +0 -5
  103. umap/templates/umap/map_detail.html +2 -2
  104. umap/tests/fixtures/test_upload_data.csv +2 -2
  105. umap/tests/integration/test_anonymous_owned_map.py +1 -0
  106. umap/tests/integration/test_basics.py +1 -1
  107. umap/tests/integration/test_browser.py +69 -7
  108. umap/tests/integration/test_caption.py +3 -3
  109. umap/tests/integration/test_circles_layer.py +12 -0
  110. umap/tests/integration/test_datalayer.py +2 -1
  111. umap/tests/integration/test_draw_polygon.py +17 -9
  112. umap/tests/integration/test_draw_polyline.py +12 -8
  113. umap/tests/integration/test_edit_datalayer.py +5 -8
  114. umap/tests/integration/test_edit_map.py +2 -2
  115. umap/tests/integration/test_edit_marker.py +1 -1
  116. umap/tests/integration/test_facets_browser.py +3 -3
  117. umap/tests/integration/test_import.py +1 -0
  118. umap/tests/integration/test_map.py +1 -0
  119. umap/tests/integration/test_owned_map.py +1 -1
  120. umap/tests/integration/test_view_marker.py +63 -0
  121. umap/tests/integration/test_view_polygon.py +12 -12
  122. umap/tests/integration/test_websocket_sync.py +65 -3
  123. umap/tests/test_clean_tilelayer.py +83 -0
  124. umap/tests/test_datalayer.py +24 -0
  125. umap/tests/test_map_views.py +20 -0
  126. umap/tests/test_purge_purgatory.py +25 -0
  127. umap/tests/test_websocket_server.py +22 -0
  128. umap/urls.py +5 -1
  129. umap/views.py +6 -3
  130. umap/websocket_server.py +130 -27
  131. {umap_project-2.6.3.dist-info → umap_project-2.7.0.dist-info}/METADATA +18 -14
  132. {umap_project-2.6.3.dist-info → umap_project-2.7.0.dist-info}/RECORD +135 -127
  133. umap/static/umap/vendors/contextmenu/leaflet.contextmenu.min.css +0 -1
  134. umap/static/umap/vendors/contextmenu/leaflet.contextmenu.min.js +0 -7
  135. {umap_project-2.6.3.dist-info → umap_project-2.7.0.dist-info}/WHEEL +0 -0
  136. {umap_project-2.6.3.dist-info → umap_project-2.7.0.dist-info}/entry_points.txt +0 -0
  137. {umap_project-2.6.3.dist-info → umap_project-2.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -9,6 +9,7 @@ import {
9
9
  latLng,
10
10
  LatLng,
11
11
  LatLngBounds,
12
+ DomEvent,
12
13
  } from '../../../vendors/leaflet/leaflet-src.esm.js'
13
14
  import { translate } from '../i18n.js'
14
15
  import { uMapAlert as Alert } from '../../components/alerts/alert.js'
@@ -35,8 +36,14 @@ const FeatureMixin = {
35
36
  }
36
37
  },
37
38
 
39
+ _removeIcon: function () {
40
+ // It may not be in the DOM, and Leaflet does not deal with this
41
+ // situation
42
+ if (this._icon) Marker.prototype._removeIcon.call(this)
43
+ },
44
+
38
45
  addInteractions: function () {
39
- this.on('contextmenu editable:vertex:contextmenu', this._showContextMenu)
46
+ this.on('contextmenu editable:vertex:contextmenu', this.onContextMenu)
40
47
  this.on('click', this.onClick)
41
48
  },
42
49
 
@@ -61,7 +68,7 @@ const FeatureMixin = {
61
68
  }).addTo(this._map, this.feature, event.latlng)
62
69
  }
63
70
  }
64
- L.DomEvent.stop(event)
71
+ DomEvent.stop(event)
65
72
  },
66
73
 
67
74
  resetTooltip: function () {
@@ -83,67 +90,12 @@ const FeatureMixin = {
83
90
  }
84
91
  },
85
92
 
86
- _showContextMenu: function (event) {
87
- L.DomEvent.stop(event)
88
- const pt = this._map.mouseEventToContainerPoint(event.originalEvent)
89
- event.relatedTarget = this
90
- this._map.contextmenu.showAt(pt, event)
91
- },
92
-
93
- getContextMenuItems: function (event) {
94
- const permalink = this.feature.getPermalink()
95
- let items = []
96
- if (permalink) {
97
- items.push({
98
- text: translate('Permalink'),
99
- callback: () => {
100
- window.open(permalink)
101
- },
102
- })
103
- }
104
- items.push({
105
- text: translate('Copy as GeoJSON'),
106
- callback: () => {
107
- L.Util.copyToClipboard(JSON.stringify(this.feature.toGeoJSON()))
108
- this._map.tooltip.open({ content: L._('✅ Copied!') })
109
- },
110
- })
111
- if (this._map.editEnabled && !this.feature.isReadOnly()) {
112
- items = items.concat(this.getContextMenuEditItems(event))
113
- }
114
- return items
115
- },
116
-
117
- getContextMenuEditItems: function () {
118
- let items = ['-']
119
- if (this._map.editedFeature !== this) {
120
- items.push({
121
- text: `${translate('Edit this feature')} (⇧+Click)`,
122
- callback: this.feature.edit,
123
- context: this.feature,
124
- iconCls: 'umap-edit',
125
- })
126
- }
127
- items = items.concat(
128
- {
129
- text: this._map.help.displayLabel('EDIT_FEATURE_LAYER'),
130
- callback: this.feature.datalayer.edit,
131
- context: this.feature.datalayer,
132
- iconCls: 'umap-edit',
133
- },
134
- {
135
- text: translate('Delete this feature'),
136
- callback: this.feature.confirmDelete,
137
- context: this.feature,
138
- iconCls: 'umap-delete',
139
- },
140
- {
141
- text: translate('Clone this feature'),
142
- callback: this.feature.clone,
143
- context: this.feature,
144
- }
145
- )
146
- return items
93
+ onContextMenu: function (event) {
94
+ DomEvent.stop(event)
95
+ const items = this.feature
96
+ .getContextMenuItems(event)
97
+ .concat(this._map.getContextMenuItems(event))
98
+ this._map.contextmenu.open(event.originalEvent, items)
147
99
  },
148
100
 
149
101
  onCommit: function () {
@@ -158,27 +110,6 @@ const PointMixin = {
158
110
  isOnScreen: function (bounds) {
159
111
  return bounds.contains(this.getCenter())
160
112
  },
161
- }
162
-
163
- export const LeafletMarker = Marker.extend({
164
- parentClass: Marker,
165
- includes: [FeatureMixin, PointMixin],
166
-
167
- initialize: function (feature, latlng) {
168
- FeatureMixin.initialize.call(this, feature, latlng)
169
- this.setIcon(this.getIcon())
170
- },
171
-
172
- getClass: () => LeafletMarker,
173
-
174
- // Make API consistent with path
175
- getLatLngs: function () {
176
- return this.getLatLng()
177
- },
178
-
179
- setLatLngs: function (latlng) {
180
- return this.setLatLng(latlng)
181
- },
182
113
 
183
114
  addInteractions() {
184
115
  FeatureMixin.addInteractions.call(this)
@@ -190,9 +121,6 @@ export const LeafletMarker = Marker.extend({
190
121
  this.on('editable:drawing:commit', this.onCommit)
191
122
  if (!this.feature.isReadOnly()) this.on('mouseover', this._enableDragging)
192
123
  this.on('mouseout', this._onMouseOut)
193
- this._popupHandlersAdded = true // prevent Leaflet from binding event on bindPopup
194
- this.on('popupopen', this.highlight)
195
- this.on('popupclose', this.resetHighlight)
196
124
  },
197
125
 
198
126
  _onMouseOut: function () {
@@ -222,8 +150,49 @@ export const LeafletMarker = Marker.extend({
222
150
  this.disableEdit()
223
151
  }
224
152
  },
153
+ }
154
+
155
+ export const LeafletMarker = Marker.extend({
156
+ parentClass: Marker,
157
+ includes: [FeatureMixin, PointMixin],
158
+
159
+ initialize: function (feature, latlng) {
160
+ FeatureMixin.initialize.call(this, feature, latlng)
161
+ this.setIcon(this.getIcon())
162
+ },
163
+
164
+ getClass: () => LeafletMarker,
165
+
166
+ setLatLngs: function (latlng) {
167
+ return this.setLatLng(latlng)
168
+ },
169
+
170
+ getEvents: function () {
171
+ const events = Marker.prototype.getEvents.call(this)
172
+ events.moveend = this.onMoveEnd
173
+ return events
174
+ },
175
+
176
+ addInteractions() {
177
+ PointMixin.addInteractions.call(this)
178
+ this._popupHandlersAdded = true // prevent Leaflet from binding event on bindPopup
179
+ this.on('popupopen', this.highlight)
180
+ this.on('popupclose', this.resetHighlight)
181
+ },
182
+
183
+ onMoveEnd: function () {
184
+ this._initIcon()
185
+ this.update()
186
+ },
225
187
 
226
188
  _initIcon: function () {
189
+ if (!this._map.getBounds().contains(this.getCenter())) {
190
+ if (this._icon) this._removeIcon()
191
+ if (this._tooltip && this.isTooltipOpen()) {
192
+ this.unbindTooltip()
193
+ }
194
+ return
195
+ }
227
196
  this.options.icon = this.getIcon()
228
197
  Marker.prototype._initIcon.call(this)
229
198
  // Allow to run code when icon is actually part of the DOM
@@ -344,6 +313,10 @@ const PathMixin = {
344
313
  }
345
314
  options.pointerEvents = options.interactive ? 'visiblePainted' : 'stroke'
346
315
  this.parentClass.prototype.setStyle.call(this, options)
316
+ // TODO remove me when this gets merged and released:
317
+ // https://github.com/Leaflet/Leaflet/pull/9475
318
+
319
+ this._path.classList.toggle('leaflet-interactive', options.interactive)
347
320
  },
348
321
 
349
322
  _redraw: function () {
@@ -360,65 +333,6 @@ const PathMixin = {
360
333
  }).addTo(this._map, this, event.latlng, event.vertex)
361
334
  },
362
335
 
363
- getContextMenuItems: function (event) {
364
- let items = FeatureMixin.getContextMenuItems.call(this, event)
365
- items.push({
366
- text: translate('Display measure'),
367
- callback: () => Alert.info(this.getMeasure()),
368
- })
369
- if (this._map.editEnabled && !this.feature.isReadOnly() && this.feature.isMulti()) {
370
- items = items.concat(this.getContextMenuMultiItems(event))
371
- }
372
- return items
373
- },
374
-
375
- getContextMenuMultiItems: function (event) {
376
- const items = [
377
- '-',
378
- {
379
- text: translate('Remove shape from the multi'),
380
- callback: () => {
381
- this.enableEdit().deleteShapeAt(event.latlng)
382
- },
383
- },
384
- ]
385
- const shape = this.shapeAt(event.latlng)
386
- if (this._latlngs.indexOf(shape) > 0) {
387
- items.push({
388
- text: translate('Make main shape'),
389
- callback: () => {
390
- this.enableEdit().deleteShape(shape)
391
- this.editor.prependShape(shape)
392
- },
393
- })
394
- }
395
- return items
396
- },
397
-
398
- getContextMenuEditItems: function (event) {
399
- const items = FeatureMixin.getContextMenuEditItems.call(this, event)
400
- if (
401
- this._map?.editedFeature !== this.feature &&
402
- this.feature.isSameClass(this._map.editedFeature)
403
- ) {
404
- items.push({
405
- text: translate('Transfer shape to edited feature'),
406
- callback: () => {
407
- this.feature.transferShape(event.latlng, this._map.editedFeature)
408
- },
409
- })
410
- }
411
- if (this.feature.isMulti()) {
412
- items.push({
413
- text: translate('Extract shape to separate feature'),
414
- callback: () => {
415
- this.isolateShape(event.latlng)
416
- },
417
- })
418
- }
419
- return items
420
- },
421
-
422
336
  isolateShape: function (atLatLng) {
423
337
  if (!this.feature.isMulti()) return
424
338
  const shape = this.enableEdit().deleteShapeAt(atLatLng)
@@ -463,46 +377,6 @@ export const LeafletPolyline = Polyline.extend({
463
377
  return actions
464
378
  },
465
379
 
466
- getContextMenuEditItems: function (event) {
467
- const items = PathMixin.getContextMenuEditItems.call(this, event)
468
- const vertexClicked = event.vertex
469
- let index
470
- if (!this.feature.isMulti()) {
471
- items.push({
472
- text: translate('Transform to polygon'),
473
- callback: this.feature.toPolygon,
474
- context: this.feature,
475
- })
476
- }
477
- if (vertexClicked) {
478
- index = event.vertex.getIndex()
479
- if (index !== 0 && index !== event.vertex.getLastIndex()) {
480
- items.push({
481
- text: translate('Split line'),
482
- callback: event.vertex.split,
483
- context: event.vertex,
484
- })
485
- } else if (index === 0 || index === event.vertex.getLastIndex()) {
486
- items.push({
487
- text: this._map.help.displayLabel('CONTINUE_LINE'),
488
- callback: event.vertex.continue,
489
- context: event.vertex.continue,
490
- })
491
- }
492
- }
493
- return items
494
- },
495
-
496
- getContextMenuMultiItems: function (event) {
497
- const items = PathMixin.getContextMenuMultiItems.call(this, event)
498
- items.push({
499
- text: translate('Merge lines'),
500
- callback: this.feature.mergeShapes,
501
- context: this.feature,
502
- })
503
- return items
504
- },
505
-
506
380
  getMeasure: function (shape) {
507
381
  // FIXME: compute from data in feature (with TurfJS)
508
382
  const length = L.GeoUtil.lineLength(this._map, shape || this._defaultShape())
@@ -516,29 +390,6 @@ export const LeafletPolygon = Polygon.extend({
516
390
 
517
391
  getClass: () => LeafletPolygon,
518
392
 
519
- getContextMenuEditItems: function (event) {
520
- const items = PathMixin.getContextMenuEditItems.call(this, event)
521
- const shape = this.shapeAt(event.latlng)
522
- // No multi and no holes.
523
- if (
524
- shape &&
525
- !this.feature.isMulti() &&
526
- (LineUtil.isFlat(shape) || shape.length === 1)
527
- ) {
528
- items.push({
529
- text: translate('Transform to lines'),
530
- callback: this.feature.toLineString,
531
- context: this.feature,
532
- })
533
- }
534
- items.push({
535
- text: translate('Start a hole here'),
536
- callback: this.startHole,
537
- context: this,
538
- })
539
- return items
540
- },
541
-
542
393
  startHole: function (event) {
543
394
  this.enableEdit().newHole(event.latlng)
544
395
  },
@@ -603,8 +454,4 @@ export const CircleMarker = BaseCircleMarker.extend({
603
454
  getCenter: function () {
604
455
  return this._latlng
605
456
  },
606
- // FIXME when Leaflet.Editable knows about CircleMarker
607
- editEnabled: () => false,
608
- enableEdit: () => {}, // No-op
609
- disableEdit: () => {}, // No-op
610
457
  })
@@ -142,9 +142,7 @@ export default class Share {
142
142
  async format(mode) {
143
143
  const type = EXPORT_FORMATS[mode]
144
144
  const content = await type.formatter(this.map)
145
- let name = this.map.options.name || 'data'
146
- name = name.replace(/[^a-z0-9]/gi, '_').toLowerCase()
147
- const filename = name + type.ext
145
+ const filename = Utils.slugify(this.map.options.name) + type.ext
148
146
  return { content, filetype: type.filetype, filename }
149
147
  }
150
148
 
@@ -1,5 +1,5 @@
1
- import { WithTemplate } from './utils.js'
2
1
  import { translate } from './i18n.js'
2
+ import { WithTemplate } from './utils.js'
3
3
 
4
4
  const TOOLBOX_TEMPLATE = `
5
5
  <ul class="umap-slideshow-toolbox dark">