umap-project 3.4.0b3__py3-none-any.whl → 3.6.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.
Files changed (222) hide show
  1. umap/__init__.py +1 -1
  2. umap/locale/br/LC_MESSAGES/django.mo +0 -0
  3. umap/locale/br/LC_MESSAGES/django.po +71 -57
  4. umap/locale/da/LC_MESSAGES/django.mo +0 -0
  5. umap/locale/da/LC_MESSAGES/django.po +18 -14
  6. umap/locale/de/LC_MESSAGES/django.mo +0 -0
  7. umap/locale/de/LC_MESSAGES/django.po +20 -16
  8. umap/locale/en/LC_MESSAGES/django.po +18 -14
  9. umap/locale/es/LC_MESSAGES/django.mo +0 -0
  10. umap/locale/es/LC_MESSAGES/django.po +20 -16
  11. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  12. umap/locale/fr/LC_MESSAGES/django.po +18 -14
  13. umap/locale/hu/LC_MESSAGES/django.mo +0 -0
  14. umap/locale/hu/LC_MESSAGES/django.po +20 -16
  15. umap/locale/pl/LC_MESSAGES/django.mo +0 -0
  16. umap/locale/pl/LC_MESSAGES/django.po +101 -95
  17. umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
  18. umap/locale/zh_TW/LC_MESSAGES/django.po +20 -16
  19. umap/management/commands/clean_tilelayer.py +0 -1
  20. umap/management/commands/search_maps.py +95 -0
  21. umap/settings/__init__.py +9 -1
  22. umap/settings/base.py +7 -6
  23. umap/static/umap/content.css +0 -3
  24. umap/static/umap/css/bar.css +9 -6
  25. umap/static/umap/css/form.css +25 -9
  26. umap/static/umap/css/icon.css +8 -0
  27. umap/static/umap/css/popup.css +1 -0
  28. umap/static/umap/img/16-white.svg +5 -2
  29. umap/static/umap/img/16.svg +1 -1
  30. umap/static/umap/img/source/16-white.svg +7 -4
  31. umap/static/umap/img/source/16.svg +1 -1
  32. umap/static/umap/js/components/copiable.js +47 -0
  33. umap/static/umap/js/modules/autocomplete.js +32 -67
  34. umap/static/umap/js/modules/browser.js +31 -14
  35. umap/static/umap/js/modules/data/features.js +34 -36
  36. umap/static/umap/js/modules/data/fields.js +199 -23
  37. umap/static/umap/js/modules/data/layer.js +85 -96
  38. umap/static/umap/js/modules/domutils.js +25 -1
  39. umap/static/umap/js/modules/filters.js +24 -50
  40. umap/static/umap/js/modules/form/builder.js +17 -16
  41. umap/static/umap/js/modules/form/fields.js +20 -20
  42. umap/static/umap/js/modules/formatter.js +9 -1
  43. umap/static/umap/js/modules/help.js +12 -13
  44. umap/static/umap/js/modules/importer.js +17 -26
  45. umap/static/umap/js/modules/importers/banfr.js +0 -1
  46. umap/static/umap/js/modules/importers/cadastrefr.js +19 -19
  47. umap/static/umap/js/modules/importers/communesfr.js +7 -8
  48. umap/static/umap/js/modules/importers/datasets.js +14 -14
  49. umap/static/umap/js/modules/importers/geodatamine.js +20 -22
  50. umap/static/umap/js/modules/importers/opendata.js +10 -0
  51. umap/static/umap/js/modules/importers/overpass.js +19 -18
  52. umap/static/umap/js/modules/managers.js +1 -1
  53. umap/static/umap/js/modules/permissions.js +15 -5
  54. umap/static/umap/js/modules/rendering/controls.js +203 -10
  55. umap/static/umap/js/modules/rendering/icon.js +5 -9
  56. umap/static/umap/js/modules/rendering/layers/base.js +1 -1
  57. umap/static/umap/js/modules/rendering/layers/classified.js +16 -11
  58. umap/static/umap/js/modules/rendering/layers/heat.js +1 -0
  59. umap/static/umap/js/modules/rendering/map.js +67 -57
  60. umap/static/umap/js/modules/rendering/popup.js +6 -3
  61. umap/static/umap/js/modules/rendering/template.js +40 -40
  62. umap/static/umap/js/modules/rendering/ui.js +1 -2
  63. umap/static/umap/js/modules/rules.js +34 -41
  64. umap/static/umap/js/modules/schema.js +0 -7
  65. umap/static/umap/js/modules/share.js +36 -69
  66. umap/static/umap/js/modules/slideshow.js +3 -3
  67. umap/static/umap/js/modules/tableeditor.js +0 -1
  68. umap/static/umap/js/modules/ui/bar.js +53 -33
  69. umap/static/umap/js/modules/ui/hash.js +36 -0
  70. umap/static/umap/js/modules/ui/loader.js +26 -0
  71. umap/static/umap/js/modules/ui/panel.js +33 -21
  72. umap/static/umap/js/modules/ui/tooltip.js +1 -1
  73. umap/static/umap/js/modules/umap.js +81 -80
  74. umap/static/umap/js/modules/utils.js +13 -3
  75. umap/static/umap/js/umap.controls.js +16 -179
  76. umap/static/umap/locale/am_ET.js +7 -8
  77. umap/static/umap/locale/am_ET.json +7 -8
  78. umap/static/umap/locale/ar.js +7 -8
  79. umap/static/umap/locale/ar.json +7 -8
  80. umap/static/umap/locale/ast.js +7 -8
  81. umap/static/umap/locale/ast.json +7 -8
  82. umap/static/umap/locale/bg.js +7 -8
  83. umap/static/umap/locale/bg.json +7 -8
  84. umap/static/umap/locale/br.js +44 -36
  85. umap/static/umap/locale/br.json +44 -36
  86. umap/static/umap/locale/ca.js +7 -8
  87. umap/static/umap/locale/ca.json +7 -8
  88. umap/static/umap/locale/cs_CZ.js +7 -8
  89. umap/static/umap/locale/cs_CZ.json +7 -8
  90. umap/static/umap/locale/da.js +8 -9
  91. umap/static/umap/locale/da.json +8 -9
  92. umap/static/umap/locale/de.js +62 -63
  93. umap/static/umap/locale/de.json +62 -63
  94. umap/static/umap/locale/el.js +7 -8
  95. umap/static/umap/locale/el.json +7 -8
  96. umap/static/umap/locale/en.js +7 -8
  97. umap/static/umap/locale/en.json +7 -8
  98. umap/static/umap/locale/en_US.json +7 -8
  99. umap/static/umap/locale/es.js +19 -20
  100. umap/static/umap/locale/es.json +19 -20
  101. umap/static/umap/locale/et.js +7 -8
  102. umap/static/umap/locale/et.json +7 -8
  103. umap/static/umap/locale/eu.js +23 -24
  104. umap/static/umap/locale/eu.json +23 -24
  105. umap/static/umap/locale/fa_IR.js +7 -8
  106. umap/static/umap/locale/fa_IR.json +7 -8
  107. umap/static/umap/locale/fi.js +7 -8
  108. umap/static/umap/locale/fi.json +7 -8
  109. umap/static/umap/locale/fr.js +11 -12
  110. umap/static/umap/locale/fr.json +11 -12
  111. umap/static/umap/locale/gl.js +147 -148
  112. umap/static/umap/locale/gl.json +147 -148
  113. umap/static/umap/locale/he.js +7 -8
  114. umap/static/umap/locale/he.json +7 -8
  115. umap/static/umap/locale/hr.js +7 -8
  116. umap/static/umap/locale/hr.json +7 -8
  117. umap/static/umap/locale/hu.js +8 -9
  118. umap/static/umap/locale/hu.json +8 -9
  119. umap/static/umap/locale/id.js +7 -8
  120. umap/static/umap/locale/id.json +7 -8
  121. umap/static/umap/locale/is.js +7 -8
  122. umap/static/umap/locale/is.json +7 -8
  123. umap/static/umap/locale/it.js +7 -8
  124. umap/static/umap/locale/it.json +7 -8
  125. umap/static/umap/locale/ja.js +7 -8
  126. umap/static/umap/locale/ja.json +7 -8
  127. umap/static/umap/locale/ko.js +7 -8
  128. umap/static/umap/locale/ko.json +7 -8
  129. umap/static/umap/locale/lt.js +7 -8
  130. umap/static/umap/locale/lt.json +7 -8
  131. umap/static/umap/locale/ms.js +7 -8
  132. umap/static/umap/locale/ms.json +7 -8
  133. umap/static/umap/locale/nl.js +7 -8
  134. umap/static/umap/locale/nl.json +7 -8
  135. umap/static/umap/locale/no.js +7 -8
  136. umap/static/umap/locale/no.json +7 -8
  137. umap/static/umap/locale/pl.js +53 -54
  138. umap/static/umap/locale/pl.json +53 -54
  139. umap/static/umap/locale/pl_PL.json +7 -8
  140. umap/static/umap/locale/pt.js +7 -8
  141. umap/static/umap/locale/pt.json +7 -8
  142. umap/static/umap/locale/pt_BR.js +7 -8
  143. umap/static/umap/locale/pt_BR.json +7 -8
  144. umap/static/umap/locale/pt_PT.js +7 -8
  145. umap/static/umap/locale/pt_PT.json +7 -8
  146. umap/static/umap/locale/ro.js +7 -8
  147. umap/static/umap/locale/ro.json +7 -8
  148. umap/static/umap/locale/ru.js +7 -8
  149. umap/static/umap/locale/ru.json +7 -8
  150. umap/static/umap/locale/sk_SK.js +7 -8
  151. umap/static/umap/locale/sk_SK.json +7 -8
  152. umap/static/umap/locale/sl.js +7 -8
  153. umap/static/umap/locale/sl.json +7 -8
  154. umap/static/umap/locale/sr.js +7 -8
  155. umap/static/umap/locale/sr.json +7 -8
  156. umap/static/umap/locale/sv.js +7 -8
  157. umap/static/umap/locale/sv.json +7 -8
  158. umap/static/umap/locale/th_TH.js +7 -8
  159. umap/static/umap/locale/th_TH.json +7 -8
  160. umap/static/umap/locale/tr.js +7 -8
  161. umap/static/umap/locale/tr.json +7 -8
  162. umap/static/umap/locale/uk_UA.js +7 -8
  163. umap/static/umap/locale/uk_UA.json +7 -8
  164. umap/static/umap/locale/vi.js +7 -8
  165. umap/static/umap/locale/vi.json +7 -8
  166. umap/static/umap/locale/vi_VN.json +7 -8
  167. umap/static/umap/locale/zh.js +7 -8
  168. umap/static/umap/locale/zh.json +7 -8
  169. umap/static/umap/locale/zh_CN.json +7 -8
  170. umap/static/umap/locale/zh_TW.Big5.json +7 -8
  171. umap/static/umap/locale/zh_TW.js +20 -21
  172. umap/static/umap/locale/zh_TW.json +20 -21
  173. umap/static/umap/map.css +6 -21
  174. umap/static/umap/unittests/utils.js +7 -7
  175. umap/static/umap/vendors/locatecontrol/L.Control.Locate.esm.js +942 -0
  176. umap/static/umap/vendors/photon/leaflet.photon.esm.js +472 -0
  177. umap/sync/app.py +4 -1
  178. umap/templates/umap/content_footer.html +1 -0
  179. umap/templates/umap/css.html +0 -4
  180. umap/templates/umap/js.html +1 -8
  181. umap/templates/umap/team_form.html +2 -1
  182. umap/tests/integration/conftest.py +3 -2
  183. umap/tests/integration/test_anonymous_owned_map.py +1 -1
  184. umap/tests/integration/test_conditional_rules.py +106 -51
  185. umap/tests/integration/test_draw_polygon.py +4 -0
  186. umap/tests/integration/test_draw_polyline.py +11 -0
  187. umap/tests/integration/test_edit_datalayer.py +1 -1
  188. umap/tests/integration/test_edit_map.py +2 -0
  189. umap/tests/integration/test_fields.py +19 -0
  190. umap/tests/integration/test_filters.py +24 -0
  191. umap/tests/integration/test_iframe.py +1 -1
  192. umap/tests/integration/test_import.py +26 -0
  193. umap/tests/integration/test_map.py +3 -3
  194. umap/tests/integration/test_optimistic_merge.py +7 -1
  195. umap/tests/integration/test_owned_map.py +2 -2
  196. umap/tests/integration/test_popup.py +31 -0
  197. umap/tests/integration/test_remote_data.py +5 -5
  198. umap/tests/integration/test_search.py +41 -0
  199. umap/tests/integration/test_share.py +2 -2
  200. umap/tests/integration/test_team.py +1 -1
  201. umap/tests/integration/test_websocket_sync.py +6 -1
  202. umap/tests/test_search_maps_command.py +44 -0
  203. umap/tests/test_utils.py +4 -1
  204. umap/utils.py +10 -3
  205. umap/views.py +17 -4
  206. {umap_project-3.4.0b3.dist-info → umap_project-3.6.0.dist-info}/METADATA +29 -23
  207. {umap_project-3.4.0b3.dist-info → umap_project-3.6.0.dist-info}/RECORD +210 -214
  208. {umap_project-3.4.0b3.dist-info → umap_project-3.6.0.dist-info}/WHEEL +1 -1
  209. umap/static/umap/js/umap.core.js +0 -93
  210. umap/static/umap/vendors/editinosm/Leaflet.EditInOSM.css +0 -46
  211. umap/static/umap/vendors/editinosm/Leaflet.EditInOSM.js +0 -240
  212. umap/static/umap/vendors/editinosm/edit-in-osm.png +0 -0
  213. umap/static/umap/vendors/hash/leaflet-hash.js +0 -162
  214. umap/static/umap/vendors/loading/Control.Loading.css +0 -26
  215. umap/static/umap/vendors/loading/Control.Loading.js +0 -351
  216. umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.css +0 -1
  217. umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.css.map +0 -1
  218. umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.js +0 -4
  219. umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.js.map +0 -1
  220. umap/static/umap/vendors/photon/leaflet.photon.js +0 -487
  221. {umap_project-3.4.0b3.dist-info → umap_project-3.6.0.dist-info}/entry_points.txt +0 -0
  222. {umap_project-3.4.0b3.dist-info → umap_project-3.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -32,7 +32,7 @@ export const copyToClipboard = (textToCopy) => {
32
32
  tooltip.open({ content: translate('✅ Copied!'), duration: 5000 })
33
33
  }
34
34
 
35
- export const copiableInput = (parent, label, value) => {
35
+ export const copiableInput = (parent, label, value = '') => {
36
36
  const [container, { input, button }] = Utils.loadTemplateWithRefs(`
37
37
  <div class="copiable-input">
38
38
  <label>${label}<input type="text" readOnly value="${value}" data-ref=input /></label>
@@ -82,6 +82,10 @@ export const hexToRGB = (hex) => {
82
82
  .match(/.{2}/g)
83
83
  .map((x) => Number.parseInt(x, 16))
84
84
  }
85
+ export const colorToRGB = (color) => {
86
+ if (!color.startsWith('#')) color = colorNameToHex(color)
87
+ return hexToRGB(color)
88
+ }
85
89
 
86
90
  const CACHE_CONTRAST = {}
87
91
  export const contrastedColor = (el, bgcolor) => {
@@ -107,3 +111,23 @@ export const contrastedColor = (el, bgcolor) => {
107
111
  if (bgcolor) CACHE_CONTRAST[bgcolor] = out
108
112
  return out
109
113
  }
114
+
115
+ export const createFieldset = (parent, title, options) => {
116
+ options = options || {}
117
+ const [details, { summary, fieldset }] = loadTemplateWithRefs(`
118
+ <details class="${options.className || ''}">
119
+ <summary data-ref="summary"><h4>${title}</h4></summary>
120
+ <fieldset data-ref="fieldset"></fieldset>
121
+ </details>
122
+ `)
123
+ details.open = options.on === true
124
+ parent.appendChild(details)
125
+ if (options.icon) {
126
+ const icon = loadTemplate(`<i class="icon icon-16 ${options.icon}"></i>`)
127
+ summary.insertBefore(icon, summary.firstChild)
128
+ }
129
+ return fieldset
130
+ }
131
+
132
+ export const loadTemplateWithRefs = Utils.loadTemplateWithRefs
133
+ export const loadTemplate = Utils.loadTemplate
@@ -6,27 +6,6 @@ import { Fields } from './form/fields.js'
6
6
 
7
7
  const EMPTY_VALUE = translate('<empty value>')
8
8
 
9
- const getParser = (type) => {
10
- switch (type) {
11
- case 'Number':
12
- return Number.parseFloat
13
- case 'Datetime':
14
- return (v) => new Date(v)
15
- case 'Date':
16
- return Utils.parseNaiveDate
17
- case 'Boolean':
18
- return Boolean
19
- case 'Enum':
20
- return (v) => {
21
- if (!v) return [EMPTY_VALUE]
22
- return String(v || '')
23
- .split(',')
24
- .map((s) => s.trim())
25
- }
26
- default:
27
- return (v) => String(v || '')
28
- }
29
- }
30
9
  const Widgets = {}
31
10
 
32
11
  class BaseWidget {
@@ -73,13 +52,13 @@ Widgets.MinMax = class extends BaseWidget {
73
52
  return this.userData.min !== undefined || this.userData.max !== undefined
74
53
  }
75
54
  getFormField(field) {
76
- if (field.type === 'Number') {
55
+ if (field.TYPE === 'Number') {
77
56
  return 'FilterByNumber'
78
57
  }
79
- if (field.type === 'Date') {
58
+ if (field.TYPE === 'Date') {
80
59
  return 'FilterByDate'
81
60
  }
82
- if (field.type === 'Datetime') {
61
+ if (field.TYPE === 'Datetime') {
83
62
  return 'FilterByDateTime'
84
63
  }
85
64
  return super.getFormField(field)
@@ -186,16 +165,15 @@ export class Filters {
186
165
  // and max values.
187
166
  computeInitialData() {
188
167
  const initialData = Object.fromEntries(
189
- this.available.keys().map((name) => [name, {}])
168
+ Array.from(this.available.keys()).map((name) => [name, {}])
190
169
  )
191
170
 
192
171
  for (const [name, filter] of this.available.entries()) {
193
172
  const field = this._parent.fields.get(name)
194
173
  if (!field) continue
195
- const parser = getParser(field.type)
196
174
  this._parent.eachFeature((feature) => {
197
175
  let value = feature.properties[name]
198
- value = parser(value)
176
+ value = field.parse(value)
199
177
  filter.computeInitialData(initialData[name], value)
200
178
  })
201
179
  }
@@ -214,6 +192,7 @@ export class Filters {
214
192
  {
215
193
  initialData: initialData[name] || {},
216
194
  handler: filter.getFormField(field),
195
+ dataField: field,
217
196
  label: Utils.escapeHTML(this.available.get(name).label || field.key),
218
197
  onClick: () => {
219
198
  this._parent
@@ -228,14 +207,8 @@ export class Filters {
228
207
  }
229
208
 
230
209
  load() {
231
- let filters = this._parent.properties.filters || []
232
- // TMP fix for dev server to update map created before changing
233
- // filters to be an array
234
- if (typeof filters === 'object' && !Array.isArray(filters) && filters !== null) {
235
- filters = Object.entries(filters).map(([fieldKey, props]) => {
236
- return { fieldKey, ...props }
237
- })
238
- }
210
+ let filters = this._parent.properties.filters
211
+ if (!Array.isArray(filters)) filters = []
239
212
  for (const filter of filters) {
240
213
  this._add({ ...filter })
241
214
  }
@@ -377,9 +350,9 @@ export class Filters {
377
350
  createFilterForm(fieldKey) {
378
351
  let widget = 'Checkbox'
379
352
  const field = this._parent.fields.get(fieldKey)
380
- if (['Number', 'Date', 'Datetime'].includes(field?.type)) {
353
+ if (['Number', 'Date', 'Datetime'].includes(field?.TYPE)) {
381
354
  widget = 'MinMax'
382
- } else if (field?.type === 'Boolean') {
355
+ } else if (field?.TYPE === 'Boolean') {
383
356
  widget = 'Switch'
384
357
  }
385
358
  const properties = {
@@ -392,7 +365,9 @@ export class Filters {
392
365
  ? [fieldKey]
393
366
  : [
394
367
  '',
395
- ...this._parent.fieldKeys.filter((fieldKey) => !this.available.has(fieldKey)),
368
+ ...Array.from(this._parent.fields.keys()).filter(
369
+ (fieldKey) => !this.available.has(fieldKey)
370
+ ),
396
371
  ]
397
372
  const metadata = [
398
373
  [
@@ -474,8 +449,7 @@ export class Filters {
474
449
  // This field may only exist on another layer.
475
450
  if (!field) continue
476
451
  let value = feature.properties[fieldKey]
477
- const parser = getParser(field.type)
478
- value = parser(value)
452
+ value = field.parse(value)
479
453
  if (obj.match(value)) return true
480
454
  }
481
455
  return false
@@ -510,6 +484,10 @@ class FiltersForm extends Form {
510
484
 
511
485
  const FilterBase = class extends Fields.Base {
512
486
  buildLabel() {}
487
+
488
+ cast(value) {
489
+ return this.properties.dataField.cast(value) || EMPTY_VALUE
490
+ }
513
491
  }
514
492
 
515
493
  const FilterByChoices = class extends FilterBase {
@@ -545,8 +523,8 @@ const FilterByChoices = class extends FilterBase {
545
523
 
546
524
  toJS() {
547
525
  return {
548
- selected: [...this.elements.ul.querySelectorAll('input:checked')].map(
549
- (i) => i.dataset.value
526
+ selected: [...this.elements.ul.querySelectorAll('input:checked')].map((i) =>
527
+ this.cast(i.dataset.value)
550
528
  ),
551
529
  }
552
530
  }
@@ -573,6 +551,10 @@ Fields.MinMaxBase = class extends FilterBase {
573
551
  return value?.valueOf() ?? null
574
552
  }
575
553
 
554
+ prepareForJS(value) {
555
+ return this.cast(value)
556
+ }
557
+
576
558
  getTemplate() {
577
559
  const [minLabel, maxLabel] = this.getLabels()
578
560
  const { min, max } = this.properties.initialData
@@ -654,10 +636,6 @@ Fields.FilterByNumber = class extends Fields.MinMaxBase {
654
636
  getInputType(type) {
655
637
  return 'number'
656
638
  }
657
-
658
- prepareForJS(value) {
659
- return new Number(value)
660
- }
661
639
  }
662
640
 
663
641
  Fields.FilterByDate = class extends Fields.MinMaxBase {
@@ -665,10 +643,6 @@ Fields.FilterByDate = class extends Fields.MinMaxBase {
665
643
  return 'date'
666
644
  }
667
645
 
668
- prepareForJS(value) {
669
- return new Date(value)
670
- }
671
-
672
646
  toLocaleDateTime(dt) {
673
647
  return new Date(dt.valueOf() - dt.getTimezoneOffset() * 60000)
674
648
  }
@@ -56,30 +56,31 @@ export class Form extends Utils.WithEvents {
56
56
  return this.helpers[field]
57
57
  }
58
58
 
59
- getter(field) {
60
- const path = field.split('.')
59
+ getter(helper) {
60
+ const path = helper.field.split('.')
61
61
  let value = this.obj
62
62
  for (const sub of path) {
63
63
  try {
64
64
  value = value[sub]
65
65
  } catch {
66
- console.debug(field)
66
+ console.debug(helper.field)
67
67
  }
68
68
  }
69
69
  return value
70
70
  }
71
71
 
72
- setter(field, value) {
72
+ setter(helper, value) {
73
73
  if ('setter' in this.obj) {
74
- this.obj.setter(field, value)
74
+ this.obj.setter(helper.field, value)
75
75
  } else {
76
- Utils.setObjectValue(this.obj, field, value)
76
+ Utils.setObjectValue(this.obj, helper.field, value)
77
77
  }
78
78
  }
79
79
 
80
80
  restoreField(field) {
81
- const initial = this.helpers[field].initial
82
- this.setter(field, initial)
81
+ const helper = this.helpers[field]
82
+ const initial = helper.initial
83
+ this.setter(helper, initial)
83
84
  }
84
85
 
85
86
  getName(field) {
@@ -127,9 +128,9 @@ export class Form extends Utils.WithEvents {
127
128
  export class MutatingForm extends Form {
128
129
  constructor(obj, fields, properties) {
129
130
  super(obj, fields, properties)
131
+ this.debounce = true
130
132
  this._umap = obj._umap || properties.umap
131
133
  this.computeDefaultProperties()
132
- // this.on('finish', this.finish)
133
134
  }
134
135
 
135
136
  computeDefaultProperties() {
@@ -180,21 +181,21 @@ export class MutatingForm extends Form {
180
181
  }
181
182
  }
182
183
 
183
- setter(field, value) {
184
- const oldValue = this.getter(field)
185
- super.setter(field, value)
184
+ setter(helper, value) {
185
+ const oldValue = this.getter(helper)
186
+ super.setter(helper, value)
186
187
  if ('render' in this.obj) {
187
- this.obj.render([field], this)
188
+ this.obj.render([helper.field], this)
188
189
  }
189
- if ('sync' in this.obj) {
190
- this.obj.sync.update(field, value, oldValue)
190
+ if ('sync' in this.obj && helper.properties.sync !== false) {
191
+ this.obj.sync.update(helper.field, value, oldValue)
191
192
  }
192
193
  }
193
194
 
194
195
  getTemplate(helper) {
195
196
  let template
196
197
  if (helper.properties.inheritable) {
197
- const extraClassName = this.getter(helper.field) === undefined ? ' undefined' : ''
198
+ const extraClassName = this.getter(helper) === undefined ? ' undefined' : ''
198
199
  template = `
199
200
  <div class="umap-field-${helper.name} formbox inheritable${extraClassName}">
200
201
  <div class="header" data-ref=header>
@@ -87,7 +87,7 @@ Fields.Base = class {
87
87
  const path = this.field.split('.')
88
88
  const key = path[path.length - 1]
89
89
  if (!this.properties.inheritable) {
90
- value = this.builder.getter(this.field)
90
+ value = this.builder.getter(this)
91
91
  } else {
92
92
  value = this.obj.getOption(key)
93
93
  }
@@ -108,8 +108,16 @@ Fields.Base = class {
108
108
  this.builder.fire('set', { helper: this })
109
109
  }
110
110
 
111
+ listenForSync(element) {
112
+ let callback = () => this.sync()
113
+ if (this.builder.form.debounce) {
114
+ callback = Utils.debounce(callback, 300)
115
+ }
116
+ element.addEventListener('input', callback)
117
+ }
118
+
111
119
  set() {
112
- this.builder.setter(this.field, this.toJS())
120
+ this.builder.setter(this, this.toJS())
113
121
  }
114
122
 
115
123
  getLabelTemplate() {
@@ -139,10 +147,7 @@ Fields.Textarea = class extends Fields.Base {
139
147
  this.textarea = this.elements.textarea
140
148
  this.input = this.textarea
141
149
  this.fetch()
142
- this.textarea.addEventListener(
143
- 'input',
144
- Utils.debounce(() => this.sync(), 300)
145
- )
150
+ this.listenForSync(this.textarea)
146
151
  this.textarea.addEventListener('keypress', (event) => this.onKeyPress(event))
147
152
  }
148
153
 
@@ -194,7 +199,7 @@ Fields.Input = class extends Fields.Base {
194
199
  this.input.disabled = true
195
200
  }
196
201
  this.fetch()
197
- this.listenForSync()
202
+ this.listenForSync(this.input)
198
203
  this.input.addEventListener('keydown', (event) => this.onKeyDown(event))
199
204
  }
200
205
 
@@ -204,13 +209,6 @@ Fields.Input = class extends Fields.Base {
204
209
  this.input.value = value
205
210
  }
206
211
 
207
- listenForSync() {
208
- this.input.addEventListener(
209
- 'input',
210
- Utils.debounce(() => this.sync(), 300)
211
- )
212
- }
213
-
214
212
  type() {
215
213
  return this.properties.type || 'text'
216
214
  }
@@ -644,7 +642,7 @@ const BaseDataLayerSwitcher = class extends Fields.Select {
644
642
 
645
643
  set() {
646
644
  this.builder._umap.lastUsedDataLayer = this.toJS()
647
- this.builder.setter(this.field, this.toJS())
645
+ this.builder.setter(this, this.toJS())
648
646
  }
649
647
  }
650
648
 
@@ -746,7 +744,7 @@ Fields.PropertyInput = class extends Fields.BlurInput {
746
744
  super.build()
747
745
  const autocomplete = new AutocompleteDatalist(this.input)
748
746
  // Will be used on Umap and DataLayer
749
- const properties = this.builder.obj.fieldKeys
747
+ const properties = Array.from(this.builder.obj.fields.keys())
750
748
  autocomplete.suggestions = properties
751
749
  }
752
750
  }
@@ -762,7 +760,7 @@ Fields.IconUrl = class extends Fields.BlurInput {
762
760
  // in the super method, maybe it's useless for all fields.
763
761
  const path = this.field.split('.')
764
762
  const key = path[path.length - 1]
765
- return this.builder.getter(this.field)
763
+ return this.builder.getter(this)
766
764
  }
767
765
 
768
766
  getTemplate() {
@@ -1217,8 +1215,9 @@ Fields.ManageOwner = class extends Fields.Base {
1217
1215
  super.build()
1218
1216
  const options = {
1219
1217
  className: 'edit-owner',
1220
- on_select: L.bind(this.onSelect, this),
1218
+ on_select: (choice) => this.onSelect(choice),
1221
1219
  placeholder: translate("Type new owner's username"),
1220
+ url: this.properties.url,
1222
1221
  }
1223
1222
  this.autocomplete = new AjaxAutocomplete(this.container, options)
1224
1223
  const owner = this.toHTML()
@@ -1248,9 +1247,10 @@ Fields.ManageEditors = class extends Fields.Base {
1248
1247
  super.build()
1249
1248
  const options = {
1250
1249
  className: 'edit-editors',
1251
- on_select: L.bind(this.onSelect, this),
1252
- on_unselect: L.bind(this.onUnselect, this),
1250
+ on_select: (choice) => this.onSelect(choice),
1251
+ on_unselect: (choice) => this.onUnselect(choice),
1253
1252
  placeholder: translate("Type editor's username"),
1253
+ url: this.properties.url,
1254
1254
  }
1255
1255
  this.autocomplete = new AjaxAutocompleteMultiple(this.container, options)
1256
1256
  this._values = this.toHTML() || []
@@ -71,7 +71,15 @@ export class Formatter {
71
71
  } catch (e) {
72
72
  src = this.toDom(str)
73
73
  }
74
- return osmtogeojson(src, { flatProperties: true })
74
+ const data = osmtogeojson(src, { flatProperties: true })
75
+ // FIXME: make a PR to osmtogeojson when it's more active
76
+ // cf https://github.com/umap-project/umap/issues/3072
77
+ for (const feature of data.features || []) {
78
+ const [osm_type, osm_id] = feature.properties.id.split('/')
79
+ feature.properties.osm_id = osm_id
80
+ feature.properties.osm_type = osm_type
81
+ }
82
+ return data
75
83
  }
76
84
 
77
85
  fromCSV(str, callback) {
@@ -1,7 +1,7 @@
1
- import { DomEvent, DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
2
1
  import { translate } from './i18n.js'
3
2
  import Dialog from './ui/dialog.js'
4
3
  import * as Utils from './utils.js'
4
+ import * as DOMUtils from './domutils.js'
5
5
 
6
6
  const SHORTCUTS = {
7
7
  DRAW_MARKER: {
@@ -209,15 +209,15 @@ export default class Help {
209
209
  }
210
210
 
211
211
  show(entries) {
212
- const container = DomUtil.add('div')
213
- DomUtil.createTitle(container, translate('Help'))
212
+ const container = DOMUtils.loadTemplate(`
213
+ <div>
214
+ <h3><i class="icon icon-16 icon-help"></i> ${translate('Help')}</h3>
215
+ </div>
216
+ `)
214
217
  for (const name of entries) {
215
- DomUtil.element({
216
- tagName: 'div',
217
- className: 'umap-help-entry',
218
- parent: container,
219
- innerHTML: ENTRIES[name],
220
- })
218
+ container.appendChild(
219
+ DOMUtils.loadTemplate(`<div class="umap-help-entry">${ENTRIES[name]}</div>`)
220
+ )
221
221
  }
222
222
  this.dialog.open({ template: container })
223
223
  }
@@ -253,11 +253,10 @@ export default class Help {
253
253
  }
254
254
 
255
255
  button(container, entries) {
256
- const button = DomUtil.createButton(
257
- 'umap-help-button',
258
- container,
259
- translate('Help')
256
+ const button = DOMUtils.loadTemplate(
257
+ `<button class="umap-help-button" type="button">${translate('Help')}</button>`
260
258
  )
259
+ container.appendChild(button)
261
260
  button.addEventListener('click', () => this.show(entries))
262
261
  return button
263
262
  }
@@ -1,13 +1,10 @@
1
- import {
2
- DomEvent,
3
- DomUtil,
4
- LatLngBounds,
5
- } from '../../vendors/leaflet/leaflet-src.esm.js'
1
+ import { LatLngBounds } from '../../vendors/leaflet/leaflet-src.esm.js'
6
2
  import { uMapAlert as Alert } from '../components/alerts/alert.js'
7
3
  import { translate } from './i18n.js'
8
4
  import { SCHEMA } from './schema.js'
9
5
  import Dialog from './ui/dialog.js'
10
6
  import * as Utils from './utils.js'
7
+ import * as DOMUtils from './domutils.js'
11
8
 
12
9
  const TEMPLATE = `
13
10
  <div class="umap-import">
@@ -203,18 +200,15 @@ export default class Importer extends Utils.WithTemplate {
203
200
  button.toggleAttribute('hidden', false)
204
201
  }
205
202
  for (const type of this.TYPES) {
206
- DomUtil.element({
207
- tagName: 'option',
208
- parent: this.qs('[name=format]'),
209
- value: type,
210
- textContent: type,
211
- })
203
+ this.qs('[name=format]').appendChild(
204
+ DOMUtils.loadTemplate(`<option value="${type}">${type}</option>`)
205
+ )
212
206
  }
213
207
  this._umap.help.parse(this.container)
214
208
  this.qs('[name=submit]').addEventListener('click', () => this.submit())
215
- DomEvent.on(this.qs('[type=file]'), 'change', this.onFileChange, this)
209
+ this.qs('[type=file]').addEventListener('change', () => this.onFileChange())
216
210
  for (const element of this.container.querySelectorAll('[onchange]')) {
217
- DomEvent.on(element, 'change', this.onChange, this)
211
+ element.addEventListener('change', () => this.onChange())
218
212
  }
219
213
  }
220
214
 
@@ -253,21 +247,18 @@ export default class Importer extends Utils.WithTemplate {
253
247
  layerSelect.innerHTML = ''
254
248
  this._umap.datalayers.reverse().map((datalayer) => {
255
249
  if (datalayer.isLoaded() && !datalayer.isRemoteLayer()) {
256
- DomUtil.element({
257
- tagName: 'option',
258
- parent: layerSelect,
259
- textContent: datalayer.getName(),
260
- value: datalayer.id,
261
- })
250
+ layerSelect.appendChild(
251
+ DOMUtils.loadTemplate(
252
+ `<option value="${datalayer.id}">${datalayer.getName()}</option>`
253
+ )
254
+ )
262
255
  }
263
256
  })
264
- DomUtil.element({
265
- tagName: 'option',
266
- value: '',
267
- textContent: translate('Import in a new layer'),
268
- parent: layerSelect,
269
- selected: true,
270
- })
257
+ layerSelect.appendChild(
258
+ DOMUtils.loadTemplate(
259
+ `<option value="" selected>${translate('Import in a new layer')}</option>`
260
+ )
261
+ )
271
262
  }
272
263
 
273
264
  open() {
@@ -1,4 +1,3 @@
1
- import { DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
2
1
  import { uMapAlert as Alert } from '../../components/alerts/alert.js'
3
2
  import { BaseAjax, SingleMixin } from '../autocomplete.js'
4
3
  import { translate } from '../i18n.js'
@@ -1,26 +1,28 @@
1
- import { DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
2
1
  import { uMapAlert as Alert } from '../../components/alerts/alert.js'
3
2
  import { BaseAjax, SingleMixin } from '../autocomplete.js'
4
3
  import { translate } from '../i18n.js'
5
4
  import * as Util from '../utils.js'
5
+ import * as DOMUtils from '../domutils.js'
6
6
  import { AutocompleteCommunes } from './communesfr.js'
7
7
 
8
8
  const TEMPLATE = `
9
- <h3>Cadastre</h3>
10
- <p>Importer les données cadastrales d’une commune française.</p>
11
- <div class="formbox">
12
- <select name="theme">
13
- <option value="batiments">Bâtiments</option>
14
- <option value="communes">Communes</option>
15
- <option value="feuilles">Feuilles</option>
16
- <option value="lieux_dits">Lieux dits</option>
17
- <option value="parcelles" selected>Parcelles</option>
18
- <option value="prefixes_sections">Préfixes sections</option>
19
- <option value="sections">Sections</option>
20
- <option value="subdivisions_fiscales">Subdivisions fiscales</option>
21
- </select>
22
- <label id="boundary">
23
- </label>
9
+ <div>
10
+ <h3>Cadastre</h3>
11
+ <p>Importer les données cadastrales d’une commune française.</p>
12
+ <div class="formbox">
13
+ <select name="theme" data-ref="select">
14
+ <option value="batiments">Bâtiments</option>
15
+ <option value="communes">Communes</option>
16
+ <option value="feuilles">Feuilles</option>
17
+ <option value="lieux_dits">Lieux dits</option>
18
+ <option value="parcelles" selected>Parcelles</option>
19
+ <option value="prefixes_sections">Préfixes sections</option>
20
+ <option value="sections">Sections</option>
21
+ <option value="subdivisions_fiscales">Subdivisions fiscales</option>
22
+ </select>
23
+ <label id="boundary">
24
+ </label>
25
+ </div>
24
26
  </div>
25
27
  `
26
28
 
@@ -33,9 +35,7 @@ export class Importer {
33
35
  async open(importer) {
34
36
  let boundary = null
35
37
  let boundaryName = null
36
- const container = DomUtil.create('div')
37
- container.innerHTML = TEMPLATE
38
- const select = container.querySelector('select')
38
+ const [container, { select }] = DOMUtils.loadTemplateWithRefs(TEMPLATE)
39
39
  const options = {
40
40
  placeholder: 'Nom ou code INSEE…',
41
41
  url: 'https://geo.api.gouv.fr/communes?nom={q}&limit=5',
@@ -1,6 +1,6 @@
1
- import { DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
2
1
  import { BaseAjax, SingleMixin } from '../autocomplete.js'
3
2
  import * as Util from '../utils.js'
3
+ import * as DOMUtils from '../domutils.js'
4
4
 
5
5
  export class AutocompleteCommunes extends SingleMixin(BaseAjax) {
6
6
  createResult(item) {
@@ -29,13 +29,12 @@ export class Importer {
29
29
  }
30
30
 
31
31
  async open(importer) {
32
- const container = DomUtil.create('div')
33
- DomUtil.createTitle(container, this.name)
34
- DomUtil.element({
35
- tagName: 'p',
36
- parent: container,
37
- textContent: "Importer les contours d'une commune française.",
38
- })
32
+ const container = DOMUtils.loadTemplate(`
33
+ <div>
34
+ <h3>${this.name}</h3>
35
+ <p>Importer les contours d'une commune française.</p>
36
+ </div>
37
+ `)
39
38
  const options = {
40
39
  placeholder: 'Nom ou code INSEE…',
41
40
  url: 'https://geo.api.gouv.fr/communes?nom={q}&limit=5',