umap-project 3.4.0b1__py3-none-any.whl → 3.4.2__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 (202) hide show
  1. umap/__init__.py +1 -1
  2. umap/context_processors.py +1 -1
  3. umap/locale/da/LC_MESSAGES/django.mo +0 -0
  4. umap/locale/da/LC_MESSAGES/django.po +20 -16
  5. umap/locale/en/LC_MESSAGES/django.po +18 -14
  6. umap/locale/es/LC_MESSAGES/django.mo +0 -0
  7. umap/locale/es/LC_MESSAGES/django.po +20 -16
  8. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  9. umap/locale/fr/LC_MESSAGES/django.po +18 -14
  10. umap/locale/pl/LC_MESSAGES/django.mo +0 -0
  11. umap/locale/pl/LC_MESSAGES/django.po +72 -71
  12. umap/migrations/0018_datalayer_uuid.py +1 -1
  13. umap/models.py +7 -3
  14. umap/settings/local.py.sample +1 -1
  15. umap/static/umap/content.css +0 -3
  16. umap/static/umap/css/bar.css +9 -6
  17. umap/static/umap/css/form.css +27 -11
  18. umap/static/umap/css/popup.css +1 -0
  19. umap/static/umap/js/components/base.js +1 -1
  20. umap/static/umap/js/components/copiable.js +47 -0
  21. umap/static/umap/js/modules/autocomplete.js +31 -58
  22. umap/static/umap/js/modules/browser.js +8 -8
  23. umap/static/umap/js/modules/data/features.js +33 -36
  24. umap/static/umap/js/modules/data/fields.js +446 -0
  25. umap/static/umap/js/modules/data/layer.js +76 -93
  26. umap/static/umap/js/modules/domutils.js +24 -4
  27. umap/static/umap/js/modules/filters.js +20 -47
  28. umap/static/umap/js/modules/form/fields.js +4 -4
  29. umap/static/umap/js/modules/formatter.js +9 -1
  30. umap/static/umap/js/modules/help.js +13 -14
  31. umap/static/umap/js/modules/i18n.js +1 -1
  32. umap/static/umap/js/modules/importer.js +18 -27
  33. umap/static/umap/js/modules/importers/banfr.js +0 -1
  34. umap/static/umap/js/modules/importers/cadastrefr.js +19 -19
  35. umap/static/umap/js/modules/importers/communesfr.js +7 -8
  36. umap/static/umap/js/modules/importers/datasets.js +14 -14
  37. umap/static/umap/js/modules/importers/geodatamine.js +20 -22
  38. umap/static/umap/js/modules/importers/opendata.js +10 -0
  39. umap/static/umap/js/modules/importers/overpass.js +19 -18
  40. umap/static/umap/js/modules/managers.js +1 -265
  41. umap/static/umap/js/modules/permissions.js +5 -3
  42. umap/static/umap/js/modules/rendering/controls.js +6 -4
  43. umap/static/umap/js/modules/rendering/icon.js +5 -9
  44. umap/static/umap/js/modules/rendering/layers/base.js +1 -1
  45. umap/static/umap/js/modules/rendering/layers/classified.js +16 -11
  46. umap/static/umap/js/modules/rendering/layers/heat.js +27 -21
  47. umap/static/umap/js/modules/rendering/map.js +22 -22
  48. umap/static/umap/js/modules/rendering/popup.js +6 -3
  49. umap/static/umap/js/modules/rendering/template.js +31 -37
  50. umap/static/umap/js/modules/rendering/ui.js +1 -2
  51. umap/static/umap/js/modules/rules.js +34 -41
  52. umap/static/umap/js/modules/schema.js +0 -7
  53. umap/static/umap/js/modules/share.js +36 -69
  54. umap/static/umap/js/modules/slideshow.js +3 -3
  55. umap/static/umap/js/modules/tableeditor.js +0 -1
  56. umap/static/umap/js/modules/ui/bar.js +51 -32
  57. umap/static/umap/js/modules/ui/dialog.js +10 -1
  58. umap/static/umap/js/modules/ui/panel.js +28 -23
  59. umap/static/umap/js/modules/ui/tooltip.js +1 -1
  60. umap/static/umap/js/modules/umap.js +84 -84
  61. umap/static/umap/js/modules/utils.js +13 -4
  62. umap/static/umap/js/umap.controls.js +33 -14
  63. umap/static/umap/locale/am_ET.js +19 -8
  64. umap/static/umap/locale/am_ET.json +19 -8
  65. umap/static/umap/locale/ar.js +19 -8
  66. umap/static/umap/locale/ar.json +19 -8
  67. umap/static/umap/locale/ast.js +19 -8
  68. umap/static/umap/locale/ast.json +19 -8
  69. umap/static/umap/locale/bg.js +19 -8
  70. umap/static/umap/locale/bg.json +19 -8
  71. umap/static/umap/locale/br.js +20 -9
  72. umap/static/umap/locale/br.json +20 -9
  73. umap/static/umap/locale/ca.js +19 -8
  74. umap/static/umap/locale/ca.json +19 -8
  75. umap/static/umap/locale/cs_CZ.js +20 -9
  76. umap/static/umap/locale/cs_CZ.json +20 -9
  77. umap/static/umap/locale/da.js +54 -43
  78. umap/static/umap/locale/da.json +54 -43
  79. umap/static/umap/locale/de.js +44 -33
  80. umap/static/umap/locale/de.json +44 -33
  81. umap/static/umap/locale/el.js +20 -9
  82. umap/static/umap/locale/el.json +20 -9
  83. umap/static/umap/locale/en.js +20 -9
  84. umap/static/umap/locale/en.json +20 -9
  85. umap/static/umap/locale/en_US.json +19 -8
  86. umap/static/umap/locale/es.js +55 -44
  87. umap/static/umap/locale/es.json +55 -44
  88. umap/static/umap/locale/et.js +20 -9
  89. umap/static/umap/locale/et.json +20 -9
  90. umap/static/umap/locale/eu.js +25 -14
  91. umap/static/umap/locale/eu.json +25 -14
  92. umap/static/umap/locale/fa_IR.js +20 -9
  93. umap/static/umap/locale/fa_IR.json +20 -9
  94. umap/static/umap/locale/fi.js +19 -8
  95. umap/static/umap/locale/fi.json +19 -8
  96. umap/static/umap/locale/fr.js +21 -10
  97. umap/static/umap/locale/fr.json +21 -10
  98. umap/static/umap/locale/gl.js +147 -136
  99. umap/static/umap/locale/gl.json +147 -136
  100. umap/static/umap/locale/he.js +19 -8
  101. umap/static/umap/locale/he.json +19 -8
  102. umap/static/umap/locale/hr.js +19 -8
  103. umap/static/umap/locale/hr.json +19 -8
  104. umap/static/umap/locale/hu.js +62 -51
  105. umap/static/umap/locale/hu.json +62 -51
  106. umap/static/umap/locale/id.js +19 -8
  107. umap/static/umap/locale/id.json +19 -8
  108. umap/static/umap/locale/is.js +20 -9
  109. umap/static/umap/locale/is.json +20 -9
  110. umap/static/umap/locale/it.js +20 -9
  111. umap/static/umap/locale/it.json +20 -9
  112. umap/static/umap/locale/ja.js +19 -8
  113. umap/static/umap/locale/ja.json +19 -8
  114. umap/static/umap/locale/ko.js +19 -8
  115. umap/static/umap/locale/ko.json +19 -8
  116. umap/static/umap/locale/lt.js +19 -8
  117. umap/static/umap/locale/lt.json +19 -8
  118. umap/static/umap/locale/ms.js +20 -9
  119. umap/static/umap/locale/ms.json +20 -9
  120. umap/static/umap/locale/nl.js +20 -9
  121. umap/static/umap/locale/nl.json +20 -9
  122. umap/static/umap/locale/no.js +19 -8
  123. umap/static/umap/locale/no.json +19 -8
  124. umap/static/umap/locale/pl.js +56 -45
  125. umap/static/umap/locale/pl.json +56 -45
  126. umap/static/umap/locale/pl_PL.json +19 -8
  127. umap/static/umap/locale/pt.js +20 -9
  128. umap/static/umap/locale/pt.json +20 -9
  129. umap/static/umap/locale/pt_BR.js +19 -8
  130. umap/static/umap/locale/pt_BR.json +19 -8
  131. umap/static/umap/locale/pt_PT.js +19 -8
  132. umap/static/umap/locale/pt_PT.json +19 -8
  133. umap/static/umap/locale/ro.js +19 -8
  134. umap/static/umap/locale/ro.json +19 -8
  135. umap/static/umap/locale/ru.js +19 -8
  136. umap/static/umap/locale/ru.json +19 -8
  137. umap/static/umap/locale/si.js +1 -1
  138. umap/static/umap/locale/si.json +1 -1
  139. umap/static/umap/locale/sk_SK.js +19 -8
  140. umap/static/umap/locale/sk_SK.json +19 -8
  141. umap/static/umap/locale/sl.js +19 -8
  142. umap/static/umap/locale/sl.json +19 -8
  143. umap/static/umap/locale/sr.js +19 -8
  144. umap/static/umap/locale/sr.json +19 -8
  145. umap/static/umap/locale/sv.js +19 -8
  146. umap/static/umap/locale/sv.json +19 -8
  147. umap/static/umap/locale/th_TH.js +19 -8
  148. umap/static/umap/locale/th_TH.json +19 -8
  149. umap/static/umap/locale/tr.js +19 -8
  150. umap/static/umap/locale/tr.json +19 -8
  151. umap/static/umap/locale/uk_UA.js +19 -8
  152. umap/static/umap/locale/uk_UA.json +19 -8
  153. umap/static/umap/locale/vi.js +19 -8
  154. umap/static/umap/locale/vi.json +19 -8
  155. umap/static/umap/locale/vi_VN.json +19 -8
  156. umap/static/umap/locale/zh.js +19 -8
  157. umap/static/umap/locale/zh.json +19 -8
  158. umap/static/umap/locale/zh_CN.json +19 -8
  159. umap/static/umap/locale/zh_TW.Big5.json +19 -8
  160. umap/static/umap/locale/zh_TW.js +53 -42
  161. umap/static/umap/locale/zh_TW.json +53 -42
  162. umap/static/umap/map.css +8 -7
  163. umap/static/umap/unittests/utils.js +7 -7
  164. umap/templates/umap/content_footer.html +1 -0
  165. umap/templates/umap/css.html +0 -2
  166. umap/templates/umap/js.html +1 -3
  167. umap/templates/umap/login_popup_end.html +2 -2
  168. umap/tests/integration/conftest.py +11 -2
  169. umap/tests/integration/test_anonymous_owned_map.py +2 -2
  170. umap/tests/integration/test_conditional_rules.py +107 -52
  171. umap/tests/integration/test_draw_polygon.py +4 -0
  172. umap/tests/integration/test_draw_polyline.py +11 -0
  173. umap/tests/integration/test_edit_datalayer.py +1 -1
  174. umap/tests/integration/test_fields.py +19 -0
  175. umap/tests/integration/test_filters.py +6 -7
  176. umap/tests/integration/test_iframe.py +1 -1
  177. umap/tests/integration/test_import.py +23 -0
  178. umap/tests/integration/test_map.py +2 -2
  179. umap/tests/integration/test_map_preview.py +1 -1
  180. umap/tests/integration/test_owned_map.py +2 -2
  181. umap/tests/integration/test_picto.py +1 -1
  182. umap/tests/integration/test_popup.py +31 -0
  183. umap/tests/integration/test_remote_data.py +4 -4
  184. umap/tests/integration/test_save.py +1 -1
  185. umap/tests/integration/test_search.py +41 -0
  186. umap/tests/integration/test_share.py +2 -2
  187. umap/tests/integration/test_team.py +1 -1
  188. umap/tests/integration/test_websocket_sync.py +69 -20
  189. umap/tests/test_dashboard.py +1 -1
  190. umap/tests/test_statics.py +2 -2
  191. umap/tests/test_utils.py +4 -1
  192. umap/tests/test_views.py +1 -1
  193. umap/utils.py +3 -2
  194. {umap_project-3.4.0b1.dist-info → umap_project-3.4.2.dist-info}/METADATA +17 -17
  195. {umap_project-3.4.0b1.dist-info → umap_project-3.4.2.dist-info}/RECORD +198 -199
  196. umap/static/umap/js/umap.core.js +0 -93
  197. umap/static/umap/vendors/editinosm/Leaflet.EditInOSM.css +0 -46
  198. umap/static/umap/vendors/editinosm/Leaflet.EditInOSM.js +0 -240
  199. umap/static/umap/vendors/editinosm/edit-in-osm.png +0 -0
  200. {umap_project-3.4.0b1.dist-info → umap_project-3.4.2.dist-info}/WHEEL +0 -0
  201. {umap_project-3.4.0b1.dist-info → umap_project-3.4.2.dist-info}/entry_points.txt +0 -0
  202. {umap_project-3.4.0b1.dist-info → umap_project-3.4.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,4 +1,4 @@
1
- import { Control } from '../../../vendors/leaflet/leaflet-src.esm.js'
1
+ import { Control, LayerGroup } from '../../../vendors/leaflet/leaflet-src.esm.js'
2
2
  import * as Utils from '../utils.js'
3
3
  import { translate } from '../i18n.js'
4
4
 
@@ -112,7 +112,9 @@ export const PermanentCreditsControl = Control.extend({
112
112
  const container = Utils.loadTemplate(
113
113
  `<div class="umap-permanent-credits-container text">${Utils.toHTML(map.options.permanentCredit)}</div>`
114
114
  )
115
- const background = map.options.permanentCreditBackground ? '#FFFFFFB0' : ''
115
+ const background = map._umap.getProperty('permanentCreditBackground')
116
+ ? '#FFFFFFB0'
117
+ : ''
116
118
  container.style.backgroundColor = background
117
119
  return container
118
120
  },
@@ -164,7 +166,7 @@ export const DataLayersControl = BaseButton.extend({
164
166
  },
165
167
 
166
168
  afterAdd: function (container) {
167
- Utils.toggleBadge(container, this._umap.browser?.hasFilters())
169
+ Utils.toggleBadge(container, this._umap.browser?.hasActiveFilters())
168
170
  },
169
171
 
170
172
  onClick: function () {
@@ -219,7 +221,7 @@ export const SearchControl = BaseButton.extend({
219
221
  },
220
222
 
221
223
  afterAdd(container, map) {
222
- this.layer = L.layerGroup().addTo(map)
224
+ this.layer = new LayerGroup().addTo(map)
223
225
  this.photonOptions = {
224
226
  limit: 10,
225
227
  noResultLabel: translate('No results'),
@@ -237,14 +237,7 @@ const Ball = DefaultIcon.extend({
237
237
  _setIconStyles: function (img, name) {
238
238
  BaseIcon.prototype._setIconStyles.call(this, img, name)
239
239
  const color = this._getColor('color')
240
- let background
241
- if (L.Browser.ielt9) {
242
- background = color
243
- } else if (L.Browser.webkit) {
244
- background = `-webkit-gradient( radial, 6 38%, 0, 6 38%, 8, from(white), to(${color}) )`
245
- } else {
246
- background = `radial-gradient(circle at 6px 38% , white -4px, ${color} 8px) repeat scroll 0 0 transparent`
247
- }
240
+ const background = `radial-gradient(circle at 6px 38% , white -4px, ${color} 8px) repeat scroll 0 0 transparent`
248
241
  this.elements.ball.style.background = background
249
242
  this.elements.ball.style.opacity = this._getOpacity()
250
243
  },
@@ -309,5 +302,8 @@ export function setContrast(icon, parent, src, bgcolor) {
309
302
  }
310
303
 
311
304
  export function formatUrl(url, feature) {
312
- return Utils.greedyTemplate(url || '', feature ? feature.extendedProperties() : {})
305
+ if (Utils.hasVar(url)) {
306
+ return Utils.greedyTemplate(url || '', feature ? feature.extendedProperties() : {})
307
+ }
308
+ return url
313
309
  }
@@ -53,7 +53,7 @@ export const LayerMixin = {
53
53
  },
54
54
 
55
55
  onZoomEnd() {
56
- if (!this.datalayer.autoLoaded) return
56
+ if (!this.datalayer.autoVisibility) return
57
57
  if (!this.datalayer.showAtZoom() && this.datalayer.isVisible()) {
58
58
  this.datalayer.hide()
59
59
  }
@@ -1,5 +1,5 @@
1
1
  import colorbrewer from '../../../../vendors/colorbrewer/colorbrewer.js'
2
- import { DomUtil, FeatureGroup } from '../../../../vendors/leaflet/leaflet-src.esm.js'
2
+ import { FeatureGroup } from '../../../../vendors/leaflet/leaflet-src.esm.js'
3
3
  import { translate } from '../../i18n.js'
4
4
  import * as Utils from '../../utils.js'
5
5
  import * as DOMUtils from '../../domutils.js'
@@ -7,7 +7,7 @@ import { CircleMarker } from '../ui.js'
7
7
  import { LayerMixin } from './base.js'
8
8
 
9
9
  // Layer where each feature color is relative to the others,
10
- // so we need all features before behing able to set one
10
+ // so we need all features before being able to set one
11
11
  // feature layer
12
12
  const ClassifiedMixin = {
13
13
  initialize: function (datalayer) {
@@ -346,7 +346,8 @@ export const Circles = FeatureGroup.extend({
346
346
  },
347
347
 
348
348
  renderLegend: function (container) {
349
- const parent = DomUtil.create('ul', 'circles-layer-legend', container)
349
+ const parent = DOMUtils.loadTemplate('<ul class="circles-layer-legend"></ul>')
350
+ container.appendChild(parent)
350
351
  const color = this.datalayer.getProperty('color')
351
352
  const values = this.getValues()
352
353
  if (!values.length) return
@@ -360,14 +361,18 @@ export const Circles = FeatureGroup.extend({
360
361
  [this.options.maxPX, maxValue],
361
362
  ]
362
363
  for (const [size, label] of items) {
363
- const li = DomUtil.create('li', '', parent)
364
- const circleEl = DomUtil.create('span', 'circle', li)
365
- circleEl.style.backgroundColor = color
366
- circleEl.style.height = `${size * 2}px`
367
- circleEl.style.width = `${size * 2}px`
368
- circleEl.style.opacity = this.datalayer.getProperty('opacity')
369
- const labelEl = DomUtil.create('span', 'label', li)
370
- labelEl.textContent = label
364
+ parent.appendChild(
365
+ DOMUtils.loadTemplate(`
366
+ <li>
367
+ <span class="circle"
368
+ style="background-color: ${color};
369
+ height: ${size * 2}px;
370
+ width: ${size * 2}px;
371
+ opacity: ${this.datalayer.getProperty('fillOpacity')};"></span>
372
+ <span class="label">${label}</span>
373
+ </li>
374
+ `)
375
+ )
371
376
  }
372
377
  },
373
378
  })
@@ -68,27 +68,32 @@ export const Heat = L.HeatLayer.extend({
68
68
  return latLngBounds(this._latlngs)
69
69
  },
70
70
 
71
- getEditableProperties: () => [
72
- [
73
- 'properties.heat.radius',
74
- {
75
- handler: 'Range',
76
- min: 10,
77
- max: 100,
78
- step: 5,
79
- label: translate('Heatmap radius'),
80
- helpText: translate('Override heatmap radius (default 25)'),
81
- },
82
- ],
83
- [
84
- 'properties.heat.intensityProperty',
85
- {
86
- handler: 'BlurInput',
87
- placeholder: translate('Heatmap intensity property'),
88
- helpText: translate('Optional intensity property for heatmap'),
89
- },
90
- ],
91
- ],
71
+ getEditableProperties: function () {
72
+ return [
73
+ [
74
+ 'properties.heat.radius',
75
+ {
76
+ handler: 'Range',
77
+ min: 10,
78
+ max: 100,
79
+ step: 5,
80
+ label: translate('Heatmap radius'),
81
+ helpText: translate('Override heatmap radius (default 25)'),
82
+ },
83
+ ],
84
+ [
85
+ 'properties.heat.intensityProperty',
86
+ {
87
+ handler: 'Select',
88
+ selectOptions: [
89
+ ['', translate('Select field to compute intensity')],
90
+ ...this.datalayer.fields.keys(),
91
+ ],
92
+ helpText: translate('Optional intensity field to compute heatmap'),
93
+ },
94
+ ],
95
+ ]
96
+ },
92
97
 
93
98
  onEdit: function (field, builder) {
94
99
  if (field === 'properties.heat.intensityProperty') {
@@ -97,6 +102,7 @@ export const Heat = L.HeatLayer.extend({
97
102
  }
98
103
  if (field === 'properties.heat.radius') {
99
104
  this.options.radius = this.datalayer.properties.heat.radius
105
+ this.redraw()
100
106
  }
101
107
  this._updateOptions()
102
108
  },
@@ -1,12 +1,14 @@
1
1
  // Goes here all code related to Leaflet, DOM and user interactions.
2
2
  import {
3
3
  Map as BaseMap,
4
+ Browser,
4
5
  Control,
5
6
  DomEvent,
6
- DomUtil,
7
7
  latLng,
8
- latLngBounds,
8
+ LatLng,
9
+ LatLngBounds,
9
10
  setOptions,
11
+ TileLayer,
10
12
  } from '../../../vendors/leaflet/leaflet-src.esm.js'
11
13
  import { uMapAlert as Alert } from '../../components/alerts/alert.js'
12
14
  import DropControl from '../drop.js'
@@ -46,7 +48,6 @@ const ControlsMixin = {
46
48
  'caption',
47
49
  'locate',
48
50
  'measure',
49
- 'editinosm',
50
51
  'print',
51
52
  'tilelayers',
52
53
  ],
@@ -91,17 +92,9 @@ const ControlsMixin = {
91
92
  this._controls.embed = new EmbedControl(this._umap)
92
93
  this._controls.print = new PrintControl(this._umap)
93
94
  this._controls.tilelayersChooser = new TileLayerChooser(this._umap)
94
- this._controls.editinosm = new Control.EditInOSM({
95
- position: 'topleft',
96
- widgetOptions: {
97
- helpText: translate(
98
- 'Open this map extent in a map editor to provide more accurate data to OpenStreetMap'
99
- ),
100
- },
101
- })
102
95
  this._controls.measure = new L.MeasureControl().initHandler(this)
103
96
  this._controls.more = new MoreControl()
104
- this._controls.scale = L.control.scale()
97
+ this._controls.scale = new Control.Scale()
105
98
  this._controls.permanentCredit = new PermanentCreditsControl(this)
106
99
  this._umap.drop = new DropControl(this._umap, this, this._container)
107
100
  this._controls.tilelayers = new U.TileLayerControl(this)
@@ -138,11 +131,10 @@ const ControlsMixin = {
138
131
  const control = this._controls[name]
139
132
  if (!control) continue
140
133
  control.addTo(this)
141
- if (status === undefined || status === null) {
142
- DomUtil.addClass(control._container, 'display-on-more')
143
- } else {
144
- DomUtil.removeClass(control._container, 'display-on-more')
145
- }
134
+ control._container.classList.toggle(
135
+ 'display-on-more',
136
+ status === undefined || status === null
137
+ )
146
138
  }
147
139
  if (this._umap.getProperty('permanentCredit'))
148
140
  this._controls.permanentCredit.addTo(this)
@@ -176,7 +168,7 @@ const ManageTilelayerMixin = {
176
168
  if (this._controls) this._controls.tilelayers.setLayers()
177
169
  },
178
170
 
179
- createTileLayer: (tilelayer) => new L.TileLayer(tilelayer.url_template, tilelayer),
171
+ createTileLayer: (tilelayer) => new TileLayer(tilelayer.url_template, tilelayer),
180
172
 
181
173
  selectTileLayer: function (tilelayer) {
182
174
  if (tilelayer === this.selectedTilelayer) {
@@ -303,7 +295,7 @@ export const LeafletMap = BaseMap.extend({
303
295
  // when scrolling the main page and touching the
304
296
  // map in an iframe. May be a bit dumb, but let's
305
297
  // try like this for now.
306
- if (L.Browser.mobile) this.dragging.disable()
298
+ if (Browser.mobile) this.dragging.disable()
307
299
  }
308
300
  // Needs tilelayer to exist for minimap
309
301
  this.renderControls()
@@ -312,7 +304,7 @@ export const LeafletMap = BaseMap.extend({
312
304
 
313
305
  latLng: (a, b, c) => {
314
306
  // manage geojson case and call original method
315
- if (!(a instanceof L.LatLng) && a.coordinates) {
307
+ if (!(a instanceof LatLng) && a.coordinates) {
316
308
  // Guess it's a geojson
317
309
  a = [a.coordinates[1], a.coordinates[0]]
318
310
  }
@@ -361,7 +353,7 @@ export const LeafletMap = BaseMap.extend({
361
353
  !Number.isNaN(north) &&
362
354
  !Number.isNaN(east)
363
355
  ) {
364
- const bounds = latLngBounds([
356
+ const bounds = new LatLngBounds([
365
357
  [south, west],
366
358
  [north, east],
367
359
  ])
@@ -381,7 +373,7 @@ export const LeafletMap = BaseMap.extend({
381
373
  setMaxBounds: function (bounds) {
382
374
  // Hack. Remove me when fix is released:
383
375
  // https://github.com/Leaflet/Leaflet/pull/4494
384
- bounds = latLngBounds(bounds)
376
+ bounds = new LatLngBounds(bounds)
385
377
 
386
378
  if (!bounds.isValid()) {
387
379
  this.options.maxBounds = null
@@ -390,6 +382,14 @@ export const LeafletMap = BaseMap.extend({
390
382
  return BaseMap.prototype.setMaxBounds.call(this, bounds)
391
383
  },
392
384
 
385
+ getLayersBounds: (layers) => {
386
+ const bounds = new LatLngBounds()
387
+ for (const layer of layers) {
388
+ bounds.extend(layer.getBounds())
389
+ }
390
+ return bounds
391
+ },
392
+
393
393
  initEditTools: function () {
394
394
  this.editTools = new U.Editable(this._umap)
395
395
  },
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  Popup as BasePopup,
3
3
  DomEvent,
4
- DomUtil,
5
4
  Path,
6
5
  } from '../../../vendors/leaflet/leaflet-src.esm.js'
7
6
  import Browser from '../browser.js'
8
7
  import loadTemplate from './template.js'
8
+ import * as DOMUtils from '../domutils.js'
9
9
 
10
10
  export default function loadPopup(name) {
11
11
  switch (name) {
@@ -25,7 +25,8 @@ const Popup = BasePopup.extend({
25
25
  },
26
26
 
27
27
  loadContent: async function () {
28
- const container = DomUtil.create('div', 'umap-popup')
28
+ const container = document.createElement('div')
29
+ container.classList.add('umap-popup')
29
30
  const name = this.feature.getOption('popupTemplate')
30
31
  this.content = await loadTemplate(name, this.feature, container)
31
32
  const elements = container.querySelectorAll('img,iframe')
@@ -34,7 +35,9 @@ const Popup = BasePopup.extend({
34
35
  }
35
36
  if (!elements.length && container.textContent.replace('\n', '') === '') {
36
37
  container.innerHTML = ''
37
- DomUtil.add('h3', '', container, this.feature.getDisplayName())
38
+ container.appendChild(
39
+ DOMUtils.loadTemplate(`<h3>${this.feature.getDisplayName()}</h3>`)
40
+ )
38
41
  }
39
42
  this.setContent(container)
40
43
  },
@@ -1,8 +1,4 @@
1
- import {
2
- DomEvent,
3
- DomUtil,
4
- CircleMarker,
5
- } from '../../../vendors/leaflet/leaflet-src.esm.js'
1
+ import { DomEvent, CircleMarker } from '../../../vendors/leaflet/leaflet-src.esm.js'
6
2
  import { getLocale, translate } from '../i18n.js'
7
3
  import { Request } from '../request.js'
8
4
  import * as Utils from '../utils.js'
@@ -92,7 +88,11 @@ class PopupTemplate {
92
88
  const title = this.renderTitle(feature)
93
89
  if (title) container.appendChild(title)
94
90
  const body = await this.renderBody(feature)
95
- if (body) DomUtil.add('div', 'umap-popup-content', container, body)
91
+ if (body) {
92
+ const div = DOMUtils.loadTemplate('<div class="umap-popup-content"></div>')
93
+ div.appendChild(body)
94
+ container.appendChild(div)
95
+ }
96
96
  const footer = this.renderFooter(feature)
97
97
  if (footer) container.appendChild(footer)
98
98
  }
@@ -108,29 +108,20 @@ export const TitleMixin = (Base) =>
108
108
  }
109
109
 
110
110
  class Table extends TitleMixin(PopupTemplate) {
111
- getValue(feature, key) {
112
- // TODO, manage links (url, mailto, wikipedia...)
113
- const value = Utils.escapeHTML(feature.properties[key]).trim()
114
- if (value.indexOf('http') === 0) {
115
- return `<a href="${value}" target="_blank">${value}</a>`
116
- }
117
- return value
118
- }
119
-
120
- makeRow(feature, key) {
111
+ makeRow(feature, field) {
121
112
  return Utils.loadTemplate(
122
- `<tr><th>${key}</th><td>${this.getValue(feature, key)}</td></tr>`
113
+ `<tr><th>${field.key}</th><td>${field.render(feature.properties[field.key])}</td></tr>`
123
114
  )
124
115
  }
125
116
 
126
117
  async renderBody(feature) {
127
118
  const table = document.createElement('table')
128
119
 
129
- for (const key in feature.properties) {
130
- if (typeof feature.properties[key] === 'object' || U.LABEL_KEYS.includes(key)) {
120
+ for (const field of feature.fields) {
121
+ if (U.LABEL_KEYS.includes(field.key)) {
131
122
  continue
132
123
  }
133
- table.appendChild(this.makeRow(feature, key))
124
+ table.appendChild(this.makeRow(feature, field))
134
125
  }
135
126
  return table
136
127
  }
@@ -138,16 +129,17 @@ class Table extends TitleMixin(PopupTemplate) {
138
129
 
139
130
  class GeoRSSImage extends TitleMixin(PopupTemplate) {
140
131
  async renderBody(feature) {
141
- const body = DomUtil.create('a')
142
- body.href = feature.properties.link
143
- body.target = '_blank'
132
+ const body = DOMUtils.loadTemplate(
133
+ `<a href="${feature.properties.link}" target="_blank"></a>`
134
+ )
144
135
  if (feature.properties.img) {
145
- const img = DomUtil.create('img', '', body)
146
- img.src = feature.properties.img
147
136
  // Sadly, we are unable to override this from JS the clean way
148
137
  // See https://github.com/Leaflet/Leaflet/commit/61d746818b99d362108545c151a27f09d60960ee#commitcomment-6061847
149
- img.style.maxWidth = '500px'
150
- img.style.maxHeight = '500px'
138
+ body.appendChild(
139
+ DOMUtils.loadTemplate(
140
+ `<img src=${feature.properties.img} style="max-width: 500px; max-height: 500px;">`
141
+ )
142
+ )
151
143
  }
152
144
  return body
153
145
  }
@@ -165,15 +157,16 @@ class GeoRSSLink extends PopupTemplate {
165
157
 
166
158
  class OSM extends PopupTemplate {
167
159
  renderTitle(feature) {
168
- const title = DomUtil.add('h3', 'popup-title')
169
160
  const color = feature.getPreviewColor()
170
- title.style.backgroundColor = color
161
+ const [title, { iconContainer }] = DOMUtils.loadTemplateWithRefs(`
162
+ <h3 class="popup-title" style="background-color: ${color};">
163
+ <span data-ref="iconContainer"></span> ${this.getName(feature)}
164
+ </h3>`)
171
165
  const iconUrl = feature.getDynamicOption('iconUrl')
172
- const icon = Icon.makeElement(iconUrl, title)
173
- DomUtil.addClass(icon, 'icon')
166
+ const icon = Icon.makeElement(iconUrl, iconContainer)
167
+ icon.classList.add('icon')
174
168
  Icon.setContrast(icon, title, iconUrl, color)
175
169
  if (DOMUtils.contrastedColor(title, color)) title.style.color = 'white'
176
- DomUtil.add('span', '', title, this.getName(feature))
177
170
  return title
178
171
  }
179
172
 
@@ -190,15 +183,16 @@ class OSM extends PopupTemplate {
190
183
  const locale = getLocale()
191
184
  const street = props['addr:street']
192
185
  if (street) {
193
- const row = DomUtil.add('address', 'address', body)
194
186
  const number = props['addr:housenumber']
187
+ let content
195
188
  if (number) {
196
- // Poor way to deal with international forms of writting addresses
197
- DomUtil.add('span', '', row, `${translate('No.')}: ${number}`)
198
- DomUtil.add('span', '', row, `${translate('Street')}: ${street}`)
189
+ // Poor way to deal with international forms of writing addresses
190
+ content = `<span>${translate('')}: ${number}</span><span>${translate('Street')}: ${street}</span>`
199
191
  } else {
200
- DomUtil.add('span', '', row, street)
192
+ content = street
201
193
  }
194
+ const row = DOMUtils.loadTemplate(`<address class="address">${content}</address>`)
195
+ body.appendChild(row)
202
196
  }
203
197
  if (props.website) {
204
198
  body.appendChild(
@@ -2,7 +2,6 @@
2
2
  import {
3
3
  CircleMarker as BaseCircleMarker,
4
4
  DomEvent,
5
- DomUtil,
6
5
  GeoJSON,
7
6
  LatLng,
8
7
  LatLngBounds,
@@ -314,7 +313,7 @@ const PathMixin = {
314
313
  this.enableEdit()
315
314
  } else {
316
315
  this._map._umap.tooltip.open({
317
- content: L._('Please zoom in to edit the geometry'),
316
+ content: translate('Please zoom in to edit the geometry'),
318
317
  })
319
318
  this.disableEdit()
320
319
  }
@@ -6,6 +6,7 @@ import Orderable from './orderable.js'
6
6
  import * as Utils from './utils.js'
7
7
  import * as Icon from './rendering/icon.js'
8
8
  import { SCHEMA } from './schema.js'
9
+ import { Registry as Fields } from './data/fields.js'
9
10
 
10
11
  const EMPTY_VALUES = ['', undefined, null]
11
12
 
@@ -28,12 +29,12 @@ class Rule {
28
29
  // cf https://caniuse.com/?search=public%20class%20field
29
30
  this._condition = null
30
31
  this.OPERATORS = [
31
- ['>', this.gt],
32
- ['<', this.lt],
32
+ ['>', 'gt'],
33
+ ['<', 'lt'],
33
34
  // When sent by Django
34
- ['&lt;', this.lt],
35
- ['!=', this.not_equal],
36
- ['=', this.equal],
35
+ ['&lt;', 'lt'],
36
+ ['!=', 'not_equal'],
37
+ ['=', 'equal'],
37
38
  ]
38
39
  this.parent = parent
39
40
  this._umap = umap
@@ -47,58 +48,47 @@ class Rule {
47
48
  this.parent.render(fields)
48
49
  }
49
50
 
50
- equal(other) {
51
- return this.expected === other
52
- }
53
-
54
- not_equal(other) {
55
- return this.expected !== other
56
- }
57
-
58
- gt(other) {
59
- return other > this.expected
60
- }
61
-
62
- lt(other) {
63
- return other < this.expected
64
- }
65
-
66
51
  parse() {
67
52
  let vars = []
68
53
  this.cast = (v) => v
69
54
  this.operator = undefined
70
- for (const [sign, func] of this.OPERATORS) {
55
+ let operator = undefined
56
+ for (const [sign, funcName] of this.OPERATORS) {
71
57
  if (this.condition.includes(sign)) {
72
- this.operator = func
58
+ operator = funcName
73
59
  vars = this.condition.split(sign)
74
60
  break
75
61
  }
76
62
  }
77
63
  if (vars.length !== 2) return
78
- this.key = vars[0]
64
+ this.field = this.parent.fields.get(vars[0]) || new Fields.String(vars[0])
65
+ this.operator = this.field[operator]
79
66
  this.expected = vars[1]
80
67
  if (EMPTY_VALUES.includes(this.expected)) {
81
68
  this.cast = (v) => EMPTY_VALUES.includes(v)
82
69
  }
83
- // Special cases where we want to be lousy when checking isNaN without
84
- // coercing to a Number first because we handle multiple types.
85
- // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/
86
- // Reference/Global_Objects/Number/isNaN
87
- // biome-ignore lint/suspicious/noGlobalIsNan: expected might not be a number.
88
- else if (!isNaN(this.expected)) {
89
- this.cast = Number.parseFloat
90
- } else if (['true', 'false'].includes(this.expected)) {
91
- this.cast = (v) => {
92
- if (`${v}`.toLowerCase() === 'true') return true
93
- if (`${v}`.toLowerCase() === 'false') return false
70
+ // TODO: deal with legacy rules on non typed fields
71
+ else {
72
+ this.cast = this.field.parse
73
+ if (
74
+ // Special cases where we want to be lousy when checking isNaN without
75
+ // coercing to a Number first because we handle multiple types.
76
+ // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/
77
+ // Reference/Global_Objects/Number/isNaN
78
+ // biome-ignore lint/suspicious/noGlobalIsNan: expected might not be a number.
79
+ !isNaN(this.expected) &&
80
+ ['gt', 'lt'].includes(operator) &&
81
+ this.field.TYPE !== 'Number'
82
+ ) {
83
+ this.cast = Number.parseFloat
94
84
  }
95
85
  }
96
86
  this.expected = this.cast(this.expected)
97
87
  }
98
88
 
99
89
  match(props) {
100
- if (!this.operator || !this.active) return false
101
- return this.operator(this.cast(props[this.key]))
90
+ if (!this.operator || !this.active || !this.field) return false
91
+ return this.operator(this.expected, this.cast(props[this.field.key]))
102
92
  }
103
93
 
104
94
  getOption(option) {
@@ -118,6 +108,7 @@ class Rule {
118
108
  'name',
119
109
  'properties.color',
120
110
  'properties.iconClass',
111
+ 'properties.iconSize',
121
112
  'properties.iconUrl',
122
113
  'properties.iconOpacity',
123
114
  'properties.opacity',
@@ -132,7 +123,7 @@ class Rule {
132
123
  const container = document.createElement('div')
133
124
  container.appendChild(builder.build())
134
125
  const autocomplete = new AutocompleteDatalist(builder.helpers.condition.input)
135
- const properties = this.parent.fieldKeys
126
+ const properties = Array.from(this.parent.fields.keys())
136
127
  autocomplete.suggestions = properties
137
128
  autocomplete.input.addEventListener('input', (event) => {
138
129
  const value = event.target.value
@@ -140,9 +131,11 @@ class Rule {
140
131
  autocomplete.suggestions = [`${value}=`, `${value}!=`, `${value}>`, `${value}<`]
141
132
  } else if (value.endsWith('=')) {
142
133
  const key = value.split('!')[0].split('=')[0]
143
- autocomplete.suggestions = this.parent
144
- .sortedValues(key)
145
- .map((str) => `${value}${str ?? ''}`)
134
+ if (key) {
135
+ autocomplete.suggestions = this.parent
136
+ .sortedValues(key)
137
+ .map((str) => `${value}${str ?? ''}`)
138
+ }
146
139
  }
147
140
  })
148
141
  const backButton = Utils.loadTemplate(`
@@ -123,13 +123,6 @@ export const SCHEMA = {
123
123
  edit_status: {
124
124
  type: Number,
125
125
  },
126
- editinosmControl: {
127
- type: Boolean,
128
- impacts: ['ui'],
129
- nullable: true,
130
- label: translate('Display the control to open OpenStreetMap editor'),
131
- default: null,
132
- },
133
126
  editors: {
134
127
  type: Array,
135
128
  },