umap-project 2.8.2__py3-none-any.whl → 2.9.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 (157) hide show
  1. umap/__init__.py +1 -1
  2. umap/asgi.py +12 -7
  3. umap/context_processors.py +1 -0
  4. umap/locale/en/LC_MESSAGES/django.po +102 -59
  5. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  6. umap/locale/fr/LC_MESSAGES/django.po +105 -61
  7. umap/management/commands/empty_trash.py +12 -1
  8. umap/migrations/0026_datalayer_modified_at_datalayer_share_status.py +26 -0
  9. umap/models.py +23 -3
  10. umap/settings/base.py +4 -1
  11. umap/static/umap/base.css +1 -1
  12. umap/static/umap/content.css +2 -22
  13. umap/static/umap/css/bar.css +7 -10
  14. umap/static/umap/css/form.css +28 -29
  15. umap/static/umap/css/icon.css +8 -2
  16. umap/static/umap/css/panel.css +2 -1
  17. umap/static/umap/css/tooltip.css +33 -31
  18. umap/static/umap/img/16-white.svg +2 -0
  19. umap/static/umap/img/16.svg +1 -1
  20. umap/static/umap/img/providers/bitbucket.png +0 -0
  21. umap/static/umap/img/providers/github.png +0 -0
  22. umap/static/umap/img/providers/keycloak.png +0 -0
  23. umap/static/umap/img/providers/openstreetmap-oauth2.png +0 -0
  24. umap/static/umap/img/providers/twitter-oauth2.png +0 -0
  25. umap/static/umap/img/source/16-white.svg +3 -1
  26. umap/static/umap/img/source/16.svg +1 -1
  27. umap/static/umap/js/components/alerts/alert.js +4 -1
  28. umap/static/umap/js/modules/browser.js +6 -6
  29. umap/static/umap/js/modules/caption.js +30 -7
  30. umap/static/umap/js/modules/data/features.js +21 -24
  31. umap/static/umap/js/modules/data/layer.js +71 -33
  32. umap/static/umap/js/modules/form/builder.js +241 -0
  33. umap/static/umap/js/modules/form/fields.js +1338 -0
  34. umap/static/umap/js/modules/formatter.js +5 -8
  35. umap/static/umap/js/modules/help.js +3 -1
  36. umap/static/umap/js/modules/importer.js +1 -1
  37. umap/static/umap/js/modules/permissions.js +5 -4
  38. umap/static/umap/js/modules/rendering/icon.js +5 -1
  39. umap/static/umap/js/modules/rendering/layers/classified.js +11 -7
  40. umap/static/umap/js/modules/rendering/layers/cluster.js +11 -1
  41. umap/static/umap/js/modules/rendering/map.js +0 -2
  42. umap/static/umap/js/modules/rules.js +2 -1
  43. umap/static/umap/js/modules/schema.js +5 -6
  44. umap/static/umap/js/modules/share.js +3 -3
  45. umap/static/umap/js/modules/sync/engine.js +18 -13
  46. umap/static/umap/js/modules/sync/updaters.js +8 -0
  47. umap/static/umap/js/modules/sync/websocket.js +10 -5
  48. umap/static/umap/js/modules/tableeditor.js +3 -2
  49. umap/static/umap/js/modules/ui/bar.js +17 -9
  50. umap/static/umap/js/modules/ui/base.js +7 -24
  51. umap/static/umap/js/modules/ui/tooltip.js +19 -11
  52. umap/static/umap/js/modules/umap.js +36 -24
  53. umap/static/umap/js/modules/utils.js +196 -12
  54. umap/static/umap/js/umap.controls.js +0 -12
  55. umap/static/umap/locale/br.js +21 -13
  56. umap/static/umap/locale/br.json +21 -13
  57. umap/static/umap/locale/ca.js +12 -4
  58. umap/static/umap/locale/ca.json +12 -4
  59. umap/static/umap/locale/cs_CZ.js +10 -4
  60. umap/static/umap/locale/cs_CZ.json +10 -4
  61. umap/static/umap/locale/de.js +12 -4
  62. umap/static/umap/locale/de.json +12 -4
  63. umap/static/umap/locale/el.js +12 -4
  64. umap/static/umap/locale/el.json +12 -4
  65. umap/static/umap/locale/en.js +9 -4
  66. umap/static/umap/locale/en.json +9 -4
  67. umap/static/umap/locale/es.js +20 -12
  68. umap/static/umap/locale/es.json +20 -12
  69. umap/static/umap/locale/eu.js +12 -4
  70. umap/static/umap/locale/eu.json +12 -4
  71. umap/static/umap/locale/fa_IR.js +12 -4
  72. umap/static/umap/locale/fa_IR.json +12 -4
  73. umap/static/umap/locale/fr.js +10 -5
  74. umap/static/umap/locale/fr.json +10 -5
  75. umap/static/umap/locale/gl.js +353 -345
  76. umap/static/umap/locale/gl.json +353 -345
  77. umap/static/umap/locale/hu.js +9 -4
  78. umap/static/umap/locale/hu.json +9 -4
  79. umap/static/umap/locale/it.js +100 -92
  80. umap/static/umap/locale/it.json +100 -92
  81. umap/static/umap/locale/ms.js +12 -4
  82. umap/static/umap/locale/ms.json +12 -4
  83. umap/static/umap/locale/nl.js +12 -4
  84. umap/static/umap/locale/nl.json +12 -4
  85. umap/static/umap/locale/pl.js +12 -4
  86. umap/static/umap/locale/pl.json +12 -4
  87. umap/static/umap/locale/pt.js +12 -4
  88. umap/static/umap/locale/pt.json +12 -4
  89. umap/static/umap/locale/pt_PT.js +12 -4
  90. umap/static/umap/locale/pt_PT.json +12 -4
  91. umap/static/umap/locale/th_TH.js +12 -4
  92. umap/static/umap/locale/th_TH.json +12 -4
  93. umap/static/umap/locale/zh_TW.js +10 -4
  94. umap/static/umap/locale/zh_TW.json +10 -4
  95. umap/static/umap/map.css +12 -8
  96. umap/static/umap/nav.css +2 -3
  97. umap/static/umap/unittests/utils.js +14 -0
  98. umap/static/umap/vars.css +2 -0
  99. umap/sync/__init__.py +0 -0
  100. umap/sync/app.py +181 -0
  101. umap/sync/payloads.py +49 -0
  102. umap/templates/auth/user_detail.html +4 -0
  103. umap/templates/auth/user_form.html +9 -6
  104. umap/templates/auth/user_stars.html +4 -0
  105. umap/templates/base.html +1 -1
  106. umap/templates/registration/login.html +2 -5
  107. umap/templates/umap/about.html +5 -0
  108. umap/templates/umap/about_summary.html +2 -2
  109. umap/templates/umap/components/provider.html +8 -0
  110. umap/templates/umap/js.html +0 -3
  111. umap/templates/umap/map_detail.html +1 -1
  112. umap/templates/umap/password_change.html +4 -0
  113. umap/templates/umap/password_change_done.html +4 -0
  114. umap/templates/umap/search.html +4 -0
  115. umap/templates/umap/team_confirm_delete.html +4 -0
  116. umap/templates/umap/team_detail.html +4 -0
  117. umap/templates/umap/team_form.html +4 -0
  118. umap/templates/umap/user_dashboard.html +1 -1
  119. umap/templates/umap/user_teams.html +4 -0
  120. umap/tests/base.py +3 -1
  121. umap/tests/integration/conftest.py +16 -23
  122. umap/tests/integration/test_basics.py +2 -2
  123. umap/tests/integration/test_caption.py +1 -0
  124. umap/tests/integration/test_draw_polygon.py +3 -3
  125. umap/tests/integration/test_edit_datalayer.py +1 -1
  126. umap/tests/integration/test_edit_map.py +3 -3
  127. umap/tests/integration/test_edit_polygon.py +1 -1
  128. umap/tests/integration/test_import.py +23 -1
  129. umap/tests/integration/test_optimistic_merge.py +1 -0
  130. umap/tests/integration/test_picto.py +8 -8
  131. umap/tests/integration/test_save.py +1 -0
  132. umap/tests/integration/test_star.py +13 -9
  133. umap/tests/integration/test_tableeditor.py +1 -0
  134. umap/tests/integration/test_websocket_sync.py +112 -33
  135. umap/tests/settings.py +2 -0
  136. umap/tests/test_datalayer.py +2 -3
  137. umap/tests/test_datalayer_views.py +20 -1
  138. umap/tests/test_empty_trash.py +10 -3
  139. umap/tests/test_map_views.py +11 -0
  140. umap/utils.py +24 -11
  141. umap/views.py +37 -6
  142. {umap_project-2.8.2.dist-info → umap_project-2.9.0b0.dist-info}/METADATA +15 -15
  143. {umap_project-2.8.2.dist-info → umap_project-2.9.0b0.dist-info}/RECORD +146 -145
  144. {umap_project-2.8.2.dist-info → umap_project-2.9.0b0.dist-info}/WHEEL +1 -1
  145. umap/management/commands/run_websocket_server.py +0 -23
  146. umap/settings/local_s3.py +0 -45
  147. umap/static/umap/bitbucket.png +0 -0
  148. umap/static/umap/github.png +0 -0
  149. umap/static/umap/js/umap.forms.js +0 -1242
  150. umap/static/umap/keycloak.png +0 -0
  151. umap/static/umap/openstreetmap.png +0 -0
  152. umap/static/umap/twitter.png +0 -0
  153. umap/static/umap/vendors/formbuilder/Leaflet.FormBuilder.js +0 -468
  154. umap/tests/test_websocket_server.py +0 -22
  155. umap/websocket_server.py +0 -202
  156. {umap_project-2.8.2.dist-info → umap_project-2.9.0b0.dist-info}/entry_points.txt +0 -0
  157. {umap_project-2.8.2.dist-info → umap_project-2.9.0b0.dist-info}/licenses/LICENSE +0 -0
