umap-project 3.4.2__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 (168) 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/de/LC_MESSAGES/django.mo +0 -0
  5. umap/locale/de/LC_MESSAGES/django.po +20 -16
  6. umap/locale/en/LC_MESSAGES/django.po +14 -14
  7. umap/locale/hu/LC_MESSAGES/django.mo +0 -0
  8. umap/locale/hu/LC_MESSAGES/django.po +20 -16
  9. umap/locale/pl/LC_MESSAGES/django.mo +0 -0
  10. umap/locale/pl/LC_MESSAGES/django.po +32 -27
  11. umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
  12. umap/locale/zh_TW/LC_MESSAGES/django.po +20 -16
  13. umap/management/commands/clean_tilelayer.py +0 -1
  14. umap/management/commands/search_maps.py +95 -0
  15. umap/settings/__init__.py +9 -1
  16. umap/settings/base.py +7 -6
  17. umap/static/umap/css/icon.css +8 -0
  18. umap/static/umap/img/16-white.svg +5 -2
  19. umap/static/umap/img/16.svg +1 -1
  20. umap/static/umap/img/source/16-white.svg +7 -4
  21. umap/static/umap/img/source/16.svg +1 -1
  22. umap/static/umap/js/modules/autocomplete.js +1 -9
  23. umap/static/umap/js/modules/browser.js +27 -10
  24. umap/static/umap/js/modules/data/features.js +3 -2
  25. umap/static/umap/js/modules/data/fields.js +12 -2
  26. umap/static/umap/js/modules/data/layer.js +13 -9
  27. umap/static/umap/js/modules/domutils.js +4 -0
  28. umap/static/umap/js/modules/filters.js +11 -10
  29. umap/static/umap/js/modules/form/builder.js +17 -16
  30. umap/static/umap/js/modules/form/fields.js +16 -16
  31. umap/static/umap/js/modules/permissions.js +10 -2
  32. umap/static/umap/js/modules/rendering/controls.js +202 -9
  33. umap/static/umap/js/modules/rendering/layers/classified.js +1 -1
  34. umap/static/umap/js/modules/rendering/map.js +45 -35
  35. umap/static/umap/js/modules/rendering/template.js +12 -6
  36. umap/static/umap/js/modules/ui/bar.js +2 -1
  37. umap/static/umap/js/modules/ui/hash.js +36 -0
  38. umap/static/umap/js/modules/ui/loader.js +26 -0
  39. umap/static/umap/js/modules/ui/panel.js +7 -0
  40. umap/static/umap/js/modules/umap.js +6 -0
  41. umap/static/umap/js/modules/utils.js +5 -4
  42. umap/static/umap/js/umap.controls.js +0 -182
  43. umap/static/umap/locale/am_ET.js +2 -5
  44. umap/static/umap/locale/am_ET.json +2 -5
  45. umap/static/umap/locale/ar.js +2 -5
  46. umap/static/umap/locale/ar.json +2 -5
  47. umap/static/umap/locale/ast.js +2 -5
  48. umap/static/umap/locale/ast.json +2 -5
  49. umap/static/umap/locale/bg.js +2 -5
  50. umap/static/umap/locale/bg.json +2 -5
  51. umap/static/umap/locale/br.js +40 -43
  52. umap/static/umap/locale/br.json +40 -43
  53. umap/static/umap/locale/ca.js +2 -5
  54. umap/static/umap/locale/ca.json +2 -5
  55. umap/static/umap/locale/cs_CZ.js +0 -3
  56. umap/static/umap/locale/cs_CZ.json +0 -3
  57. umap/static/umap/locale/da.js +1 -4
  58. umap/static/umap/locale/da.json +1 -4
  59. umap/static/umap/locale/de.js +27 -30
  60. umap/static/umap/locale/de.json +27 -30
  61. umap/static/umap/locale/el.js +0 -3
  62. umap/static/umap/locale/el.json +0 -3
  63. umap/static/umap/locale/en.js +0 -3
  64. umap/static/umap/locale/en.json +0 -3
  65. umap/static/umap/locale/en_US.json +2 -5
  66. umap/static/umap/locale/es.js +0 -3
  67. umap/static/umap/locale/es.json +0 -3
  68. umap/static/umap/locale/et.js +0 -3
  69. umap/static/umap/locale/et.json +0 -3
  70. umap/static/umap/locale/eu.js +0 -3
  71. umap/static/umap/locale/eu.json +0 -3
  72. umap/static/umap/locale/fa_IR.js +0 -3
  73. umap/static/umap/locale/fa_IR.json +0 -3
  74. umap/static/umap/locale/fi.js +2 -5
  75. umap/static/umap/locale/fi.json +2 -5
  76. umap/static/umap/locale/fr.js +3 -6
  77. umap/static/umap/locale/fr.json +3 -6
  78. umap/static/umap/locale/gl.js +0 -3
  79. umap/static/umap/locale/gl.json +0 -3
  80. umap/static/umap/locale/he.js +2 -5
  81. umap/static/umap/locale/he.json +2 -5
  82. umap/static/umap/locale/hr.js +2 -5
  83. umap/static/umap/locale/hr.json +2 -5
  84. umap/static/umap/locale/hu.js +7 -10
  85. umap/static/umap/locale/hu.json +7 -10
  86. umap/static/umap/locale/id.js +2 -5
  87. umap/static/umap/locale/id.json +2 -5
  88. umap/static/umap/locale/is.js +0 -3
  89. umap/static/umap/locale/is.json +0 -3
  90. umap/static/umap/locale/it.js +0 -3
  91. umap/static/umap/locale/it.json +0 -3
  92. umap/static/umap/locale/ja.js +2 -5
  93. umap/static/umap/locale/ja.json +2 -5
  94. umap/static/umap/locale/ko.js +2 -5
  95. umap/static/umap/locale/ko.json +2 -5
  96. umap/static/umap/locale/lt.js +2 -5
  97. umap/static/umap/locale/lt.json +2 -5
  98. umap/static/umap/locale/ms.js +0 -3
  99. umap/static/umap/locale/ms.json +0 -3
  100. umap/static/umap/locale/nl.js +0 -3
  101. umap/static/umap/locale/nl.json +0 -3
  102. umap/static/umap/locale/no.js +2 -5
  103. umap/static/umap/locale/no.json +2 -5
  104. umap/static/umap/locale/pl.js +2 -5
  105. umap/static/umap/locale/pl.json +2 -5
  106. umap/static/umap/locale/pl_PL.json +2 -5
  107. umap/static/umap/locale/pt.js +0 -3
  108. umap/static/umap/locale/pt.json +0 -3
  109. umap/static/umap/locale/pt_BR.js +2 -5
  110. umap/static/umap/locale/pt_BR.json +2 -5
  111. umap/static/umap/locale/pt_PT.js +2 -5
  112. umap/static/umap/locale/pt_PT.json +2 -5
  113. umap/static/umap/locale/ro.js +2 -5
  114. umap/static/umap/locale/ro.json +2 -5
  115. umap/static/umap/locale/ru.js +2 -5
  116. umap/static/umap/locale/ru.json +2 -5
  117. umap/static/umap/locale/sk_SK.js +2 -5
  118. umap/static/umap/locale/sk_SK.json +2 -5
  119. umap/static/umap/locale/sl.js +2 -5
  120. umap/static/umap/locale/sl.json +2 -5
  121. umap/static/umap/locale/sr.js +2 -5
  122. umap/static/umap/locale/sr.json +2 -5
  123. umap/static/umap/locale/sv.js +2 -5
  124. umap/static/umap/locale/sv.json +2 -5
  125. umap/static/umap/locale/th_TH.js +2 -5
  126. umap/static/umap/locale/th_TH.json +2 -5
  127. umap/static/umap/locale/tr.js +2 -5
  128. umap/static/umap/locale/tr.json +2 -5
  129. umap/static/umap/locale/uk_UA.js +2 -5
  130. umap/static/umap/locale/uk_UA.json +2 -5
  131. umap/static/umap/locale/vi.js +2 -5
  132. umap/static/umap/locale/vi.json +2 -5
  133. umap/static/umap/locale/vi_VN.json +2 -5
  134. umap/static/umap/locale/zh.js +2 -5
  135. umap/static/umap/locale/zh.json +2 -5
  136. umap/static/umap/locale/zh_CN.json +2 -5
  137. umap/static/umap/locale/zh_TW.Big5.json +2 -5
  138. umap/static/umap/locale/zh_TW.js +1 -4
  139. umap/static/umap/locale/zh_TW.json +1 -4
  140. umap/static/umap/map.css +1 -17
  141. umap/static/umap/vendors/locatecontrol/L.Control.Locate.esm.js +942 -0
  142. umap/static/umap/vendors/photon/leaflet.photon.esm.js +472 -0
  143. umap/sync/app.py +4 -1
  144. umap/templates/umap/css.html +0 -2
  145. umap/templates/umap/js.html +0 -5
  146. umap/templates/umap/team_form.html +2 -1
  147. umap/tests/integration/test_edit_map.py +2 -0
  148. umap/tests/integration/test_filters.py +24 -0
  149. umap/tests/integration/test_import.py +26 -23
  150. umap/tests/integration/test_map.py +1 -1
  151. umap/tests/integration/test_optimistic_merge.py +7 -1
  152. umap/tests/integration/test_remote_data.py +1 -1
  153. umap/tests/test_search_maps_command.py +44 -0
  154. umap/utils.py +9 -3
  155. umap/views.py +17 -4
  156. {umap_project-3.4.2.dist-info → umap_project-3.6.0.dist-info}/METADATA +24 -18
  157. {umap_project-3.4.2.dist-info → umap_project-3.6.0.dist-info}/RECORD +160 -162
  158. {umap_project-3.4.2.dist-info → umap_project-3.6.0.dist-info}/WHEEL +1 -1
  159. umap/static/umap/vendors/hash/leaflet-hash.js +0 -162
  160. umap/static/umap/vendors/loading/Control.Loading.css +0 -26
  161. umap/static/umap/vendors/loading/Control.Loading.js +0 -351
  162. umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.css +0 -1
  163. umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.css.map +0 -1
  164. umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.js +0 -4
  165. umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.js.map +0 -1
  166. umap/static/umap/vendors/photon/leaflet.photon.js +0 -487
  167. {umap_project-3.4.2.dist-info → umap_project-3.6.0.dist-info}/entry_points.txt +0 -0
  168. {umap_project-3.4.2.dist-info → umap_project-3.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -215,14 +215,10 @@ export class BaseAutocomplete {
215
215
  export class BaseAjax extends BaseAutocomplete {
216
216
  constructor(el, options) {
217
217
  super(el, options)
218
- this.setUrl()
218
+ this.url = this.options.url
219
219
  this.initRequest()
220
220
  }
221
221
 
222
- setUrl() {
223
- this.url = this.options?.url
224
- }
225
-
226
222
  initRequest() {
227
223
  this.request = new Request()
228
224
  }
@@ -260,10 +256,6 @@ export class BaseAjax extends BaseAutocomplete {
260
256
  }
261
257
 
262
258
  class BaseServerAjax extends BaseAjax {
263
- setUrl() {
264
- this.url = '/agnocomplete/AutocompleteUser/?q={q}'
265
- }
266
-
267
259
  initRequest() {
268
260
  this.server = new ServerRequest()
269
261
  }
@@ -57,18 +57,23 @@ export default class Browser {
57
57
 
58
58
  addDataLayer(datalayer, parent) {
59
59
  const open = this.mode !== 'layers' ? ' open' : ''
60
- const [container, { headline, toolbox, label }] = Utils.loadTemplateWithRefs(`
61
- <details class="datalayer ${datalayer.cssId}" id="${this.datalayerId(datalayer)}"${open}>
62
- <summary data-ref=headline class="with-toolbox">
60
+ const [container, { details, toolbox, label, ul }] = Utils.loadTemplateWithRefs(`
61
+ <details data-ref=details class="datalayer ${datalayer.cssId}" id="${datalayer.cssId}"${open}>
62
+ <summary class="with-toolbox">
63
63
  <span>
64
64
  <span class="datalayer-name truncate" data-id="${datalayer.id}" data-ref=label></span>
65
65
  <span class="datalayer-counter"></span>
66
66
  </span>
67
67
  <span data-ref=toolbox></span>
68
68
  </summary>
69
- <ul></ul>
69
+ <ul data-ref=ul></ul>
70
70
  </details>
71
71
  `)
72
+ details.addEventListener('toggle', () => {
73
+ if (details.open && !ul.innerHTML.trim()) {
74
+ this._appendFeaturesDOM(datalayer, ul)
75
+ }
76
+ })
72
77
  datalayer.renderToolbox(toolbox)
73
78
  parent.appendChild(container)
74
79
  this.updateFeaturesList(datalayer)
@@ -77,25 +82,31 @@ export default class Browser {
77
82
  updateFeaturesList(datalayer) {
78
83
  // Compute once, but use it for each feature later.
79
84
  this.bounds = this._leafletMap.getBounds()
80
- const id = this.datalayerId(datalayer)
81
- const parent = document.getElementById(id)
82
- // Panel is not open
85
+ const parent = document.getElementById(datalayer.cssId)
86
+ // Browser is not open
83
87
  if (!parent) return
84
88
  parent.classList.toggle('off', !datalayer.isVisible())
85
89
  const label = parent.querySelector('.datalayer-name')
86
90
  const container = parent.querySelector('ul')
87
91
  container.innerHTML = ''
88
- datalayer.features.forEach((feature) => this.addFeature(feature, container))
92
+ const isOpen = container.parentNode.open
93
+ if (isOpen || this.hasActiveFilters()) {
94
+ this._appendFeaturesDOM(datalayer, container)
95
+ }
89
96
  datalayer.propagate(['properties.name'])
90
97
  const total = datalayer.count()
91
98
  if (!total) return
92
99
  const current = container.querySelectorAll('li').length
93
- const count = total === current ? total : `${current}/${total}`
100
+ const count = !this.hasActiveFilters() ? total : `${current}/${total}`
94
101
  const counter = parent.querySelector('.datalayer-counter')
95
102
  counter.textContent = `(${count})`
96
103
  counter.title = translate(`Features in this layer: ${count}`)
97
104
  }
98
105
 
106
+ _appendFeaturesDOM(datalayer, container) {
107
+ datalayer.features.forEach((feature) => this.addFeature(feature, container))
108
+ }
109
+
99
110
  toggleBadge() {
100
111
  Utils.toggleBadge(this.filtersTitle, this.hasActiveFilters())
101
112
  Utils.toggleBadge('.umap-control-browse', this.hasActiveFilters())
@@ -139,6 +150,7 @@ export default class Browser {
139
150
  }
140
151
 
141
152
  open(mode) {
153
+ // TODO add loader
142
154
  // Force only if mode is known, otherwise keep current mode.
143
155
  if (mode) this.mode = mode
144
156
  const template = `
@@ -200,11 +212,16 @@ export default class Browser {
200
212
  content: container,
201
213
  className: 'umap-browser',
202
214
  })
203
-
215
+ details.addEventListener('toggle', () => {
216
+ if (details.open && !formContainer.innerHTML.trim()) {
217
+ this.buildFilters()
218
+ }
219
+ })
204
220
  this.update()
205
221
  }
206
222
 
207
223
  buildFilters() {
224
+ if (!this.filtersTitle.parentNode.open) return
208
225
  this.formContainer.innerHTML = ''
209
226
  const fields = [
210
227
  [
@@ -244,8 +244,10 @@ class Feature {
244
244
  </div>
245
245
  `)
246
246
 
247
+ // No need to sync the datalayer key, given we already do a delete/upsert when
248
+ // it changes.
247
249
  let builder = new MutatingForm(this, [
248
- ['datalayer', { handler: 'EditableDataLayerSwitcher' }],
250
+ ['datalayer', { handler: 'EditableDataLayerSwitcher', sync: false }],
249
251
  ])
250
252
  // removeLayer step will close the edit panel, let's reopen it
251
253
  builder.on('set', () => this.edit(event))
@@ -587,7 +589,6 @@ class Feature {
587
589
  }
588
590
 
589
591
  extendedProperties() {
590
- console.trace()
591
592
  // Include context properties
592
593
  const properties = this._umap.getGeoContext()
593
594
  const locale = getLocale()
@@ -42,6 +42,10 @@ class BaseField {
42
42
  return Utils.escapeHTML(value).trim()
43
43
  }
44
44
 
45
+ cast(value) {
46
+ return this.parse(value)
47
+ }
48
+
45
49
  dumps() {
46
50
  return {
47
51
  key: this.key,
@@ -94,7 +98,9 @@ Registry.Number = class extends BaseField {
94
98
  }
95
99
 
96
100
  parse(value) {
97
- return Number.parseFloat(value)
101
+ const parsed = Number.parseFloat(value)
102
+ if (Number.isNaN(parsed)) return null
103
+ return parsed
98
104
  }
99
105
  }
100
106
 
@@ -146,8 +152,12 @@ Registry.Enum = class extends BaseField {
146
152
  this.LABEL = translate('List of values')
147
153
  }
148
154
 
149
- parse(value) {
155
+ cast(value) {
150
156
  return String(value || '')
157
+ }
158
+
159
+ parse(value) {
160
+ return this.cast(value)
151
161
  .split(',')
152
162
  .map((s) => s.trim())
153
163
  }
@@ -70,6 +70,7 @@ export class DataLayer {
70
70
  if (this.properties.rank === undefined) {
71
71
  this.properties.rank = this._umap.datalayers.count()
72
72
  }
73
+ this._umap.datalayers.add(this)
73
74
 
74
75
  if (!Utils.isObject(this.properties.remoteData)) {
75
76
  this.properties.remoteData = {}
@@ -83,13 +84,13 @@ export class DataLayer {
83
84
  this.properties.toZoom = this.properties.remoteData.to
84
85
  delete this.properties.remoteData.to
85
86
  }
86
- this.connectToMap()
87
87
  this.permissions = new DataLayerPermissions(this._umap, this)
88
88
 
89
89
  this._needsFetch = this.createdOnServer || this.isRemoteLayer()
90
90
  this.fields = new Fields(this, this._umap.dialog)
91
91
  this.filters = new Filters(this, this._umap)
92
92
  this.rules = new Rules(umap, this)
93
+ this._umap.onDataLayersChanged()
93
94
 
94
95
  if (!this.createdOnServer) {
95
96
  if (this.showAtLoad()) this.show()
@@ -350,10 +351,15 @@ export class DataLayer {
350
351
 
351
352
  async getUrl(url, initialUrl) {
352
353
  const response = await this._umap.request.get(url)
353
- return new Promise((resolve) => {
354
+ return new Promise(async (resolve) => {
354
355
  if (response?.ok) {
355
356
  this._umap.modifiedAt = response.headers.get('last-modified')
356
- return resolve(response.text())
357
+ const id = Math.random()
358
+ this._umap.loader.start(id)
359
+ const raw = await response.text()
360
+ const promise = resolve(raw)
361
+ this._umap.loader.stop(id)
362
+ return promise
357
363
  }
358
364
  Alert.error(
359
365
  translate('Cannot load remote data for layer "{layer}" with url "{url}"', {
@@ -406,11 +412,6 @@ export class DataLayer {
406
412
  this.resetLayer()
407
413
  }
408
414
 
409
- connectToMap() {
410
- this._umap.datalayers.add(this)
411
- this._umap.onDataLayersChanged()
412
- }
413
-
414
415
  _dataUrl() {
415
416
  let url = this._umap.urls.get('datalayer_view', {
416
417
  pk: this.id,
@@ -532,6 +533,8 @@ export class DataLayer {
532
533
  }
533
534
 
534
535
  addData(geojson, sync) {
536
+ const id = Math.random()
537
+ this._umap.loader.start(id)
535
538
  let data = []
536
539
  this._batch = true
537
540
  try {
@@ -544,6 +547,7 @@ export class DataLayer {
544
547
  }
545
548
  this._batch = false
546
549
  this.dataChanged()
550
+ this._umap.loader.stop(id)
547
551
  return data
548
552
  }
549
553
 
@@ -1286,7 +1290,7 @@ export class DataLayer {
1286
1290
 
1287
1291
  this.setReferenceVersion({ response, sync: true })
1288
1292
 
1289
- this.connectToMap()
1293
+ this._umap.onDataLayersChanged()
1290
1294
  this.redraw() // Needed for reordering features
1291
1295
  return true
1292
1296
  }
@@ -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) => {
@@ -192,6 +192,7 @@ export class Filters {
192
192
  {
193
193
  initialData: initialData[name] || {},
194
194
  handler: filter.getFormField(field),
195
+ dataField: field,
195
196
  label: Utils.escapeHTML(this.available.get(name).label || field.key),
196
197
  onClick: () => {
197
198
  this._parent
@@ -483,6 +484,10 @@ class FiltersForm extends Form {
483
484
 
484
485
  const FilterBase = class extends Fields.Base {
485
486
  buildLabel() {}
487
+
488
+ cast(value) {
489
+ return this.properties.dataField.cast(value) || EMPTY_VALUE
490
+ }
486
491
  }
487
492
 
488
493
  const FilterByChoices = class extends FilterBase {
@@ -518,8 +523,8 @@ const FilterByChoices = class extends FilterBase {
518
523
 
519
524
  toJS() {
520
525
  return {
521
- selected: [...this.elements.ul.querySelectorAll('input:checked')].map(
522
- (i) => i.dataset.value
526
+ selected: [...this.elements.ul.querySelectorAll('input:checked')].map((i) =>
527
+ this.cast(i.dataset.value)
523
528
  ),
524
529
  }
525
530
  }
@@ -546,6 +551,10 @@ Fields.MinMaxBase = class extends FilterBase {
546
551
  return value?.valueOf() ?? null
547
552
  }
548
553
 
554
+ prepareForJS(value) {
555
+ return this.cast(value)
556
+ }
557
+
549
558
  getTemplate() {
550
559
  const [minLabel, maxLabel] = this.getLabels()
551
560
  const { min, max } = this.properties.initialData
@@ -627,10 +636,6 @@ Fields.FilterByNumber = class extends Fields.MinMaxBase {
627
636
  getInputType(type) {
628
637
  return 'number'
629
638
  }
630
-
631
- prepareForJS(value) {
632
- return new Number(value)
633
- }
634
639
  }
635
640
 
636
641
  Fields.FilterByDate = class extends Fields.MinMaxBase {
@@ -638,10 +643,6 @@ Fields.FilterByDate = class extends Fields.MinMaxBase {
638
643
  return 'date'
639
644
  }
640
645
 
641
- prepareForJS(value) {
642
- return new Date(value)
643
- }
644
-
645
646
  toLocaleDateTime(dt) {
646
647
  return new Date(dt.valueOf() - dt.getTimezoneOffset() * 60000)
647
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
 
@@ -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() {
@@ -1219,6 +1217,7 @@ Fields.ManageOwner = class extends Fields.Base {
1219
1217
  className: 'edit-owner',
1220
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()
@@ -1251,6 +1250,7 @@ Fields.ManageEditors = class extends Fields.Base {
1251
1250
  on_select: (choice) => this.onSelect(choice),
1252
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() || []
@@ -126,7 +126,11 @@ export class MapPermissions {
126
126
  ])
127
127
  collaboratorsFields.push([
128
128
  'properties.owner',
129
- { handler: 'ManageOwner', label: translate("Map's owner") },
129
+ {
130
+ handler: 'ManageOwner',
131
+ label: translate("Map's owner"),
132
+ url: this._umap.properties.urls.agnocomplete,
133
+ },
130
134
  ])
131
135
  if (this._umap.properties.user?.teams?.length) {
132
136
  collaboratorsFields.push([
@@ -141,7 +145,11 @@ export class MapPermissions {
141
145
  }
142
146
  collaboratorsFields.push([
143
147
  'properties.editors',
144
- { handler: 'ManageEditors', label: translate("Map's editors") },
148
+ {
149
+ handler: 'ManageEditors',
150
+ label: translate("Map's editors"),
151
+ url: this._umap.properties.urls.agnocomplete,
152
+ },
145
153
  ])
146
154
 
147
155
  const builder = new MutatingForm(this, topFields)