umap-project 3.3.5__py3-none-any.whl → 3.4.0b0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of umap-project might be problematic. Click here for more details.

Files changed (218) hide show
  1. umap/__init__.py +1 -1
  2. umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  3. umap/locale/cs_CZ/LC_MESSAGES/django.po +43 -33
  4. umap/locale/da/LC_MESSAGES/django.mo +0 -0
  5. umap/locale/da/LC_MESSAGES/django.po +43 -33
  6. umap/locale/de/LC_MESSAGES/django.mo +0 -0
  7. umap/locale/de/LC_MESSAGES/django.po +35 -29
  8. umap/locale/el/LC_MESSAGES/django.mo +0 -0
  9. umap/locale/el/LC_MESSAGES/django.po +35 -29
  10. umap/locale/en/LC_MESSAGES/django.po +34 -28
  11. umap/locale/es/LC_MESSAGES/django.mo +0 -0
  12. umap/locale/es/LC_MESSAGES/django.po +43 -33
  13. umap/locale/et/LC_MESSAGES/django.mo +0 -0
  14. umap/locale/et/LC_MESSAGES/django.po +58 -54
  15. umap/locale/eu/LC_MESSAGES/django.mo +0 -0
  16. umap/locale/eu/LC_MESSAGES/django.po +43 -33
  17. umap/locale/fa_IR/LC_MESSAGES/django.mo +0 -0
  18. umap/locale/fa_IR/LC_MESSAGES/django.po +43 -33
  19. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  20. umap/locale/fr/LC_MESSAGES/django.po +36 -30
  21. umap/locale/gl/LC_MESSAGES/django.mo +0 -0
  22. umap/locale/gl/LC_MESSAGES/django.po +43 -33
  23. umap/locale/hu/LC_MESSAGES/django.mo +0 -0
  24. umap/locale/hu/LC_MESSAGES/django.po +35 -29
  25. umap/locale/is/LC_MESSAGES/django.mo +0 -0
  26. umap/locale/is/LC_MESSAGES/django.po +43 -33
  27. umap/locale/it/LC_MESSAGES/django.mo +0 -0
  28. umap/locale/it/LC_MESSAGES/django.po +43 -33
  29. umap/locale/nl/LC_MESSAGES/django.mo +0 -0
  30. umap/locale/nl/LC_MESSAGES/django.po +35 -29
  31. umap/locale/pl/LC_MESSAGES/django.mo +0 -0
  32. umap/locale/pl/LC_MESSAGES/django.po +43 -33
  33. umap/locale/pt/LC_MESSAGES/django.mo +0 -0
  34. umap/locale/pt/LC_MESSAGES/django.po +43 -33
  35. umap/locale/th_TH/LC_MESSAGES/django.mo +0 -0
  36. umap/locale/th_TH/LC_MESSAGES/django.po +310 -109
  37. umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
  38. umap/locale/zh_TW/LC_MESSAGES/django.po +80 -70
  39. umap/management/commands/switch_user.py +2 -2
  40. umap/static/umap/base.css +89 -32
  41. umap/static/umap/content.css +129 -33
  42. umap/static/umap/css/bar.css +82 -20
  43. umap/static/umap/css/browser.css +163 -0
  44. umap/static/umap/css/contextmenu.css +15 -0
  45. umap/static/umap/css/dialog.css +36 -16
  46. umap/static/umap/css/form.css +122 -32
  47. umap/static/umap/css/icon.css +46 -3
  48. umap/static/umap/css/panel.css +7 -3
  49. umap/static/umap/css/popup.css +34 -8
  50. umap/static/umap/css/tooltip.css +8 -4
  51. umap/static/umap/img/16-white.svg +26 -8
  52. umap/static/umap/img/16.svg +1 -1
  53. umap/static/umap/img/source/16-white.svg +36 -18
  54. umap/static/umap/img/source/16.svg +1 -1
  55. umap/static/umap/js/components/alerts/alert.css +69 -31
  56. umap/static/umap/js/components/alerts/alert.js +20 -2
  57. umap/static/umap/js/modules/browser.js +64 -56
  58. umap/static/umap/js/modules/caption.js +10 -7
  59. umap/static/umap/js/modules/data/features.js +82 -59
  60. umap/static/umap/js/modules/data/layer.js +75 -166
  61. umap/static/umap/js/modules/domutils.js +109 -0
  62. umap/static/umap/js/modules/filters.js +807 -0
  63. umap/static/umap/js/modules/form/builder.js +8 -5
  64. umap/static/umap/js/modules/form/fields.js +110 -220
  65. umap/static/umap/js/modules/formatter.js +24 -1
  66. umap/static/umap/js/modules/help.js +3 -2
  67. umap/static/umap/js/modules/importers/opendata.js +5 -0
  68. umap/static/umap/js/modules/importers/openrouteservice.js +6 -1
  69. umap/static/umap/js/modules/managers.js +265 -0
  70. umap/static/umap/js/modules/permissions.js +35 -31
  71. umap/static/umap/js/modules/rendering/controls.js +7 -7
  72. umap/static/umap/js/modules/rendering/icon.js +3 -8
  73. umap/static/umap/js/modules/rendering/layers/base.js +1 -1
  74. umap/static/umap/js/modules/rendering/layers/classified.js +17 -10
  75. umap/static/umap/js/modules/rendering/layers/cluster.js +2 -2
  76. umap/static/umap/js/modules/rendering/template.js +44 -8
  77. umap/static/umap/js/modules/rendering/ui.js +29 -23
  78. umap/static/umap/js/modules/rules.js +4 -3
  79. umap/static/umap/js/modules/schema.js +3 -6
  80. umap/static/umap/js/modules/share.js +4 -3
  81. umap/static/umap/js/modules/tableeditor.js +50 -38
  82. umap/static/umap/js/modules/templates.js +2 -3
  83. umap/static/umap/js/modules/ui/bar.js +42 -18
  84. umap/static/umap/js/modules/ui/dialog.js +33 -31
  85. umap/static/umap/js/modules/ui/panel.js +21 -7
  86. umap/static/umap/js/modules/ui/tooltip.js +6 -5
  87. umap/static/umap/js/modules/umap.js +155 -46
  88. umap/static/umap/js/modules/utils.js +23 -1
  89. umap/static/umap/js/umap.core.js +1 -110
  90. umap/static/umap/locale/am_ET.js +40 -14
  91. umap/static/umap/locale/am_ET.json +40 -14
  92. umap/static/umap/locale/ar.js +40 -14
  93. umap/static/umap/locale/ar.json +40 -14
  94. umap/static/umap/locale/ast.js +40 -14
  95. umap/static/umap/locale/ast.json +40 -14
  96. umap/static/umap/locale/bg.js +40 -14
  97. umap/static/umap/locale/bg.json +40 -14
  98. umap/static/umap/locale/br.js +47 -21
  99. umap/static/umap/locale/br.json +47 -21
  100. umap/static/umap/locale/ca.js +40 -14
  101. umap/static/umap/locale/ca.json +40 -14
  102. umap/static/umap/locale/cs_CZ.js +40 -14
  103. umap/static/umap/locale/cs_CZ.json +40 -14
  104. umap/static/umap/locale/da.js +40 -14
  105. umap/static/umap/locale/da.json +40 -14
  106. umap/static/umap/locale/de.js +39 -13
  107. umap/static/umap/locale/de.json +39 -13
  108. umap/static/umap/locale/el.js +40 -14
  109. umap/static/umap/locale/el.json +40 -14
  110. umap/static/umap/locale/en.js +39 -13
  111. umap/static/umap/locale/en.json +39 -13
  112. umap/static/umap/locale/en_US.json +40 -14
  113. umap/static/umap/locale/es.js +40 -14
  114. umap/static/umap/locale/es.json +40 -14
  115. umap/static/umap/locale/et.js +79 -53
  116. umap/static/umap/locale/et.json +79 -53
  117. umap/static/umap/locale/eu.js +72 -46
  118. umap/static/umap/locale/eu.json +72 -46
  119. umap/static/umap/locale/fa_IR.js +40 -14
  120. umap/static/umap/locale/fa_IR.json +40 -14
  121. umap/static/umap/locale/fi.js +40 -14
  122. umap/static/umap/locale/fi.json +40 -14
  123. umap/static/umap/locale/fr.js +39 -13
  124. umap/static/umap/locale/fr.json +39 -13
  125. umap/static/umap/locale/gl.js +40 -14
  126. umap/static/umap/locale/gl.json +40 -14
  127. umap/static/umap/locale/he.js +40 -14
  128. umap/static/umap/locale/he.json +40 -14
  129. umap/static/umap/locale/hr.js +40 -14
  130. umap/static/umap/locale/hr.json +40 -14
  131. umap/static/umap/locale/hu.js +40 -14
  132. umap/static/umap/locale/hu.json +40 -14
  133. umap/static/umap/locale/id.js +40 -14
  134. umap/static/umap/locale/id.json +40 -14
  135. umap/static/umap/locale/is.js +40 -14
  136. umap/static/umap/locale/is.json +40 -14
  137. umap/static/umap/locale/it.js +40 -14
  138. umap/static/umap/locale/it.json +40 -14
  139. umap/static/umap/locale/ja.js +40 -14
  140. umap/static/umap/locale/ja.json +40 -14
  141. umap/static/umap/locale/ko.js +40 -14
  142. umap/static/umap/locale/ko.json +40 -14
  143. umap/static/umap/locale/lt.js +40 -14
  144. umap/static/umap/locale/lt.json +40 -14
  145. umap/static/umap/locale/ms.js +40 -14
  146. umap/static/umap/locale/ms.json +40 -14
  147. umap/static/umap/locale/nl.js +40 -14
  148. umap/static/umap/locale/nl.json +40 -14
  149. umap/static/umap/locale/no.js +40 -14
  150. umap/static/umap/locale/no.json +40 -14
  151. umap/static/umap/locale/pl.js +40 -14
  152. umap/static/umap/locale/pl.json +40 -14
  153. umap/static/umap/locale/pl_PL.json +40 -14
  154. umap/static/umap/locale/pt.js +40 -14
  155. umap/static/umap/locale/pt.json +40 -14
  156. umap/static/umap/locale/pt_BR.js +40 -14
  157. umap/static/umap/locale/pt_BR.json +40 -14
  158. umap/static/umap/locale/pt_PT.js +40 -14
  159. umap/static/umap/locale/pt_PT.json +40 -14
  160. umap/static/umap/locale/ro.js +40 -14
  161. umap/static/umap/locale/ro.json +40 -14
  162. umap/static/umap/locale/ru.js +40 -14
  163. umap/static/umap/locale/ru.json +40 -14
  164. umap/static/umap/locale/sk_SK.js +40 -14
  165. umap/static/umap/locale/sk_SK.json +40 -14
  166. umap/static/umap/locale/sl.js +40 -14
  167. umap/static/umap/locale/sl.json +40 -14
  168. umap/static/umap/locale/sr.js +40 -14
  169. umap/static/umap/locale/sr.json +40 -14
  170. umap/static/umap/locale/sv.js +40 -14
  171. umap/static/umap/locale/sv.json +40 -14
  172. umap/static/umap/locale/th_TH.js +40 -14
  173. umap/static/umap/locale/th_TH.json +40 -14
  174. umap/static/umap/locale/tr.js +40 -14
  175. umap/static/umap/locale/tr.json +40 -14
  176. umap/static/umap/locale/uk_UA.js +40 -14
  177. umap/static/umap/locale/uk_UA.json +40 -14
  178. umap/static/umap/locale/vi.js +40 -14
  179. umap/static/umap/locale/vi.json +40 -14
  180. umap/static/umap/locale/vi_VN.json +40 -14
  181. umap/static/umap/locale/zh.js +40 -14
  182. umap/static/umap/locale/zh.json +40 -14
  183. umap/static/umap/locale/zh_CN.json +40 -14
  184. umap/static/umap/locale/zh_TW.Big5.json +40 -14
  185. umap/static/umap/locale/zh_TW.js +40 -14
  186. umap/static/umap/locale/zh_TW.json +40 -14
  187. umap/static/umap/map.css +60 -223
  188. umap/static/umap/unittests/utils.js +18 -0
  189. umap/static/umap/vars.css +23 -5
  190. umap/templates/umap/components/alerts/alert.html +32 -29
  191. umap/templates/umap/css.html +2 -1
  192. umap/templates/umap/login_popup_end.html +18 -9
  193. umap/templates/umap/user_map_table.html +7 -2
  194. umap/tests/integration/conftest.py +2 -6
  195. umap/tests/integration/test_anonymous_owned_map.py +89 -36
  196. umap/tests/integration/test_basics.py +25 -1
  197. umap/tests/integration/test_browser.py +37 -0
  198. umap/tests/integration/test_datalayer.py +9 -16
  199. umap/tests/integration/test_draw_polygon.py +2 -0
  200. umap/tests/integration/test_edit_marker.py +1 -1
  201. umap/tests/integration/test_export_map.py +19 -0
  202. umap/tests/integration/test_fields.py +522 -0
  203. umap/tests/integration/test_filters.py +617 -0
  204. umap/tests/integration/test_import.py +15 -42
  205. umap/tests/integration/test_remote_data.py +60 -4
  206. umap/tests/integration/test_share.py +4 -4
  207. umap/tests/integration/test_tableeditor.py +31 -7
  208. umap/tests/integration/test_websocket_sync.py +3 -1
  209. umap/tests/test_dashboard.py +10 -0
  210. umap/urls.py +1 -0
  211. umap/views.py +5 -0
  212. {umap_project-3.3.5.dist-info → umap_project-3.4.0b0.dist-info}/METADATA +12 -12
  213. {umap_project-3.3.5.dist-info → umap_project-3.4.0b0.dist-info}/RECORD +216 -213
  214. umap/static/umap/js/modules/facets.js +0 -164
  215. umap/tests/integration/test_facets_browser.py +0 -279
  216. {umap_project-3.3.5.dist-info → umap_project-3.4.0b0.dist-info}/WHEEL +0 -0
  217. {umap_project-3.3.5.dist-info → umap_project-3.4.0b0.dist-info}/entry_points.txt +0 -0
  218. {umap_project-3.3.5.dist-info → umap_project-3.4.0b0.dist-info}/licenses/LICENSE +0 -0