@@ -1,1242 +0,0 @@
1
- U.COLORS = [
2
- 'Black',
3
- 'Navy',
4
- 'DarkBlue',
5
- 'MediumBlue',
6
- 'Blue',
7
- 'DarkGreen',
8
- 'Green',
9
- 'Teal',
10
- 'DarkCyan',
11
- 'DeepSkyBlue',
12
- 'DarkTurquoise',
13
- 'MediumSpringGreen',
14
- 'Lime',
15
- 'SpringGreen',
16
- 'Aqua',
17
- 'Cyan',
18
- 'MidnightBlue',
19
- 'DodgerBlue',
20
- 'LightSeaGreen',
21
- 'ForestGreen',
22
- 'SeaGreen',
23
- 'DarkSlateGray',
24
- 'DarkSlateGrey',
25
- 'LimeGreen',
26
- 'MediumSeaGreen',
27
- 'Turquoise',
28
- 'RoyalBlue',
29
- 'SteelBlue',
30
- 'DarkSlateBlue',
31
- 'MediumTurquoise',
32
- 'Indigo',
33
- 'DarkOliveGreen',
34
- 'CadetBlue',
35
- 'CornflowerBlue',
36
- 'MediumAquaMarine',
37
- 'DimGray',
38
- 'DimGrey',
39
- 'SlateBlue',
40
- 'OliveDrab',
41
- 'SlateGray',
42
- 'SlateGrey',
43
- 'LightSlateGray',
44
- 'LightSlateGrey',
45
- 'MediumSlateBlue',
46
- 'LawnGreen',
47
- 'Chartreuse',
48
- 'Aquamarine',
49
- 'Maroon',
50
- 'Purple',
51
- 'Olive',
52
- 'Gray',
53
- 'Grey',
54
- 'SkyBlue',
55
- 'LightSkyBlue',
56
- 'BlueViolet',
57
- 'DarkRed',
58
- 'DarkMagenta',
59
- 'SaddleBrown',
60
- 'DarkSeaGreen',
61
- 'LightGreen',
62
- 'MediumPurple',
63
- 'DarkViolet',
64
- 'PaleGreen',
65
- 'DarkOrchid',
66
- 'YellowGreen',
67
- 'Sienna',
68
- 'Brown',
69
- 'DarkGray',
70
- 'DarkGrey',
71
- 'LightBlue',
72
- 'GreenYellow',
73
- 'PaleTurquoise',
74
- 'LightSteelBlue',
75
- 'PowderBlue',
76
- 'FireBrick',
77
- 'DarkGoldenRod',
78
- 'MediumOrchid',
79
- 'RosyBrown',
80
- 'DarkKhaki',
81
- 'Silver',
82
- 'MediumVioletRed',
83
- 'IndianRed',
84
- 'Peru',
85
- 'Chocolate',
86
- 'Tan',
87
- 'LightGray',
88
- 'LightGrey',
89
- 'Thistle',
90
- 'Orchid',
91
- 'GoldenRod',
92
- 'PaleVioletRed',
93
- 'Crimson',
94
- 'Gainsboro',
95
- 'Plum',
96
- 'BurlyWood',
97
- 'LightCyan',
98
- 'Lavender',
99
- 'DarkSalmon',
100
- 'Violet',
101
- 'PaleGoldenRod',
102
- 'LightCoral',
103
- 'Khaki',
104
- 'AliceBlue',
105
- 'HoneyDew',
106
- 'Azure',
107
- 'SandyBrown',
108
- 'Wheat',
109
- 'Beige',
110
- 'WhiteSmoke',
111
- 'MintCream',
112
- 'GhostWhite',
113
- 'Salmon',
114
- 'AntiqueWhite',
115
- 'Linen',
116
- 'LightGoldenRodYellow',
117
- 'OldLace',
118
- 'Red',
119
- 'Fuchsia',
120
- 'Magenta',
121
- 'DeepPink',
122
- 'OrangeRed',
123
- 'Tomato',
124
- 'HotPink',
125
- 'Coral',
126
- 'DarkOrange',
127
- 'LightSalmon',
128
- 'Orange',
129
- 'LightPink',
130
- 'Pink',
131
- 'Gold',
132
- 'PeachPuff',
133
- 'NavajoWhite',
134
- 'Moccasin',
135
- 'Bisque',
136
- 'MistyRose',
137
- 'BlanchedAlmond',
138
- 'PapayaWhip',
139
- 'LavenderBlush',
140
- 'SeaShell',
141
- 'Cornsilk',
142
- 'LemonChiffon',
143
- 'FloralWhite',
144
- 'Snow',
145
- 'Yellow',
146
- 'LightYellow',
147
- 'Ivory',
148
- 'White',
149
- ]
150
-
151
- L.FormBuilder.Element.include({
152
- undefine: function () {
153
- L.DomUtil.addClass(this.wrapper, 'undefined')
154
- this.clear()
155
- this.sync()
156
- },
157
-
158
- getParentNode: function () {
159
- if (this.options.wrapper) {
160
- return L.DomUtil.create(
161
- this.options.wrapper,
162
- this.options.wrapperClass || '',
163
- this.form
164
- )
165
- }
166
- let className = 'formbox'
167
- if (this.options.inheritable) {
168
- className +=
169
- this.get(true) === undefined ? ' inheritable undefined' : ' inheritable '
170
- }
171
- className += ` umap-field-${this.name}`
172
- this.wrapper = L.DomUtil.create('div', className, this.form)
173
- this.header = L.DomUtil.create('div', 'header', this.wrapper)
174
- if (this.options.inheritable) {
175
- const undefine = L.DomUtil.add('a', 'button undefine', this.header, L._('clear'))
176
- const define = L.DomUtil.add('a', 'button define', this.header, L._('define'))
177
- L.DomEvent.on(
178
- define,
179
- 'click',
180
- function (e) {
181
- L.DomEvent.stop(e)
182
- this.fetch()
183
- this.fire('define')
184
- L.DomUtil.removeClass(this.wrapper, 'undefined')
185
- },
186
- this
187
- )
188
- L.DomEvent.on(undefine, 'click', L.DomEvent.stop).on(
189
- undefine,
190
- 'click',
191
- this.undefine,
192
- this
193
- )
194
- }
195
- this.quickContainer = L.DomUtil.create(
196
- 'span',
197
- 'quick-actions show-on-defined',
198
- this.header
199
- )
200
- this.extendedContainer = L.DomUtil.create('div', 'show-on-defined', this.wrapper)
201
- return this.extendedContainer
202
- },
203
-
204
- getLabelParent: function () {
205
- return this.header
206
- },
207
-
208
- clear: function () {
209
- this.input.value = ''
210
- },
211
-
212
- get: function (own) {
213
- if (!this.options.inheritable || own) return this.builder.getter(this.field)
214
- const path = this.field.split('.')
215
- const key = path[path.length - 1]
216
- return this.obj.getOption(key)
217
- },
218
-
219
- buildLabel: function () {
220
- if (this.options.label) {
221
- this.label = L.DomUtil.create('label', '', this.getLabelParent())
222
- this.label.textContent = this.label.title = this.options.label
223
- if (this.options.helpEntries) {
224
- this.builder._umap.help.button(this.label, this.options.helpEntries)
225
- } else if (this.options.helpTooltip) {
226
- const info = L.DomUtil.create('i', 'info', this.label)
227
- L.DomEvent.on(info, 'mouseover', () => {
228
- this.builder._umap.tooltip.open({
229
- anchor: info,
230
- content: this.options.helpTooltip,
231
- position: 'top',
232
- })
233
- })
234
- }
235
- }
236
- },
237
- })
238
-
239
- L.FormBuilder.Select.include({
240
- clear: function () {
241
- this.select.value = ''
242
- },
243
-
244
- getDefault: function () {
245
- if (this.options.inheritable) return undefined
246
- return this.getOptions()[0][0]
247
- },
248
- })
249
-
250
- L.FormBuilder.CheckBox.include({
251
- value: function () {
252
- return L.DomUtil.hasClass(this.wrapper, 'undefined')
253
- ? undefined
254
- : this.input.checked
255
- },
256
-
257
- clear: function () {
258
- this.fetch()
259
- },
260
- })
261
-
262
- L.FormBuilder.EditableText = L.FormBuilder.Element.extend({
263
- build: function () {
264
- this.input = L.DomUtil.create('span', this.options.className || '', this.parentNode)
265
- this.input.contentEditable = true
266
- this.fetch()
267
- L.DomEvent.on(this.input, 'input', this.sync, this)
268
- L.DomEvent.on(this.input, 'keypress', this.onKeyPress, this)
269
- },
270
-
271
- getParentNode: function () {
272
- return this.form
273
- },
274
-
275
- value: function () {
276
- return this.input.textContent
277
- },
278
-
279
- fetch: function () {
280
- this.input.textContent = this.toHTML()
281
- },
282
-
283
- onKeyPress: function (event) {
284
- if (event.keyCode === 13) {
285
- event.preventDefault()
286
- this.input.blur()
287
- }
288
- },
289
- })
290
-
291
- L.FormBuilder.ColorPicker = L.FormBuilder.Input.extend({
292
- colors: U.COLORS,
293
- getParentNode: function () {
294
- L.FormBuilder.CheckBox.prototype.getParentNode.call(this)
295
- return this.quickContainer
296
- },
297
-
298
- build: function () {
299
- L.FormBuilder.Input.prototype.build.call(this)
300
- this.input.placeholder = this.options.placeholder || L._('Inherit')
301
- this.container = L.DomUtil.create(
302
- 'div',
303
- 'umap-color-picker',
304
- this.extendedContainer
305
- )
306
- this.container.style.display = 'none'
307
- for (const idx in this.colors) {
308
- this.addColor(this.colors[idx])
309
- }
310
- this.spreadColor()
311
- this.input.autocomplete = 'off'
312
- L.DomEvent.on(this.input, 'focus', this.onFocus, this)
313
- L.DomEvent.on(this.input, 'blur', this.onBlur, this)
314
- L.DomEvent.on(this.input, 'change', this.sync, this)
315
- this.on('define', this.onFocus)
316
- },
317
-
318
- onFocus: function () {
319
- this.container.style.display = 'block'
320
- this.spreadColor()
321
- },
322
-
323
- onBlur: function () {
324
- const closePicker = () => {
325
- this.container.style.display = 'none'
326
- }
327
- // We must leave time for the click to be listened.
328
- window.setTimeout(closePicker, 100)
329
- },
330
-
331
- sync: function () {
332
- this.spreadColor()
333
- L.FormBuilder.Input.prototype.sync.call(this)
334
- },
335
-
336
- spreadColor: function () {
337
- if (this.input.value) this.input.style.backgroundColor = this.input.value
338
- else this.input.style.backgroundColor = 'inherit'
339
- },
340
-
341
- addColor: function (colorName) {
342
- const span = L.DomUtil.create('span', '', this.container)
343
- span.style.backgroundColor = span.title = colorName
344
- const updateColorInput = function () {
345
- this.input.value = colorName
346
- this.sync()
347
- this.container.style.display = 'none'
348
- }
349
- L.DomEvent.on(span, 'mousedown', updateColorInput, this)
350
- },
351
- })
352
-
353
- L.FormBuilder.TextColorPicker = L.FormBuilder.ColorPicker.extend({
354
- colors: [
355
- 'Black',
356
- 'DarkSlateGrey',
357
- 'DimGrey',
358
- 'SlateGrey',
359
- 'LightSlateGrey',
360
- 'Grey',
361
- 'DarkGrey',
362
- 'LightGrey',
363
- 'White',
364
- ],
365
- })
366
-
367
- L.FormBuilder.LayerTypeChooser = L.FormBuilder.Select.extend({
368
- getOptions: () => {
369
- return U.LAYER_TYPES.map((class_) => [class_.TYPE, class_.NAME])
370
- },
371
- })
372
-
373
- L.FormBuilder.SlideshowDelay = L.FormBuilder.IntSelect.extend({
374
- getOptions: () => {
375
- const options = []
376
- for (let i = 1; i < 30; i++) {
377
- options.push([i * 1000, L._('{delay} seconds', { delay: i })])
378
- }
379
- return options
380
- },
381
- })
382
-
383
- L.FormBuilder.DataLayerSwitcher = L.FormBuilder.Select.extend({
384
- getOptions: function () {
385
- const options = []
386
- this.builder._umap.eachDataLayerReverse((datalayer) => {
387
- if (
388
- datalayer.isLoaded() &&
389
- !datalayer.isDataReadOnly() &&
390
- datalayer.isBrowsable()
391
- ) {
392
- options.push([L.stamp(datalayer), datalayer.getName()])
393
- }
394
- })
395
- return options
396
- },
397
-
398
- toHTML: function () {
399
- return L.stamp(this.obj.datalayer)
400
- },
401
-
402
- toJS: function () {
403
- return this.builder._umap.datalayers[this.value()]
404
- },
405
-
406
- set: function () {
407
- this.builder._umap.lastUsedDataLayer = this.toJS()
408
- this.obj.changeDataLayer(this.toJS())
409
- },
410
- })
411
-
412
- L.FormBuilder.DataFormat = L.FormBuilder.Select.extend({
413
- selectOptions: [
414
- [undefined, L._('Choose the data format')],
415
- ['geojson', 'geojson'],
416
- ['osm', 'osm'],
417
- ['csv', 'csv'],
418
- ['gpx', 'gpx'],
419
- ['kml', 'kml'],
420
- ['georss', 'georss'],
421
- ],
422
- })
423
-
424
- L.FormBuilder.LicenceChooser = L.FormBuilder.Select.extend({
425
- getOptions: function () {
426
- const licences = []
427
- const licencesList = this.builder.obj.properties.licences
428
- let licence
429
- for (const i in licencesList) {
430
- licence = licencesList[i]
431
- licences.push([i, licence.name])
432
- }
433
- return licences
434
- },
435
-
436
- toHTML: function () {
437
- return this.get()?.name
438
- },
439
-
440
- toJS: function () {
441
- return this.builder.obj.properties.licences[this.value()]
442
- },
443
- })
444
-
445
- L.FormBuilder.NullableBoolean = L.FormBuilder.Select.extend({
446
- selectOptions: [
447
- [undefined, L._('inherit')],
448
- [true, L._('yes')],
449
- [false, L._('no')],
450
- ],
451
-
452
- toJS: function () {
453
- let value = this.value()
454
- switch (value) {
455
- case 'true':
456
- case true:
457
- value = true
458
- break
459
- case 'false':
460
- case false:
461
- value = false
462
- break
463
- default:
464
- value = undefined
465
- }
466
- return value
467
- },
468
- })
469
-
470
- L.FormBuilder.BlurInput.include({
471
- build: function () {
472
- this.options.className = 'blur'
473
- L.FormBuilder.Input.prototype.build.call(this)
474
- const button = L.DomUtil.create('span', 'button blur-button')
475
- L.DomUtil.after(this.input, button)
476
- L.DomEvent.on(this.input, 'focus', this.fetch, this)
477
- },
478
- })
479
-
480
- // Adds an autocomplete using all available user defined properties
481
- L.FormBuilder.PropertyInput = L.FormBuilder.BlurInput.extend({
482
- build: function () {
483
- L.FormBuilder.BlurInput.prototype.build.call(this)
484
- const autocomplete = new U.AutocompleteDatalist(this.input)
485
- // Will be used on Umap and DataLayer
486
- const properties = this.builder.obj.allProperties()
487
- autocomplete.suggestions = properties
488
- },
489
- })
490
-
491
- L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
492
- type: () => 'hidden',
493
-
494
- build: function () {
495
- L.FormBuilder.BlurInput.prototype.build.call(this)
496
- this.buttons = L.DomUtil.create('div', '', this.parentNode)
497
- this.tabs = L.DomUtil.create('div', 'flat-tabs', this.parentNode)
498
- this.body = L.DomUtil.create('div', 'umap-pictogram-body', this.parentNode)
499
- this.footer = L.DomUtil.create('div', '', this.parentNode)
500
- this.updatePreview()
501
- this.on('define', this.onDefine)
502
- },
503
-
504
- onDefine: async function () {
505
- this.buttons.innerHTML = ''
506
- this.footer.innerHTML = ''
507
- const [{ pictogram_list }, response, error] = await this.builder._umap.server.get(
508
- this.builder._umap.properties.urls.pictogram_list_json
509
- )
510
- if (!error) this.pictogram_list = pictogram_list
511
- this.buildTabs()
512
- const value = this.value()
513
- if (U.Icon.RECENT.length) this.showRecentTab()
514
- else if (!value || U.Utils.isPath(value)) this.showSymbolsTab()
515
- else if (U.Utils.isRemoteUrl(value) || U.Utils.isDataImage(value)) this.showURLTab()
516
- else this.showCharsTab()
517
- const closeButton = L.DomUtil.createButton(
518
- 'button action-button',
519
- this.footer,
520
- L._('Close'),
521
- function (e) {
522
- this.body.innerHTML = ''
523
- this.tabs.innerHTML = ''
524
- this.footer.innerHTML = ''
525
- if (this.isDefault()) this.undefine(e)
526
- else this.updatePreview()
527
- },
528
- this
529
- )
530
- },
531
-
532
- buildTabs: function () {
533
- this.tabs.innerHTML = ''
534
- if (U.Icon.RECENT.length) {
535
- const recent = L.DomUtil.add(
536
- 'button',
537
- 'flat tab-recent',
538
- this.tabs,
539
- L._('Recent')
540
- )
541
- L.DomEvent.on(recent, 'click', L.DomEvent.stop).on(
542
- recent,
543
- 'click',
544
- this.showRecentTab,
545
- this
546
- )
547
- }
548
- const symbol = L.DomUtil.add('button', 'flat tab-symbols', this.tabs, L._('Symbol'))
549
- const char = L.DomUtil.add(
550
- 'button',
551
- 'flat tab-chars',
552
- this.tabs,
553
- L._('Emoji & Character')
554
- )
555
- url = L.DomUtil.add('button', 'flat tab-url', this.tabs, L._('URL'))
556
- L.DomEvent.on(symbol, 'click', L.DomEvent.stop).on(
557
- symbol,
558
- 'click',
559
- this.showSymbolsTab,
560
- this
561
- )
562
- L.DomEvent.on(char, 'click', L.DomEvent.stop).on(
563
- char,
564
- 'click',
565
- this.showCharsTab,
566
- this
567
- )
568
- L.DomEvent.on(url, 'click', L.DomEvent.stop).on(url, 'click', this.showURLTab, this)
569
- },
570
-
571
- openTab: function (name) {
572
- const els = this.tabs.querySelectorAll('button')
573
- for (const el of els) {
574
- L.DomUtil.removeClass(el, 'on')
575
- }
576
- const el = this.tabs.querySelector(`.tab-${name}`)
577
- L.DomUtil.addClass(el, 'on')
578
- this.body.innerHTML = ''
579
- },
580
-
581
- updatePreview: function () {
582
- this.buttons.innerHTML = ''
583
- if (this.isDefault()) return
584
- if (!U.Utils.hasVar(this.value())) {
585
- // Do not try to render URL with variables
586
- const box = L.DomUtil.create('div', 'umap-pictogram-choice', this.buttons)
587
- L.DomEvent.on(box, 'click', this.onDefine, this)
588
- const icon = U.Icon.makeElement(this.value(), box)
589
- }
590
- this.button = L.DomUtil.createButton(
591
- 'button action-button',
592
- this.buttons,
593
- this.value() ? L._('Change') : L._('Add'),
594
- this.onDefine,
595
- this
596
- )
597
- },
598
-
599
- addIconPreview: function (pictogram, parent) {
600
- const baseClass = 'umap-pictogram-choice'
601
- const value = pictogram.src
602
- const search = U.Utils.normalize(this.searchInput.value)
603
- const title = pictogram.attribution
604
- ? `${pictogram.name} — © ${pictogram.attribution}`
605
- : pictogram.name || pictogram.src
606
- if (search && U.Utils.normalize(title).indexOf(search) === -1) return
607
- const className = value === this.value() ? `${baseClass} selected` : baseClass
608
- const container = L.DomUtil.create('div', className, parent)
609
- U.Icon.makeElement(value, container)
610
- container.title = title
611
- L.DomEvent.on(
612
- container,
613
- 'click',
614
- function (e) {
615
- this.input.value = value
616
- this.sync()
617
- this.unselectAll(this.grid)
618
- L.DomUtil.addClass(container, 'selected')
619
- },
620
- this
621
- )
622
- return true // Icon has been added (not filtered)
623
- },
624
-
625
- clear: function () {
626
- this.input.value = ''
627
- this.unselectAll(this.body)
628
- this.sync()
629
- this.body.innerHTML = ''
630
- this.updatePreview()
631
- },
632
-
633
- addCategory: function (items, name) {
634
- const parent = L.DomUtil.create('div', 'umap-pictogram-category')
635
- if (name) L.DomUtil.add('h6', '', parent, name)
636
- const grid = L.DomUtil.create('div', 'umap-pictogram-grid', parent)
637
- let status = false
638
- for (const item of items) {
639
- status = this.addIconPreview(item, grid) || status
640
- }
641
- if (status) this.grid.appendChild(parent)
642
- },
643
-
644
- buildSymbolsList: function () {
645
- this.grid.innerHTML = ''
646
- const categories = {}
647
- let category
648
- for (const props of this.pictogram_list) {
649
- category = props.category || L._('Generic')
650
- categories[category] = categories[category] || []
651
- categories[category].push(props)
652
- }
653
- const sorted = Object.entries(categories).toSorted(([a], [b]) =>
654
- U.Utils.naturalSort(a, b, U.lang)
655
- )
656
- for (const [name, items] of sorted) {
657
- this.addCategory(items, name)
658
- }
659
- },
660
-
661
- buildRecentList: function () {
662
- this.grid.innerHTML = ''
663
- const items = U.Icon.RECENT.map((src) => ({
664
- src,
665
- }))
666
- this.addCategory(items)
667
- },
668
-
669
- isDefault: function () {
670
- return !this.value() || this.value() === U.SCHEMA.iconUrl.default
671
- },
672
-
673
- addGrid: function (onSearch) {
674
- this.searchInput = L.DomUtil.create('input', '', this.body)
675
- this.searchInput.type = 'search'
676
- this.searchInput.placeholder = L._('Search')
677
- this.grid = L.DomUtil.create('div', '', this.body)
678
- L.DomEvent.on(this.searchInput, 'input', onSearch, this)
679
- },
680
-
681
- showRecentTab: function () {
682
- if (!U.Icon.RECENT.length) return
683
- this.openTab('recent')
684
- this.addGrid(this.buildRecentList)
685
- this.buildRecentList()
686
- },
687
-
688
- showSymbolsTab: function () {
689
- this.openTab('symbols')
690
- this.addGrid(this.buildSymbolsList)
691
- this.buildSymbolsList()
692
- },
693
-
694
- showCharsTab: function () {
695
- this.openTab('chars')
696
- const value = !U.Icon.isImg(this.value()) ? this.value() : null
697
- const input = this.buildInput(this.body, value)
698
- input.placeholder = L._('Type char or paste emoji')
699
- input.type = 'text'
700
- },
701
-
702
- showURLTab: function () {
703
- this.openTab('url')
704
- const value =
705
- U.Utils.isRemoteUrl(this.value()) || U.Utils.isDataImage(this.value())
706
- ? this.value()
707
- : null
708
- const input = this.buildInput(this.body, value)
709
- input.placeholder = L._('Add image URL')
710
- input.type = 'url'
711
- },
712
-
713
- buildInput: function (parent, value) {
714
- const input = L.DomUtil.create('input', 'blur', parent)
715
- const button = L.DomUtil.create('span', 'button blur-button', parent)
716
- if (value) input.value = value
717
- L.DomEvent.on(input, 'blur', () => {
718
- // Do not clear this.input when focus-blur
719
- // empty input
720
- if (input.value === value) return
721
- this.input.value = input.value
722
- this.sync()
723
- })
724
- return input
725
- },
726
-
727
- unselectAll: (container) => {
728
- const els = container.querySelectorAll('div.selected')
729
- for (const el in els) {
730
- if (els.hasOwnProperty(el)) L.DomUtil.removeClass(els[el], 'selected')
731
- }
732
- },
733
- })
734
-
735
- L.FormBuilder.Url = L.FormBuilder.Input.extend({
736
- type: () => 'url',
737
- })
738
-
739
- L.FormBuilder.Switch = L.FormBuilder.CheckBox.extend({
740
- getParentNode: function () {
741
- L.FormBuilder.CheckBox.prototype.getParentNode.call(this)
742
- if (this.options.inheritable) return this.quickContainer
743
- return this.extendedContainer
744
- },
745
-
746
- build: function () {
747
- L.FormBuilder.CheckBox.prototype.build.apply(this)
748
- if (this.options.inheritable)
749
- this.label = L.DomUtil.create('label', '', this.input.parentNode)
750
- else this.input.parentNode.appendChild(this.label)
751
- L.DomUtil.addClass(this.input.parentNode, 'with-switch')
752
- const id = `${this.builder.options.id || Date.now()}.${this.name}`
753
- this.label.setAttribute('for', id)
754
- L.DomUtil.addClass(this.input, 'switch')
755
- this.input.id = id
756
- },
757
- })
758
-
759
- L.FormBuilder.FacetSearchBase = L.FormBuilder.Element.extend({
760
- buildLabel: function () {
761
- this.label = L.DomUtil.element({
762
- tagName: 'legend',
763
- textContent: this.options.label,
764
- })
765
- },
766
- })
767
- L.FormBuilder.FacetSearchChoices = L.FormBuilder.FacetSearchBase.extend({
768
- build: function () {
769
- this.container = L.DomUtil.create('fieldset', 'umap-facet', this.parentNode)
770
- this.container.appendChild(this.label)
771
- this.ul = L.DomUtil.create('ul', '', this.container)
772
- this.type = this.options.criteria.type
773
-
774
- const choices = this.options.criteria.choices
775
- choices.sort()
776
- choices.forEach((value) => this.buildLi(value))
777
- },
778
-
779
- buildLi: function (value) {
780
- const property_li = L.DomUtil.create('li', '', this.ul)
781
- const label = L.DomUtil.create('label', '', property_li)
782
- const input = L.DomUtil.create('input', '', label)
783
- L.DomUtil.add('span', '', label, value)
784
-
785
- input.type = this.type
786
- input.name = `${this.type}_${this.name}`
787
- input.checked = this.get().choices.includes(value)
788
- input.dataset.value = value
789
-
790
- L.DomEvent.on(input, 'change', (e) => this.sync())
791
- },
792
-
793
- toJS: function () {
794
- return {
795
- type: this.type,
796
- choices: [...this.ul.querySelectorAll('input:checked')].map(
797
- (i) => i.dataset.value
798
- ),
799
- }
800
- },
801
- })
802
-
803
- L.FormBuilder.MinMaxBase = L.FormBuilder.FacetSearchBase.extend({
804
- getInputType: (type) => type,
805
-
806
- getLabels: () => [L._('Min'), L._('Max')],
807
-
808
- prepareForHTML: (value) => value.valueOf(),
809
-
810
- build: function () {
811
- this.container = L.DomUtil.create('fieldset', 'umap-facet', this.parentNode)
812
- this.container.appendChild(this.label)
813
- const { min, max, type } = this.options.criteria
814
- const { min: modifiedMin, max: modifiedMax } = this.get()
815
-
816
- const currentMin = modifiedMin !== undefined ? modifiedMin : min
817
- const currentMax = modifiedMax !== undefined ? modifiedMax : max
818
- this.type = type
819
- this.inputType = this.getInputType(this.type)
820
-
821
- const [minLabel, maxLabel] = this.getLabels()
822
-
823
- this.minLabel = L.DomUtil.create('label', '', this.container)
824
- this.minLabel.textContent = minLabel
825
-
826
- this.minInput = L.DomUtil.create('input', '', this.minLabel)
827
- this.minInput.type = this.inputType
828
- this.minInput.step = 'any'
829
- this.minInput.min = this.prepareForHTML(min)
830
- this.minInput.max = this.prepareForHTML(max)
831
- if (min != null) {
832
- // The value stored using setAttribute is not modified by
833
- // user input, and will be used as initial value when calling
834
- // form.reset(), and can also be retrieve later on by using
835
- // getAttributing, to compare with current value and know
836
- // if this value has been modified by the user
837
- // https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reset
838
- this.minInput.setAttribute('value', this.prepareForHTML(min))
839
- this.minInput.value = this.prepareForHTML(currentMin)
840
- }
841
-
842
- this.maxLabel = L.DomUtil.create('label', '', this.container)
843
- this.maxLabel.textContent = maxLabel
844
-
845
- this.maxInput = L.DomUtil.create('input', '', this.maxLabel)
846
- this.maxInput.type = this.inputType
847
- this.maxInput.step = 'any'
848
- this.maxInput.min = this.prepareForHTML(min)
849
- this.maxInput.max = this.prepareForHTML(max)
850
- if (max != null) {
851
- // Cf comment above about setAttribute vs value
852
- this.maxInput.setAttribute('value', this.prepareForHTML(max))
853
- this.maxInput.value = this.prepareForHTML(currentMax)
854
- }
855
- this.toggleStatus()
856
-
857
- L.DomEvent.on(this.minInput, 'change', () => this.sync())
858
- L.DomEvent.on(this.maxInput, 'change', () => this.sync())
859
- },
860
-
861
- toggleStatus: function () {
862
- this.minInput.dataset.modified = this.isMinModified()
863
- this.maxInput.dataset.modified = this.isMaxModified()
864
- },
865
-
866
- sync: function () {
867
- L.FormBuilder.Element.prototype.sync.call(this)
868
- this.toggleStatus()
869
- },
870
-
871
- isMinModified: function () {
872
- const default_ = this.minInput.getAttribute('value')
873
- const current = this.minInput.value
874
- return current !== default_
875
- },
876
-
877
- isMaxModified: function () {
878
- const default_ = this.maxInput.getAttribute('value')
879
- const current = this.maxInput.value
880
- return current !== default_
881
- },
882
-
883
- toJS: function () {
884
- const opts = {
885
- type: this.type,
886
- }
887
- if (this.minInput.value !== '' && this.isMinModified()) {
888
- opts.min = this.prepareForJS(this.minInput.value)
889
- }
890
- if (this.maxInput.value !== '' && this.isMaxModified()) {
891
- opts.max = this.prepareForJS(this.maxInput.value)
892
- }
893
- return opts
894
- },
895
- })
896
-
897
- L.FormBuilder.FacetSearchNumber = L.FormBuilder.MinMaxBase.extend({
898
- prepareForJS: (value) => new Number(value),
899
- })
900
-
901
- L.FormBuilder.FacetSearchDate = L.FormBuilder.MinMaxBase.extend({
902
- prepareForJS: (value) => new Date(value),
903
-
904
- toLocaleDateTime: (dt) => new Date(dt.valueOf() - dt.getTimezoneOffset() * 60000),
905
-
906
- prepareForHTML: function (value) {
907
- // Value must be in local time
908
- if (Number.isNaN(value)) return
909
- return this.toLocaleDateTime(value).toISOString().substr(0, 10)
910
- },
911
-
912
- getLabels: () => [L._('From'), L._('Until')],
913
- })
914
-
915
- L.FormBuilder.FacetSearchDateTime = L.FormBuilder.FacetSearchDate.extend({
916
- getInputType: (type) => 'datetime-local',
917
-
918
- prepareForHTML: function (value) {
919
- // Value must be in local time
920
- if (Number.isNaN(value)) return
921
- return this.toLocaleDateTime(value).toISOString().slice(0, -1)
922
- },
923
- })
924
-
925
- L.FormBuilder.MultiChoice = L.FormBuilder.Element.extend({
926
- default: 'null',
927
- className: 'umap-multiplechoice',
928
-
929
- clear: function () {
930
- const checked = this.container.querySelector('input[type="radio"]:checked')
931
- if (checked) checked.checked = false
932
- },
933
-
934
- fetch: function () {
935
- this.initial = this.toHTML()
936
- let value = this.initial
937
- if (!this.container.querySelector(`input[type="radio"][value="${value}"]`)) {
938
- value = this.options.default !== undefined ? this.options.default : this.default
939
- }
940
- const choices = this.getChoices().map(([value, label]) => `${value}`)
941
- if (choices.includes(`${value}`)) {
942
- this.container.querySelector(`input[type="radio"][value="${value}"]`).checked =
943
- true
944
- }
945
- },
946
-
947
- value: function () {
948
- const checked = this.container.querySelector('input[type="radio"]:checked')
949
- if (checked) return checked.value
950
- },
951
-
952
- getChoices: function () {
953
- return this.options.choices || this.choices
954
- },
955
-
956
- build: function () {
957
- const choices = this.getChoices()
958
- this.container = L.DomUtil.create(
959
- 'div',
960
- `${this.className} by${choices.length}`,
961
- this.parentNode
962
- )
963
- for (const [i, [value, label]] of choices.entries()) {
964
- this.addChoice(value, label, i)
965
- }
966
- this.fetch()
967
- },
968
-
969
- addChoice: function (value, label, counter) {
970
- const input = L.DomUtil.create('input', '', this.container)
971
- label = L.DomUtil.add('label', '', this.container, label)
972
- input.type = 'radio'
973
- input.name = this.name
974
- input.value = value
975
- const id = `${Date.now()}.${this.name}.${counter}`
976
- label.setAttribute('for', id)
977
- input.id = id
978
- L.DomEvent.on(input, 'change', this.sync, this)
979
- },
980
- })
981
-
982
- L.FormBuilder.TernaryChoices = L.FormBuilder.MultiChoice.extend({
983
- default: 'null',
984
-
985
- toJS: function () {
986
- let value = this.value()
987
- switch (value) {
988
- case 'true':
989
- case true:
990
- value = true
991
- break
992
- case 'false':
993
- case false:
994
- value = false
995
- break
996
- case 'null':
997
- case null:
998
- value = null
999
- break
1000
- default:
1001
- value = undefined
1002
- }
1003
- return value
1004
- },
1005
- })
1006
-
1007
- L.FormBuilder.NullableChoices = L.FormBuilder.TernaryChoices.extend({
1008
- choices: [
1009
- [true, L._('always')],
1010
- [false, L._('never')],
1011
- ['null', L._('hidden')],
1012
- ],
1013
- })
1014
-
1015
- L.FormBuilder.DataLayersControl = L.FormBuilder.TernaryChoices.extend({
1016
- choices: [
1017
- [true, L._('collapsed')],
1018
- ['expanded', L._('expanded')],
1019
- [false, L._('never')],
1020
- ['null', L._('hidden')],
1021
- ],
1022
-
1023
- toJS: function () {
1024
- let value = this.value()
1025
- if (value !== 'expanded')
1026
- value = L.FormBuilder.TernaryChoices.prototype.toJS.call(this)
1027
- return value
1028
- },
1029
- })
1030
-
1031
- L.FormBuilder.Range = L.FormBuilder.FloatInput.extend({
1032
- type: () => 'range',
1033
-
1034
- value: function () {
1035
- return L.DomUtil.hasClass(this.wrapper, 'undefined')
1036
- ? undefined
1037
- : L.FormBuilder.FloatInput.prototype.value.call(this)
1038
- },
1039
-
1040
- buildHelpText: function () {
1041
- let options = ''
1042
- const step = this.options.step || 1
1043
- const digits = step < 1 ? 1 : 0
1044
- const id = `range-${this.options.label || this.name}`
1045
- for (let i = this.options.min; i <= this.options.max; i += this.options.step) {
1046
- options += `<option value="${i.toFixed(digits)}" label="${i.toFixed(
1047
- digits
1048
- )}"></option>`
1049
- }
1050
- const datalist = L.DomUtil.element({
1051
- tagName: 'datalist',
1052
- parent: this.getHelpTextParent(),
1053
- className: 'umap-field-datalist',
1054
- safeHTML: options,
1055
- id: id,
1056
- })
1057
- this.input.setAttribute('list', id)
1058
- L.FormBuilder.Input.prototype.buildHelpText.call(this)
1059
- },
1060
- })
1061
-
1062
- L.FormBuilder.ManageOwner = L.FormBuilder.Element.extend({
1063
- build: function () {
1064
- const options = {
1065
- className: 'edit-owner',
1066
- on_select: L.bind(this.onSelect, this),
1067
- placeholder: L._("Type new owner's username"),
1068
- }
1069
- this.autocomplete = new U.AjaxAutocomplete(this.parentNode, options)
1070
- const owner = this.toHTML()
1071
- if (owner)
1072
- this.autocomplete.displaySelected({
1073
- item: { value: owner.id, label: owner.name },
1074
- })
1075
- },
1076
-
1077
- value: function () {
1078
- return this._value
1079
- },
1080
-
1081
- onSelect: function (choice) {
1082
- this._value = {
1083
- id: choice.item.value,
1084
- name: choice.item.label,
1085
- url: choice.item.url,
1086
- }
1087
- this.set()
1088
- },
1089
- })
1090
-
1091
- L.FormBuilder.ManageEditors = L.FormBuilder.Element.extend({
1092
- build: function () {
1093
- const options = {
1094
- className: 'edit-editors',
1095
- on_select: L.bind(this.onSelect, this),
1096
- on_unselect: L.bind(this.onUnselect, this),
1097
- placeholder: L._("Type editor's username"),
1098
- }
1099
- this.autocomplete = new U.AjaxAutocompleteMultiple(this.parentNode, options)
1100
- this._values = this.toHTML()
1101
- if (this._values)
1102
- for (let i = 0; i < this._values.length; i++)
1103
- this.autocomplete.displaySelected({
1104
- item: { value: this._values[i].id, label: this._values[i].name },
1105
- })
1106
- },
1107
-
1108
- value: function () {
1109
- return this._values
1110
- },
1111
-
1112
- onSelect: function (choice) {
1113
- this._values.push({
1114
- id: choice.item.value,
1115
- name: choice.item.label,
1116
- url: choice.item.url,
1117
- })
1118
- this.set()
1119
- },
1120
-
1121
- onUnselect: function (choice) {
1122
- const index = this._values.findIndex((item) => item.id === choice.item.value)
1123
- if (index !== -1) {
1124
- this._values.splice(index, 1)
1125
- this.set()
1126
- }
1127
- },
1128
- })
1129
-
1130
- L.FormBuilder.ManageTeam = L.FormBuilder.IntSelect.extend({
1131
- getOptions: function () {
1132
- return [[null, L._('None')]].concat(
1133
- this.options.teams.map((team) => [team.id, team.name])
1134
- )
1135
- },
1136
- toHTML: function () {
1137
- return this.get()?.id
1138
- },
1139
- toJS: function () {
1140
- const value = this.value()
1141
- for (const team of this.options.teams) {
1142
- if (team.id === value) return team
1143
- }
1144
- },
1145
- })
1146
-
1147
- U.FormBuilder = L.FormBuilder.extend({
1148
- options: {
1149
- className: 'umap-form',
1150
- },
1151
-
1152
- customHandlers: {
1153
- sortKey: 'PropertyInput',
1154
- easing: 'Switch',
1155
- facetKey: 'PropertyInput',
1156
- slugKey: 'PropertyInput',
1157
- labelKey: 'PropertyInput',
1158
- },
1159
-
1160
- computeDefaultOptions: function () {
1161
- for (const [key, schema] of Object.entries(U.SCHEMA)) {
1162
- if (schema.type === Boolean) {
1163
- if (schema.nullable) schema.handler = 'NullableChoices'
1164
- else schema.handler = 'Switch'
1165
- } else if (schema.type === 'Text') {
1166
- schema.handler = 'Textarea'
1167
- } else if (schema.type === Number) {
1168
- if (schema.step) schema.handler = 'Range'
1169
- else schema.handler = 'IntInput'
1170
- } else if (schema.choices) {
1171
- const text_length = schema.choices.reduce(
1172
- (acc, [_, label]) => acc + label.length,
1173
- 0
1174
- )
1175
- // Try to be smart and use MultiChoice only
1176
- // for choices where labels are shorts…
1177
- if (text_length < 40) {
1178
- schema.handler = 'MultiChoice'
1179
- } else {
1180
- schema.handler = 'Select'
1181
- schema.selectOptions = schema.choices
1182
- }
1183
- } else {
1184
- switch (key) {
1185
- case 'color':
1186
- case 'fillColor':
1187
- schema.handler = 'ColorPicker'
1188
- break
1189
- case 'iconUrl':
1190
- schema.handler = 'IconUrl'
1191
- break
1192
- case 'licence':
1193
- schema.handler = 'LicenceChooser'
1194
- break
1195
- }
1196
- }
1197
- if (this.customHandlers[key]) {
1198
- schema.handler = this.customHandlers[key]
1199
- }
1200
- // FormBuilder use this key for the input type itself
1201
- delete schema.type
1202
- this.defaultOptions[key] = schema
1203
- }
1204
- },
1205
-
1206
- initialize: function (obj, fields, options = {}) {
1207
- this._umap = obj._umap || options.umap
1208
- this.computeDefaultOptions()
1209
- L.FormBuilder.prototype.initialize.call(this, obj, fields, options)
1210
- this.on('finish', this.finish)
1211
- },
1212
-
1213
- setter: function (field, value) {
1214
- L.FormBuilder.prototype.setter.call(this, field, value)
1215
- this.obj.isDirty = true
1216
- if ('render' in this.obj) {
1217
- this.obj.render([field], this)
1218
- }
1219
- if ('sync' in this.obj) {
1220
- this.obj.sync.update(field, value)
1221
- }
1222
- },
1223
-
1224
- getter: function (field) {
1225
- const path = field.split('.')
1226
- let value = this.obj
1227
- let sub
1228
- for (sub of path) {
1229
- try {
1230
- value = value[sub]
1231
- } catch {
1232
- console.log(field)
1233
- }
1234
- }
1235
- if (value === undefined) values = U.SCHEMA[sub]?.default
1236
- return value
1237
- },
1238
-
1239
- finish: (event) => {
1240
- event.helper?.input?.blur()
1241
- },
1242
- })