@@ -1,7 +1,7 @@
1
1
  import { translate } from '../i18n.js'
2
2
  import { SCHEMA } from '../schema.js'
3
3
  import * as Utils from '../utils.js'
4
- import getClass from './fields.js'
4
+ import { getClass } from './fields.js'
5
5
 
6
6
  export class Form extends Utils.WithEvents {
7
7
  constructor(obj, fields, properties) {
@@ -84,7 +84,7 @@ export class Form extends Utils.WithEvents {
84
84
 
85
85
  getName(field) {
86
86
  const fieldEls = field.split('.')
87
- return fieldEls[fieldEls.length - 1]
87
+ return Utils.escapeHTML(fieldEls[fieldEls.length - 1])
88
88
  }
89
89
 
90
90
  fetchAll() {
@@ -107,14 +107,18 @@ export class Form extends Utils.WithEvents {
107
107
 
108
108
  finish() {}
109
109
 
110
- getTemplate(helper) {
110
+ getHelperTemplate(helper) {
111
111
  let tpl = helper.getTemplate()
112
112
  if (helper.properties.label && !tpl.includes(helper.properties.label)) {
113
113
  tpl = `<label>${helper.properties.label}${tpl}</label>`
114
114
  }
115
+ return tpl
116
+ }
117
+
118
+ getTemplate(helper) {
115
119
  return `
116
120
  <div class="formbox" data-ref=container>
117
- ${tpl}
121
+ ${this.getHelperTemplate(helper)}
118
122
  <small class="help-text" data-ref=helpText></small>
119
123
  </div>`
120
124
  }
@@ -132,7 +136,6 @@ export class MutatingForm extends Form {
132
136
  const customHandlers = {
133
137
  sortKey: 'PropertyInput',
134
138
  easing: 'Switch',
135
- facetKey: 'PropertyInput',
136
139
  slugKey: 'PropertyInput',
137
140
  labelKey: 'PropertyInput',
138
141
  color: 'ColorPicker',
@@ -8,15 +8,15 @@ import * as Icon from '../rendering/icon.js'
8
8
  import { SCHEMA } from '../schema.js'
9
9
  import * as Utils from '../utils.js'
10
10
 
11
- const Fields = {}
11
+ export const Fields = {}
12
12
 
13
- export default function getClass(name) {
13
+ export function getClass(name) {
14
14
  if (typeof name === 'function') return name
15
15
  if (!Fields[name]) throw Error(`Unknown class ${name}`)
16
16
  return Fields[name]
17
17
  }
18
18
 
19
- class BaseElement {
19
+ Fields.Base = class {
20
20
  constructor(builder, field, properties) {
21
21
  this.builder = builder
22
22
  this.obj = this.builder.obj
@@ -25,7 +25,7 @@ class BaseElement {
25
25
  this.setProperties(properties)
26
26
  this.fieldEls = this.field.split('.')
27
27
  this.name = this.builder.getName(field)
28
- this.id = `${this.builder.properties.id || Date.now()}.${this.name}`
28
+ this.id = `id.${this.builder.properties.id || Date.now()}.${this.name}`
29
29
  }
30
30
 
31
31
  getDefaultProperties() {
@@ -49,6 +49,7 @@ class BaseElement {
49
49
  this.elements = elements
50
50
  this.container = elements.container
51
51
  this.form.appendChild(this.root)
52
+ return [root, elements]
52
53
  }
53
54
 
54
55
  getTemplate() {
@@ -56,6 +57,7 @@ class BaseElement {
56
57
  }
57
58
 
58
59
  build() {
60
+ if (!this.elements.helpText) return
59
61
  if (this.properties.helpText) {
60
62
  this.elements.helpText.textContent = this.properties.helpText
61
63
  } else {
@@ -113,9 +115,7 @@ class BaseElement {
113
115
  getLabelTemplate() {
114
116
  const label = this.properties.label
115
117
  const help = this.properties.helpEntries?.join() || ''
116
- return label
117
- ? `<label title="${label}" data-ref=label data-help="${help}">${label}</label>`
118
- : ''
118
+ return label ? `<label data-ref=label data-help="${help}">${label}</label>` : ''
119
119
  }
120
120
 
121
121
  fetch() {}
@@ -129,7 +129,7 @@ class BaseElement {
129
129
  }
130
130
  }
131
131
 
132
- Fields.Textarea = class extends BaseElement {
132
+ Fields.Textarea = class extends Fields.Base {
133
133
  getTemplate() {
134
134
  return `<textarea placeholder="${this.properties.placeholder || ''}" name="${this.name}" data-ref=textarea></textarea>`
135
135
  }
@@ -169,7 +169,7 @@ Fields.Textarea = class extends BaseElement {
169
169
  }
170
170
  }
171
171
 
172
- Fields.Input = class extends BaseElement {
172
+ Fields.Input = class extends Fields.Base {
173
173
  getTemplate() {
174
174
  return `<input type="${this.type()}" name="${this.name}" placeholder="${this.properties.placeholder || ''}" data-ref=input />`
175
175
  }
@@ -190,6 +190,9 @@ Fields.Input = class extends BaseElement {
190
190
  if (this.properties.step) {
191
191
  this.input.step = this.properties.step
192
192
  }
193
+ if (this.properties.disabled) {
194
+ this.input.disabled = true
195
+ }
193
196
  this.fetch()
194
197
  this.listenForSync()
195
198
  this.input.addEventListener('keydown', (event) => this.onKeyDown(event))
@@ -296,7 +299,41 @@ Fields.BlurFloatInput = class extends FloatMixin(Fields.BlurInput) {
296
299
  }
297
300
  }
298
301
 
299
- Fields.CheckBox = class extends BaseElement {
302
+ const DateMixin = (Base) =>
303
+ class extends Base {
304
+ toHTML() {
305
+ const raw = super.toHTML()
306
+ if (!raw) return null
307
+ const parsed = Utils.parseNaiveDate(raw)
308
+ if (!parsed) return null
309
+ return parsed.toISOString().substring(0, 10)
310
+ }
311
+
312
+ type() {
313
+ return 'date'
314
+ }
315
+ }
316
+
317
+ Fields.DateInput = class extends DateMixin(Fields.Input) {}
318
+
319
+ const DateTimeMixin = (Base) =>
320
+ class extends Base {
321
+ toHTML() {
322
+ const raw = super.toHTML()
323
+ if (!raw) return null
324
+ const datetime = new Date(raw)
325
+ if (isNaN(datetime)) return null
326
+ return datetime.toISOString()
327
+ }
328
+
329
+ type() {
330
+ return 'datetime-local'
331
+ }
332
+ }
333
+
334
+ Fields.DateTimeInput = class extends DateTimeMixin(Fields.Input) {}
335
+
336
+ Fields.CheckBox = class extends Fields.Base {
300
337
  getTemplate() {
301
338
  return `<input type=checkbox name="${this.name}" data-ref=input />`
302
339
  }
@@ -327,7 +364,7 @@ Fields.CheckBox = class extends BaseElement {
327
364
  }
328
365
  }
329
366
 
330
- Fields.CheckBoxes = class extends BaseElement {
367
+ Fields.CheckBoxes = class extends Fields.Base {
331
368
  getInputTemplate(value, label) {
332
369
  return `<label><input type=checkbox value="${value}" name="${this.name}" data-ref=input />${label}</label>`
333
370
  }
@@ -350,13 +387,16 @@ Fields.CheckBoxes = class extends BaseElement {
350
387
  }
351
388
  }
352
389
 
353
- Fields.Select = class extends BaseElement {
390
+ Fields.Select = class extends Fields.Base {
354
391
  getTemplate() {
355
392
  return `<select name="${this.name}" data-ref=select></select>`
356
393
  }
357
394
 
358
395
  build() {
359
396
  this.select = this.elements.select
397
+ if (this.properties.disabled) {
398
+ this.select.disabled = true
399
+ }
360
400
  this.validValues = []
361
401
  this.buildOptions()
362
402
  this.select.addEventListener('change', () => this.sync())
@@ -423,7 +463,7 @@ Fields.IntSelect = class extends Fields.Select {
423
463
  }
424
464
  }
425
465
 
426
- Fields.EditableText = class extends BaseElement {
466
+ Fields.EditableText = class extends Fields.Base {
427
467
  getTemplate() {
428
468
  return `<span class="${this.properties.className || ''}" data-ref=input></span>`
429
469
  }
@@ -579,12 +619,9 @@ Fields.SlideshowDelay = class extends Fields.IntSelect {
579
619
  }
580
620
  }
581
621
 
582
- Fields.DataLayerSwitcher = class extends Fields.Select {
622
+ const BaseDataLayerSwitcher = class extends Fields.Select {
583
623
  getOptions() {
584
624
  const options = []
585
- if (this.properties.allowEmpty) {
586
- options.push([null, translate('Import in a new layer')])
587
- }
588
625
  this.builder._umap.datalayers.reverse().map((datalayer) => {
589
626
  if (
590
627
  datalayer.isLoaded() &&
@@ -611,6 +648,36 @@ Fields.DataLayerSwitcher = class extends Fields.Select {
611
648
  }
612
649
  }
613
650
 
651
+ Fields.NullableDataLayerSwitcher = class extends BaseDataLayerSwitcher {
652
+ getOptions() {
653
+ const options = super.getOptions()
654
+ options.unshift([null, translate('Import in a new layer')])
655
+ return options
656
+ }
657
+ }
658
+
659
+ Fields.EditableDataLayerSwitcher = class extends BaseDataLayerSwitcher {
660
+ getTemplate() {
661
+ return `
662
+ <div class="select-with-actions">
663
+ ${super.getTemplate()}
664
+ <button type="button" class="icon icon-16 icon-edit flat" data-ref=openEditPanel></button>
665
+ <button type="button" class="icon icon-16 icon-table flat" data-ref=openTableEditor></button>
666
+ </div>
667
+ `
668
+ }
669
+
670
+ build() {
671
+ super.build()
672
+ this.elements.openEditPanel.addEventListener('click', () => {
673
+ this.obj.datalayer.edit()
674
+ })
675
+ this.elements.openTableEditor.addEventListener('click', () => {
676
+ this.obj.datalayer.tableEdit()
677
+ })
678
+ }
679
+ }
680
+
614
681
  Fields.DataFormat = class extends Fields.Select {
615
682
  getOptions() {
616
683
  return [
@@ -689,6 +756,15 @@ Fields.IconUrl = class extends Fields.BlurInput {
689
756
  return 'hidden'
690
757
  }
691
758
 
759
+ get() {
760
+ // We never want to have parent value here
761
+ // TODO: check if/when we need the getOption call
762
+ // in the super method, maybe it's useless for all fields.
763
+ const path = this.field.split('.')
764
+ const key = path[path.length - 1]
765
+ return this.builder.getter(this.field)
766
+ }
767
+
692
768
  getTemplate() {
693
769
  return `
694
770
  <div>
@@ -964,216 +1040,27 @@ Fields.Url = class extends Fields.Input {
964
1040
  }
965
1041
 
966
1042
  Fields.Switch = class extends Fields.CheckBox {
1043
+ getLabelTemplate() {
1044
+ if (!this.properties.inheritable) return ''
1045
+ return super.getLabelTemplate()
1046
+ }
967
1047
  getTemplate() {
968
- const label = this.properties.label
969
- const help = this.properties.helpEntries?.join() || ''
970
- return `${super.getTemplate()}<label title="${label}" for="${this.id}" data-ref=customLabel data-help="${help}">${label}</label>`
1048
+ const label = this.properties.inheritable ? '' : this.properties.label
1049
+ const help = this.properties.inheritable
1050
+ ? ''
1051
+ : this.properties.helpEntries?.join() || ''
1052
+ return `${super.getTemplate()}<label for="${this.id}" data-ref=customLabel data-help="${help}">${label}</label>`
971
1053
  }
972
1054
 
973
1055
  build() {
974
1056
  super.build()
975
- // We have it in our template
976
- if (!this.properties.inheritable) {
977
- // We already have the label near the switch,
978
- // only show the default label in inheritable mode
979
- // as the switch itself may be hidden (until "defined")
980
- if (this.elements.label) {
981
- this.elements.label.hidden = true
982
- this.elements.label.innerHTML = ''
983
- this.elements.label.title = ''
984
- }
985
- }
986
1057
  this.container.classList.add('with-switch')
987
1058
  this.input.classList.add('switch')
988
1059
  this.input.id = this.id
989
1060
  }
990
1061
  }
991
1062
 
992
- Fields.FacetSearchBase = class extends BaseElement {
993
- buildLabel() {}
994
- }
995
-
996
- Fields.FacetSearchChoices = class extends Fields.FacetSearchBase {
997
- getTemplate() {
998
- return `
999
- <fieldset class="umap-facet">
1000
- <legend data-ref=label>${Utils.escapeHTML(this.properties.label)}</legend>
1001
- <ul data-ref=ul></ul>
1002
- </fieldset>
1003
- `
1004
- }
1005
-
1006
- build() {
1007
- this.type = this.properties.criteria.type
1008
-
1009
- const choices = this.properties.criteria.choices
1010
- choices.sort()
1011
- choices.forEach((value) => this.buildLi(value))
1012
- super.build()
1013
- }
1014
-
1015
- buildLi(value) {
1016
- const name = `${this.type}_${this.name}`
1017
- const [li, { input, label }] = Utils.loadTemplateWithRefs(`
1018
- <li>
1019
- <label>
1020
- <input type="${this.type}" name="${name}" data-ref=input />
1021
- <span data-ref=label></span>
1022
- </label>
1023
- </li>
1024
- `)
1025
- label.textContent = value
1026
- input.checked = this.get().choices.includes(value)
1027
- input.dataset.value = value
1028
- input.addEventListener('change', () => this.sync())
1029
- this.elements.ul.appendChild(li)
1030
- }
1031
-
1032
- toJS() {
1033
- return {
1034
- type: this.type,
1035
- choices: [...this.elements.ul.querySelectorAll('input:checked')].map(
1036
- (i) => i.dataset.value
1037
- ),
1038
- }
1039
- }
1040
- }
1041
-
1042
- Fields.MinMaxBase = class extends Fields.FacetSearchBase {
1043
- getInputType(type) {
1044
- return type
1045
- }
1046
-
1047
- getLabels() {
1048
- return [translate('Min'), translate('Max')]
1049
- }
1050
-
1051
- prepareForHTML(value) {
1052
- return value.valueOf()
1053
- }
1054
-
1055
- getTemplate() {
1056
- const [minLabel, maxLabel] = this.getLabels()
1057
- const { min, max, type } = this.properties.criteria
1058
- this.type = type
1059
- const inputType = this.getInputType(this.type)
1060
- const minHTML = this.prepareForHTML(min)
1061
- const maxHTML = this.prepareForHTML(max)
1062
- return `
1063
- <fieldset class="umap-facet">
1064
- <legend>${Utils.escapeHTML(this.properties.label)}</legend>
1065
- <label>${minLabel}<input min="${minHTML}" max="${maxHTML}" step=any type="${inputType}" data-ref=minInput /></label>
1066
- <label>${maxLabel}<input min="${minHTML}" max="${maxHTML}" step=any type="${inputType}" data-ref=maxInput /></label>
1067
- </fieldset>
1068
- `
1069
- }
1070
-
1071
- build() {
1072
- this.minInput = this.elements.minInput
1073
- this.maxInput = this.elements.maxInput
1074
- const { min, max, type } = this.properties.criteria
1075
- const { min: modifiedMin, max: modifiedMax } = this.get()
1076
-
1077
- const currentMin = modifiedMin !== undefined ? modifiedMin : min
1078
- const currentMax = modifiedMax !== undefined ? modifiedMax : max
1079
- if (min != null) {
1080
- // The value stored using setAttribute is not modified by
1081
- // user input, and will be used as initial value when calling
1082
- // form.reset(), and can also be retrieve later on by using
1083
- // getAttributing, to compare with current value and know
1084
- // if this value has been modified by the user
1085
- // https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reset
1086
- this.minInput.setAttribute('value', this.prepareForHTML(min))
1087
- this.minInput.value = this.prepareForHTML(currentMin)
1088
- }
1089
-
1090
- if (max != null) {
1091
- // Cf comment above about setAttribute vs value
1092
- this.maxInput.setAttribute('value', this.prepareForHTML(max))
1093
- this.maxInput.value = this.prepareForHTML(currentMax)
1094
- }
1095
- this.toggleStatus()
1096
-
1097
- this.minInput.addEventListener('change', () => this.sync())
1098
- this.maxInput.addEventListener('change', () => this.sync())
1099
- super.build()
1100
- }
1101
-
1102
- toggleStatus() {
1103
- this.minInput.dataset.modified = this.isMinModified()
1104
- this.maxInput.dataset.modified = this.isMaxModified()
1105
- }
1106
-
1107
- sync() {
1108
- super.sync()
1109
- this.toggleStatus()
1110
- }
1111
-
1112
- isMinModified() {
1113
- const default_ = this.minInput.getAttribute('value')
1114
- const current = this.minInput.value
1115
- return current !== default_
1116
- }
1117
-
1118
- isMaxModified() {
1119
- const default_ = this.maxInput.getAttribute('value')
1120
- const current = this.maxInput.value
1121
- return current !== default_
1122
- }
1123
-
1124
- toJS() {
1125
- const opts = {
1126
- type: this.type,
1127
- }
1128
- if (this.minInput.value !== '' && this.isMinModified()) {
1129
- opts.min = this.prepareForJS(this.minInput.value)
1130
- }
1131
- if (this.maxInput.value !== '' && this.isMaxModified()) {
1132
- opts.max = this.prepareForJS(this.maxInput.value)
1133
- }
1134
- return opts
1135
- }
1136
- }
1137
-
1138
- Fields.FacetSearchNumber = class extends Fields.MinMaxBase {
1139
- prepareForJS(value) {
1140
- return new Number(value)
1141
- }
1142
- }
1143
-
1144
- Fields.FacetSearchDate = class extends Fields.MinMaxBase {
1145
- prepareForJS(value) {
1146
- return new Date(value)
1147
- }
1148
-
1149
- toLocaleDateTime(dt) {
1150
- return new Date(dt.valueOf() - dt.getTimezoneOffset() * 60000)
1151
- }
1152
-
1153
- prepareForHTML(value) {
1154
- // Value must be in local time
1155
- if (Number.isNaN(value)) return
1156
- return this.toLocaleDateTime(value).toISOString().substr(0, 10)
1157
- }
1158
-
1159
- getLabels() {
1160
- return [translate('From'), translate('Until')]
1161
- }
1162
- }
1163
-
1164
- Fields.FacetSearchDateTime = class extends Fields.FacetSearchDate {
1165
- getInputType(type) {
1166
- return 'datetime-local'
1167
- }
1168
-
1169
- prepareForHTML(value) {
1170
- // Value must be in local time
1171
- if (Number.isNaN(value)) return
1172
- return this.toLocaleDateTime(value).toISOString().slice(0, -1)
1173
- }
1174
- }
1175
-
1176
- Fields.MultiChoice = class extends BaseElement {
1063
+ Fields.MultiChoice = class extends Fields.Base {
1177
1064
  getDefault() {
1178
1065
  return 'null'
1179
1066
  }
@@ -1207,7 +1094,10 @@ Fields.MultiChoice = class extends BaseElement {
1207
1094
  }
1208
1095
 
1209
1096
  getChoices() {
1210
- return this.properties.choices || this.choices
1097
+ let choices = this.properties.choices || this.choices
1098
+ // Allow to pass flat arrays [c1, c2, c3] instead of [[c1, v1], [c2, v2]]
1099
+ if (!Array.isArray(choices[0])) choices = choices.map((key) => [key, key])
1100
+ return choices
1211
1101
  }
1212
1102
 
1213
1103
  getTemplate() {
@@ -1224,7 +1114,7 @@ Fields.MultiChoice = class extends BaseElement {
1224
1114
  }
1225
1115
 
1226
1116
  addChoice(value, label, counter) {
1227
- const id = `${Date.now()}.${this.name}.${counter}`
1117
+ const id = `id.${Date.now()}.${this.name}.${counter}`
1228
1118
  const input = Utils.loadTemplate(
1229
1119
  `<input type="radio" name="${this.name}" id="${id}" value="${value}" />`
1230
1120
  )
@@ -1322,7 +1212,7 @@ Fields.Range = class extends Fields.FloatInput {
1322
1212
  }
1323
1213
  }
1324
1214
 
1325
- Fields.ManageOwner = class extends BaseElement {
1215
+ Fields.ManageOwner = class extends Fields.Base {
1326
1216
  build() {
1327
1217
  super.build()
1328
1218
  const options = {
@@ -1353,7 +1243,7 @@ Fields.ManageOwner = class extends BaseElement {
1353
1243
  }
1354
1244
  }
1355
1245
 
1356
- Fields.ManageEditors = class extends BaseElement {
1246
+ Fields.ManageEditors = class extends Fields.Base {
1357
1247
  build() {
1358
1248
  super.build()
1359
1249
  const options = {
@@ -32,6 +32,10 @@ export const EXPORT_FORMATS = {
32
32
  ext: '.csv',
33
33
  filetype: 'text/csv',
34
34
  },
35
+ wkt: {
36
+ ext: '.csv',
37
+ filetype: 'text/csv',
38
+ },
35
39
  }
36
40
 
37
41
  export class Formatter {
@@ -84,7 +88,12 @@ export class Formatter {
84
88
  const first = result.features[0]
85
89
  if (first.geometry === null) {
86
90
  const geomFields = ['geom', 'geometry', 'wkt', 'geojson']
87
- for (const field of geomFields) {
91
+ const availableFields = Object.keys(first.properties).reduce((acc, key) => {
92
+ acc[key.toLowerCase()] = key
93
+ return acc
94
+ }, {})
95
+ for (let field of geomFields) {
96
+ field = availableFields[field]
88
97
  if (first.properties[field]) {
89
98
  for (const feature of result.features) {
90
99
  feature.geometry = await parseTextGeom(feature.properties[field])
@@ -169,6 +178,8 @@ export class Formatter {
169
178
  switch (format) {
170
179
  case 'csv':
171
180
  return await this.toCSV(features)
181
+ case 'wkt':
182
+ return await this.toWKT(features)
172
183
  case 'gpx':
173
184
  return await this.toGPX(features)
174
185
  case 'kml':
@@ -215,4 +226,16 @@ export class Formatter {
215
226
  }
216
227
  return csv2geojson.dsv.csvFormat(table)
217
228
  }
229
+
230
+ async toWKT(features) {
231
+ const table = []
232
+ const betterknown = await import('../../vendors/betterknown/betterknown.mjs')
233
+ for (const feature of features) {
234
+ const row = feature.toGeoJSON().properties
235
+ delete row._umap_options
236
+ row.geometry = betterknown.geoJSONToWkt(feature.geometry)
237
+ table.push(row)
238
+ }
239
+ return csv2geojson.dsv.csvFormat(table)
240
+ }
218
241
  }
@@ -92,8 +92,8 @@ const ENTRIES = {
92
92
  filterKey: translate(
93
93
  'Comma separated list of properties to use when filtering features by text input'
94
94
  ),
95
- facetKey: translate(
96
- 'Comma separated list of properties to use for filters (eg.: mykey,otherkey). To control label, add it after a | (eg.: mykey|My Key,otherkey|Other Key). To control input field type, add it after another | (eg.: mykey|My Key|checkbox,otherkey|Other Key|datetime). Allowed values for the input field type are checkbox (default), radio, number, date and datetime.'
95
+ filters: translate(
96
+ 'Filters will be displayed in the data browser to ease data selection.'
97
97
  ),
98
98
  interactive: translate(
99
99
  'If false, the polygon or line will act as a part of the underlying map.'
@@ -170,6 +170,7 @@ const ENTRIES = {
170
170
  <li>${translate('key!=value (eg. building!=yes)')}</li>
171
171
  <li>${translate('key~value (eg. name~Grisy)')}</li>
172
172
  <li>${translate('key="value|value2" (eg. name="Paris|Berlin")')}</li>
173
+ <li>${translate('[key="value"][key2="value2"] (eg. [boundary="educational"][name="Académie de Lyon"])')}</li>
173
174
  </ul>
174
175
  <div>${translate('More info about Overpass syntax')}: <a href="https://wiki.openstreetmap.org/wiki/Overpass_API/Language_Guide">https://wiki.openstreetmap.org/wiki/Overpass_API/Language_Guide</a></div>
175
176
  <div>${translate('For more complex needs, see')} <a href="https://overpass-turbo.eu/">https://overpass-turbo.eu/</a></div>
@@ -33,6 +33,11 @@ const PORTALS = [
33
33
  url: 'https://opendata.clermont-ferrand.fr',
34
34
  platform: 'opendatasoft',
35
35
  },
36
+ {
37
+ name: 'Ministère de la Culture',
38
+ url: 'https://data.culture.gouv.fr',
39
+ platform: 'opendatasoft',
40
+ },
36
41
  {
37
42
  name: 'Métropole de Dijon',
38
43
  url: 'https://data.metropole-dijon.fr',
@@ -37,7 +37,7 @@ export class Importer {
37
37
  }
38
38
 
39
39
  const metadatas = [
40
- ['datalayer', { handler: 'DataLayerSwitcher', allowEmpty: true }],
40
+ ['datalayer', { handler: 'NullableDataLayerSwitcher' }],
41
41
  [
42
42
  'profile',
43
43
  { handler: 'Select', selectOptions: PROFILES, label: translate('Profile') },
@@ -82,6 +82,11 @@ export class Importer {
82
82
  params.interval = (properties.range / properties.lines) * 60
83
83
  }
84
84
  const data = await Isochrones.calculate(params)
85
+ data.features.reverse()
86
+ for (const feature of data.features) {
87
+ feature.properties.duration = Number(feature.properties.value) / 60
88
+ feature.properties.profile = properties.profile
89
+ }
85
90
  this.umap.importer.build()
86
91
  this.umap.importer.raw = JSON.stringify(data)
87
92
  this.umap.importer.format = 'geojson'