umap-project 3.3.6__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 (216) 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 +63 -55
  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 +56 -157
  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 -1
  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/classified.js +17 -10
  74. umap/static/umap/js/modules/rendering/layers/cluster.js +2 -2
  75. umap/static/umap/js/modules/rendering/template.js +44 -8
  76. umap/static/umap/js/modules/rendering/ui.js +29 -23
  77. umap/static/umap/js/modules/rules.js +4 -3
  78. umap/static/umap/js/modules/schema.js +3 -6
  79. umap/static/umap/js/modules/share.js +4 -3
  80. umap/static/umap/js/modules/tableeditor.js +50 -38
  81. umap/static/umap/js/modules/templates.js +2 -3
  82. umap/static/umap/js/modules/ui/bar.js +42 -18
  83. umap/static/umap/js/modules/ui/dialog.js +33 -31
  84. umap/static/umap/js/modules/ui/panel.js +21 -7
  85. umap/static/umap/js/modules/ui/tooltip.js +6 -5
  86. umap/static/umap/js/modules/umap.js +148 -51
  87. umap/static/umap/js/modules/utils.js +23 -1
  88. umap/static/umap/js/umap.core.js +1 -110
  89. umap/static/umap/locale/am_ET.js +40 -14
  90. umap/static/umap/locale/am_ET.json +40 -14
  91. umap/static/umap/locale/ar.js +40 -14
  92. umap/static/umap/locale/ar.json +40 -14
  93. umap/static/umap/locale/ast.js +40 -14
  94. umap/static/umap/locale/ast.json +40 -14
  95. umap/static/umap/locale/bg.js +40 -14
  96. umap/static/umap/locale/bg.json +40 -14
  97. umap/static/umap/locale/br.js +47 -21
  98. umap/static/umap/locale/br.json +47 -21
  99. umap/static/umap/locale/ca.js +40 -14
  100. umap/static/umap/locale/ca.json +40 -14
  101. umap/static/umap/locale/cs_CZ.js +40 -14
  102. umap/static/umap/locale/cs_CZ.json +40 -14
  103. umap/static/umap/locale/da.js +40 -14
  104. umap/static/umap/locale/da.json +40 -14
  105. umap/static/umap/locale/de.js +39 -13
  106. umap/static/umap/locale/de.json +39 -13
  107. umap/static/umap/locale/el.js +40 -14
  108. umap/static/umap/locale/el.json +40 -14
  109. umap/static/umap/locale/en.js +39 -13
  110. umap/static/umap/locale/en.json +39 -13
  111. umap/static/umap/locale/en_US.json +40 -14
  112. umap/static/umap/locale/es.js +40 -14
  113. umap/static/umap/locale/es.json +40 -14
  114. umap/static/umap/locale/et.js +79 -53
  115. umap/static/umap/locale/et.json +79 -53
  116. umap/static/umap/locale/eu.js +72 -46
  117. umap/static/umap/locale/eu.json +72 -46
  118. umap/static/umap/locale/fa_IR.js +40 -14
  119. umap/static/umap/locale/fa_IR.json +40 -14
  120. umap/static/umap/locale/fi.js +40 -14
  121. umap/static/umap/locale/fi.json +40 -14
  122. umap/static/umap/locale/fr.js +39 -13
  123. umap/static/umap/locale/fr.json +39 -13
  124. umap/static/umap/locale/gl.js +40 -14
  125. umap/static/umap/locale/gl.json +40 -14
  126. umap/static/umap/locale/he.js +40 -14
  127. umap/static/umap/locale/he.json +40 -14
  128. umap/static/umap/locale/hr.js +40 -14
  129. umap/static/umap/locale/hr.json +40 -14
  130. umap/static/umap/locale/hu.js +40 -14
  131. umap/static/umap/locale/hu.json +40 -14
  132. umap/static/umap/locale/id.js +40 -14
  133. umap/static/umap/locale/id.json +40 -14
  134. umap/static/umap/locale/is.js +40 -14
  135. umap/static/umap/locale/is.json +40 -14
  136. umap/static/umap/locale/it.js +40 -14
  137. umap/static/umap/locale/it.json +40 -14
  138. umap/static/umap/locale/ja.js +40 -14
  139. umap/static/umap/locale/ja.json +40 -14
  140. umap/static/umap/locale/ko.js +40 -14
  141. umap/static/umap/locale/ko.json +40 -14
  142. umap/static/umap/locale/lt.js +40 -14
  143. umap/static/umap/locale/lt.json +40 -14
  144. umap/static/umap/locale/ms.js +40 -14
  145. umap/static/umap/locale/ms.json +40 -14
  146. umap/static/umap/locale/nl.js +40 -14
  147. umap/static/umap/locale/nl.json +40 -14
  148. umap/static/umap/locale/no.js +40 -14
  149. umap/static/umap/locale/no.json +40 -14
  150. umap/static/umap/locale/pl.js +40 -14
  151. umap/static/umap/locale/pl.json +40 -14
  152. umap/static/umap/locale/pl_PL.json +40 -14
  153. umap/static/umap/locale/pt.js +40 -14
  154. umap/static/umap/locale/pt.json +40 -14
  155. umap/static/umap/locale/pt_BR.js +40 -14
  156. umap/static/umap/locale/pt_BR.json +40 -14
  157. umap/static/umap/locale/pt_PT.js +40 -14
  158. umap/static/umap/locale/pt_PT.json +40 -14
  159. umap/static/umap/locale/ro.js +40 -14
  160. umap/static/umap/locale/ro.json +40 -14
  161. umap/static/umap/locale/ru.js +40 -14
  162. umap/static/umap/locale/ru.json +40 -14
  163. umap/static/umap/locale/sk_SK.js +40 -14
  164. umap/static/umap/locale/sk_SK.json +40 -14
  165. umap/static/umap/locale/sl.js +40 -14
  166. umap/static/umap/locale/sl.json +40 -14
  167. umap/static/umap/locale/sr.js +40 -14
  168. umap/static/umap/locale/sr.json +40 -14
  169. umap/static/umap/locale/sv.js +40 -14
  170. umap/static/umap/locale/sv.json +40 -14
  171. umap/static/umap/locale/th_TH.js +40 -14
  172. umap/static/umap/locale/th_TH.json +40 -14
  173. umap/static/umap/locale/tr.js +40 -14
  174. umap/static/umap/locale/tr.json +40 -14
  175. umap/static/umap/locale/uk_UA.js +40 -14
  176. umap/static/umap/locale/uk_UA.json +40 -14
  177. umap/static/umap/locale/vi.js +40 -14
  178. umap/static/umap/locale/vi.json +40 -14
  179. umap/static/umap/locale/vi_VN.json +40 -14
  180. umap/static/umap/locale/zh.js +40 -14
  181. umap/static/umap/locale/zh.json +40 -14
  182. umap/static/umap/locale/zh_CN.json +40 -14
  183. umap/static/umap/locale/zh_TW.Big5.json +40 -14
  184. umap/static/umap/locale/zh_TW.js +39 -13
  185. umap/static/umap/locale/zh_TW.json +39 -13
  186. umap/static/umap/map.css +60 -223
  187. umap/static/umap/unittests/utils.js +18 -0
  188. umap/static/umap/vars.css +23 -5
  189. umap/templates/umap/components/alerts/alert.html +32 -29
  190. umap/templates/umap/css.html +2 -1
  191. umap/templates/umap/login_popup_end.html +18 -9
  192. umap/templates/umap/user_map_table.html +7 -2
  193. umap/tests/integration/conftest.py +2 -6
  194. umap/tests/integration/test_anonymous_owned_map.py +89 -36
  195. umap/tests/integration/test_basics.py +25 -1
  196. umap/tests/integration/test_browser.py +37 -0
  197. umap/tests/integration/test_draw_polygon.py +2 -0
  198. umap/tests/integration/test_edit_marker.py +1 -1
  199. umap/tests/integration/test_export_map.py +19 -0
  200. umap/tests/integration/test_fields.py +522 -0
  201. umap/tests/integration/test_filters.py +617 -0
  202. umap/tests/integration/test_import.py +15 -42
  203. umap/tests/integration/test_remote_data.py +60 -4
  204. umap/tests/integration/test_share.py +4 -4
  205. umap/tests/integration/test_tableeditor.py +31 -7
  206. umap/tests/integration/test_websocket_sync.py +3 -1
  207. umap/tests/test_dashboard.py +10 -0
  208. umap/urls.py +1 -0
  209. umap/views.py +5 -0
  210. {umap_project-3.3.6.dist-info → umap_project-3.4.0b0.dist-info}/METADATA +12 -12
  211. {umap_project-3.3.6.dist-info → umap_project-3.4.0b0.dist-info}/RECORD +214 -211
  212. umap/static/umap/js/modules/facets.js +0 -164
  213. umap/tests/integration/test_facets_browser.py +0 -279
  214. {umap_project-3.3.6.dist-info → umap_project-3.4.0b0.dist-info}/WHEEL +0 -0
  215. {umap_project-3.3.6.dist-info → umap_project-3.4.0b0.dist-info}/entry_points.txt +0 -0
  216. {umap_project-3.3.6.dist-info → umap_project-3.4.0b0.dist-info}/licenses/LICENSE +0 -0
@@ -111,6 +111,10 @@ const FeatureMixin = {
111
111
  onCommit: function () {
112
112
  this.feature.onCommit()
113
113
  },
114
+
115
+ isVisible() {
116
+ return Boolean(this._map?.hasLayer(this))
117
+ },
114
118
  }
115
119
 
116
120
  const PointMixin = {
@@ -377,6 +381,27 @@ const PathMixin = {
377
381
  // https://github.com/Leaflet/Leaflet/pull/9475
378
382
 
379
383
  this._path.classList.toggle('leaflet-interactive', options.interactive)
384
+
385
+ // Text decoration
386
+ this.setText(null) // Reset.
387
+ const textPath = this.feature.getDynamicOption('textPath')
388
+ if (textPath) {
389
+ const color =
390
+ this.feature.getOption('textPathColor') ||
391
+ this.feature.getDynamicOption('color')
392
+ const textPathOptions = {
393
+ repeat: this.feature.getOption('textPathRepeat'),
394
+ offset: this.feature.getOption('textPathOffset') || undefined,
395
+ position: this.feature.getOption('textPathPosition'),
396
+ attributes: {
397
+ fill: color,
398
+ opacity: this.feature.getDynamicOption('opacity'),
399
+ rotate: this.feature.getOption('textPathRotate'),
400
+ 'font-size': this.feature.getOption('textPathSize'),
401
+ },
402
+ }
403
+ this.setText(textPath, textPathOptions)
404
+ }
380
405
  },
381
406
 
382
407
  _redraw: function () {
@@ -423,29 +448,6 @@ export const LeafletPolyline = Polyline.extend({
423
448
  parentClass: Polyline,
424
449
  includes: [FeatureMixin, PathMixin],
425
450
 
426
- setStyle: function (options) {
427
- PathMixin.setStyle.call(this, options)
428
- this.setText(null) // Reset.
429
- const textPath = this.feature.getDynamicOption('textPath')
430
- if (textPath) {
431
- const color =
432
- this.feature.getOption('textPathColor') ||
433
- this.feature.getDynamicOption('color')
434
- const textPathOptions = {
435
- repeat: this.feature.getOption('textPathRepeat'),
436
- offset: this.feature.getOption('textPathOffset') || undefined,
437
- position: this.feature.getOption('textPathPosition'),
438
- attributes: {
439
- fill: color,
440
- opacity: this.feature.getDynamicOption('opacity'),
441
- rotate: this.feature.getOption('textPathRotate'),
442
- 'font-size': this.feature.getOption('textPathSize'),
443
- },
444
- }
445
- this.setText(textPath, textPathOptions)
446
- }
447
- },
448
-
449
451
  getClass: () => LeafletPolyline,
450
452
 
451
453
  getMeasure: function (shape) {
@@ -632,4 +634,8 @@ export const CircleMarker = BaseCircleMarker.extend({
632
634
  getCenter: function () {
633
635
  return this._latlng
634
636
  },
637
+
638
+ setText() {
639
+ // Dummy function, as it inherits from PathMixin
640
+ },
635
641
  })
@@ -207,7 +207,8 @@ class Rule {
207
207
  const [li, { colorBox }] = Utils.loadTemplateWithRefs(
208
208
  `<li><span class="color-box" data-ref=colorBox></span>${this.label}</li>`
209
209
  )
210
- const bgcolor = this.properties.color || this.parent.getColor()
210
+ const bgcolor =
211
+ this.properties.fillColor || this.properties.color || this.parent.getColor()
211
212
  const symbol = this.properties.iconUrl
212
213
  colorBox.style.backgroundColor = bgcolor
213
214
  if (symbol && symbol !== SCHEMA.iconUrl.default) {
@@ -265,10 +266,10 @@ export default class Rules {
265
266
  edit(container) {
266
267
  const template = `
267
268
  <details id="rules">
268
- <summary>${translate('Conditional style rules')}</summary>
269
+ <summary><h4>${translate('Conditional style rules')}</h4></summary>
269
270
  <fieldset>
270
271
  <ul data-ref=ul></ul>
271
- <button class="umap-add" type="button" data-ref=add>${translate('Add rule')}</button>
272
+ <button type="button" data-ref=add>${translate('Add rule')}</button>
272
273
  </fieldset>
273
274
  </details>
274
275
  `
@@ -140,15 +140,12 @@ export const SCHEMA = {
140
140
  label: translate('Display the embed control'),
141
141
  default: true,
142
142
  },
143
- facetKey: {
144
- type: String,
143
+ filters: {
144
+ type: Array,
145
145
  impacts: ['ui'],
146
- helpEntries: ['facetKey'],
147
- placeholder: translate('Example: key1,key2|Label 2,key3|Label 3|checkbox'),
148
- label: translate('Filters keys'),
149
146
  },
150
147
  fields: {
151
- type: Object,
148
+ type: Array,
152
149
  },
153
150
  fill: {
154
151
  type: Boolean,
@@ -3,6 +3,7 @@ import { MutatingForm } from './form/builder.js'
3
3
  import { EXPORT_FORMATS } from './formatter.js'
4
4
  import { translate } from './i18n.js'
5
5
  import * as Utils from './utils.js'
6
+ import * as DOMUtils from './domutils.js'
6
7
 
7
8
  export default class Share {
8
9
  constructor(umap) {
@@ -17,14 +18,14 @@ export default class Share {
17
18
  'icon-share'
18
19
  )
19
20
 
20
- DomUtil.createCopiableInput(
21
+ DOMUtils.copiableInput(
21
22
  this.container,
22
23
  translate('Link to view the map'),
23
24
  window.location.protocol + Utils.getBaseUrl()
24
25
  )
25
26
 
26
27
  if (this._umap.properties.shortUrl) {
27
- DomUtil.createCopiableInput(
28
+ DOMUtils.copiableInput(
28
29
  this.container,
29
30
  translate('Short link'),
30
31
  this._umap.properties.shortUrl
@@ -79,7 +80,7 @@ export default class Share {
79
80
  const embedTitle = DomUtil.add('h4', '', this.container, translate('Embed the map'))
80
81
  const iframe = DomUtil.create('textarea', 'umap-share-iframe', this.container)
81
82
  const urlTitle = DomUtil.add('h4', '', this.container, translate('Direct link'))
82
- const exportUrl = DomUtil.createCopiableInput(
83
+ const exportUrl = DOMUtils.copiableInput(
83
84
  this.container,
84
85
  translate('Share this link to open a customized map view'),
85
86
  ''
@@ -31,53 +31,73 @@ export default class TableEditor extends WithTemplate {
31
31
  this.elements.body.addEventListener('keydown', (event) => this.onKeyDown(event))
32
32
  this.elements.header.addEventListener('click', (event) => {
33
33
  const property = event.target.dataset.property
34
- if (property) this.openHeaderMenu(property)
34
+ const parentType = event.target.dataset.fieldParent
35
+ if (property)
36
+ this.openHeaderMenu(
37
+ property,
38
+ parentType === 'map' ? this._umap : this.datalayer
39
+ )
35
40
  })
36
41
  }
37
42
 
38
- openHeaderMenu(property) {
39
- const actions = []
40
- let filterItem
41
- if (this._umap.facets.has(property)) {
42
- filterItem = {
43
- label: translate('Remove filter for this column'),
43
+ openHeaderMenu(name, parent) {
44
+ let actionLabel
45
+ if (parent.filters.has(name)) {
46
+ actionLabel = translate('Edit filter for this field')
47
+ } else {
48
+ actionLabel = translate('Add filter for this field')
49
+ }
50
+ const actions = [
51
+ {
52
+ label: actionLabel,
44
53
  action: () => {
45
- this._umap.facets.remove(property)
54
+ parent.filters.createFilterForm(name)
46
55
  this._umap.browser.open('filters')
47
56
  },
48
- }
49
- } else {
50
- filterItem = {
51
- label: translate('Add filter for this column'),
57
+ },
58
+ {
59
+ label: translate('Edit this field'),
52
60
  action: () => {
53
- this._umap.facets.add(property)
54
- this._umap.browser.open('filters')
61
+ parent.fields.editField(name).then(() => this.open())
55
62
  },
56
- }
57
- }
58
- actions.push(filterItem)
59
- if (!this.datalayer.isRemoteLayer()) {
63
+ },
64
+ ]
65
+ // Only allow deleting fields for map and local datalayer.
66
+ if (!parent.isRemoteLayer?.()) {
60
67
  actions.push({
61
- label: translate('Rename this column'),
62
- action: () => this.renameProperty(property),
63
- })
64
- actions.push({
65
- label: translate('Delete this column'),
66
- action: () => this.deleteProperty(property),
68
+ label: translate('Delete this field'),
69
+ action: () => {
70
+ parent.fields.confirmDelete(name).then(() => this.open())
71
+ },
67
72
  })
68
73
  }
69
74
  this.contextmenu.open(event, actions)
70
75
  }
71
76
 
77
+ get fields() {
78
+ return [
79
+ ...this.datalayer.fields.all().map((field) => {
80
+ const copy = { ...field }
81
+ copy.parent = 'datalayer'
82
+ return copy
83
+ }),
84
+ ...this._umap.fields.all().map((field) => {
85
+ const copy = { ...field }
86
+ copy.parent = 'map'
87
+ return copy
88
+ }),
89
+ ]
90
+ }
91
+
72
92
  renderHeaders() {
73
93
  this.elements.header.innerHTML = ''
74
94
  const th = loadTemplate('<th><input type="checkbox" /></th>')
75
95
  const checkbox = th.firstChild
76
96
  this.elements.header.appendChild(th)
77
- for (const field of this.datalayer.fields) {
97
+ for (const field of this.fields) {
78
98
  this.elements.header.appendChild(
79
99
  loadTemplate(
80
- `<th>${field.key}<button data-property="${field.key}" class="flat" aria-label="${translate('Advanced actions')}">…</button></th>`
100
+ `<th>${field.key}<button data-property="${field.key}" data-field-parent="${field.parent}" class="flat" aria-label="${translate('Advanced actions')}">…</button></th>`
81
101
  )
82
102
  )
83
103
  }
@@ -94,7 +114,7 @@ export default class TableEditor extends WithTemplate {
94
114
  this.datalayer.features.forEach((feature) => {
95
115
  if (feature.isFiltered()) return
96
116
  if (inBbox && !feature.isOnScreen(bounds)) return
97
- const tds = this.datalayer.fields.map(
117
+ const tds = this.fields.map(
98
118
  (field) =>
99
119
  `<td tabindex="0" data-property="${field.key}">${feature.properties[field.key] ?? ''}</td>`
100
120
  )
@@ -103,16 +123,8 @@ export default class TableEditor extends WithTemplate {
103
123
  this.elements.body.innerHTML = html
104
124
  }
105
125
 
106
- renameProperty(property) {
107
- this.datalayer.askForRenameProperty(property).then(() => this.open())
108
- }
109
-
110
- deleteProperty(property) {
111
- this.datalayer.confirmDeleteProperty(property).then(() => this.open())
112
- }
113
-
114
- addProperty() {
115
- this.datalayer.addProperty().then(() => this.open())
126
+ addField() {
127
+ this.datalayer.fields.editField().then(() => this.open())
116
128
  }
117
129
 
118
130
  open() {
@@ -127,7 +139,7 @@ export default class TableEditor extends WithTemplate {
127
139
  <button class="flat" type="button" data-ref="add">
128
140
  <i class="icon icon-16 icon-add"></i>${translate('Add a new field')}
129
141
  </button>`)
130
- addButton.addEventListener('click', () => this.addProperty())
142
+ addButton.addEventListener('click', () => this.addField())
131
143
  actions.push(addButton)
132
144
 
133
145
  const deleteButton = loadTemplate(`
@@ -32,9 +32,8 @@ export default class TemplateImporter {
32
32
  const [root, { tabs, form, body, mine, confirm, confirmData }] =
33
33
  Utils.loadTemplateWithRefs(TEMPLATE)
34
34
  const uri = this.umap.urls.get('template_list')
35
- const userIsAuth = Boolean(this.umap.properties.user?.id)
36
- const defaultTab = userIsAuth ? 'mine' : 'staff'
37
- mine.hidden = !userIsAuth
35
+ const defaultTab = this.umap.permissions.userIsAuth() ? 'mine' : 'staff'
36
+ mine.hidden = !this.umap.permissions.userIsAuth()
38
37
 
39
38
  const loadTemplates = async (source) => {
40
39
  const [data, response, error] = await this.umap.server.get(
@@ -11,11 +11,16 @@ const TOP_BAR_TEMPLATE = `
11
11
  <div class="umap-left-edit-toolbox" data-ref="left">
12
12
  <div class="logo"><a class="" href="/" title="${translate('Go to the homepage')}">uMap</a></div>
13
13
  <button class="map-name flat truncate" type="button" data-ref="name"></button>
14
- <button class="share-status flat truncate" type="button" data-ref="share"></button>
15
- <button class="edit-undo round flat" type="button" data-ref="undo" disabled>
14
+ <button class="flat truncate" type="button" data-ref="share">
15
+ <i class="icon icon-16 icon-draft show-on-draft"></i><span class="share-status"></span>
16
+ </button>
17
+ <button class="anonymous truncate soft-round" type="button" data-ref="shareAnonymous" hidden>
18
+ <i class="icon icon-16 icon-anonymous"></i><span class="share-status"></span>
19
+ </button>
20
+ <button class="edit-undo flat" type="button" data-ref="undo" disabled>
16
21
  <i class="icon icon-16 icon-undo"></i>
17
22
  </button>
18
- <button class="edit-redo round flat" type="button" data-ref="redo" disabled>
23
+ <button class="edit-redo flat" type="button" data-ref="redo" disabled>
19
24
  <i class="icon icon-16 icon-redo"></i>
20
25
  </button>
21
26
  </div>
@@ -26,7 +31,7 @@ const TOP_BAR_TEMPLATE = `
26
31
  </button>
27
32
  <button class="umap-user flat" type="button" data-ref="user">
28
33
  <i class="icon icon-16 icon-profile"></i>
29
- <span class="username truncate" data-ref="username"></span>
34
+ <span class="username truncate" data-ref="username">${translate('Anonymous')}</span>
30
35
  </button>
31
36
  <button class="umap-help-link flat" type="button" title="${translate('Help')}" data-ref="help">${translate('Help')}</button>
32
37
  <button class="edit-disable round disabled-on-dirty" type="button" data-ref="view">
@@ -72,17 +77,31 @@ export class TopBar extends WithTemplate {
72
77
  duration: 5000,
73
78
  })
74
79
  })
80
+ this.elements.shareAnonymous.addEventListener('mouseover', () => {
81
+ this._umap.tooltip.open({
82
+ content: translate('Anonymous map: update who can see and edit it'),
83
+ anchor: this.elements.shareAnonymous,
84
+ position: 'bottom',
85
+ delay: 500,
86
+ duration: 5000,
87
+ })
88
+ })
75
89
  if (this._umap.properties.editMode === 'advanced') {
76
90
  this.elements.name.addEventListener('click', () => this._umap.editCaption())
77
91
  this.elements.share.addEventListener('click', () => this._umap.permissions.edit())
92
+ this.elements.shareAnonymous.addEventListener('click', () =>
93
+ this._umap.permissions.edit()
94
+ )
78
95
  }
79
96
  this.elements.user.addEventListener('click', () => {
80
- if (this._umap.properties.user?.id) {
81
- const actions = [
82
- {
83
- label: translate('New map'),
84
- action: this._umap.urls.get('map_new'),
85
- },
97
+ const actions = [
98
+ {
99
+ label: translate('New map'),
100
+ action: this._umap.urls.get('map_new'),
101
+ },
102
+ ]
103
+ if (this._umap.permissions.userIsAuth()) {
104
+ actions.push(
86
105
  {
87
106
  label: translate('My maps'),
88
107
  action: this._umap.urls.get('user_dashboard'),
@@ -90,18 +109,22 @@ export class TopBar extends WithTemplate {
90
109
  {
91
110
  label: translate('My teams'),
92
111
  action: this._umap.urls.get('user_teams'),
93
- },
94
- ]
112
+ }
113
+ )
95
114
  if (this._umap.urls.has('user_profile')) {
96
115
  actions.push({
97
116
  label: translate('My profile'),
98
117
  action: this._umap.urls.get('user_profile'),
99
118
  })
100
119
  }
101
- this._menu.openBelow(this.elements.user, actions)
120
+ } else {
121
+ actions.push({
122
+ label: translate('Login'),
123
+ action: () => this._umap.askForLogin(),
124
+ })
102
125
  }
126
+ this._menu.openBelow(this.elements.user, actions)
103
127
  })
104
-
105
128
  this.elements.peers.addEventListener('mouseover', () => {
106
129
  const connectedPeers = this._umap.sync.getPeers()
107
130
  if (!Object.keys(connectedPeers).length) return
@@ -162,10 +185,10 @@ export class TopBar extends WithTemplate {
162
185
  duration: 5000,
163
186
  })
164
187
  })
165
- this.redraw()
166
188
  }
167
189
 
168
190
  redraw() {
191
+ this.element.classList.toggle('draft', this._umap.permissions.isDraft())
169
192
  const syncEnabled = this._umap.getProperty('syncEnabled')
170
193
  this.elements.peers.hidden = !syncEnabled
171
194
  this.elements.view.disabled = this._umap.sync._undoManager.isDirty()
@@ -175,6 +198,8 @@ export class TopBar extends WithTemplate {
175
198
  this.elements.saveDraftLabel.hidden = !isDraft || isTemplate
176
199
  this.elements.saveTemplateLabel.hidden = !isTemplate
177
200
  this._umap.sync._undoManager.toggleState()
201
+ this.elements.share.hidden = this._umap.permissions.isAnonymousMap()
202
+ this.elements.shareAnonymous.hidden = !this._umap.permissions.isAnonymousMap()
178
203
  }
179
204
  }
180
205
 
@@ -218,7 +243,6 @@ export class BottomBar extends WithTemplate {
218
243
  }
219
244
  })
220
245
  })
221
- this.redraw()
222
246
  }
223
247
 
224
248
  redraw() {
@@ -229,7 +253,7 @@ export class BottomBar extends WithTemplate {
229
253
  const showMenus = this._umap.getProperty('captionMenus')
230
254
  this.elements.caption.hidden = !showMenus
231
255
  this.elements.browse.hidden = !showMenus
232
- this.elements.filter.hidden = !showMenus || !this._umap.properties.facetKey
256
+ this.elements.filter.hidden = !showMenus || !this._umap.hasFilters()
233
257
  this.buildDataLayerSwitcher()
234
258
  }
235
259
 
@@ -267,7 +291,7 @@ const EDIT_BAR_TEMPLATE = `
267
291
  </li>
268
292
  <li data-ref="route" hidden><button type="button" data-getstarted title="${translate('Draw along routes')}"><i class="icon icon-24 icon-route"></i></button></li>
269
293
  <hr>
270
- <li data-ref="caption" hidden><button data-getstarted type="button" title="${translate('Edit map name and caption')}"><i class="icon icon-24 icon-caption"></i></button></li>
294
+ <li data-ref="caption" hidden><button data-getstarted type="button" title="${translate('Edit map name and caption')}"><i class="icon icon-24 icon-info"></i></button></li>
271
295
  <li data-ref="import" hidden><button type="button"><i class="icon icon-24 icon-upload"></i></button></li>
272
296
  <li data-ref="templates" hidden><button type="button" title="${translate('Load template')}" data-getstarted><i class="icon icon-24 icon-template"></i></button></li>
273
297
  <li data-ref="layers" hidden><button type="button" title="${translate('Manage layers')}"><i class="icon icon-24 icon-layers"></i></button></li>
@@ -78,8 +78,7 @@ export default class Dialog extends WithTemplate {
78
78
  if (!this.dialogSupported) {
79
79
  this.elements.form.addEventListener('submit', (event) => {
80
80
  event.preventDefault()
81
- this.dialog.returnValue = 'accept'
82
- this.close()
81
+ this.accept()
83
82
  })
84
83
  }
85
84
  this.dialog.addEventListener('keydown', (e) => {
@@ -118,7 +117,6 @@ export default class Dialog extends WithTemplate {
118
117
  this.elements.cancel.hidden = !dialog.cancel
119
118
  this.elements.message.textContent = dialog.message
120
119
  this.elements.message.hidden = !dialog.message
121
- this.elements.target = dialog.target || ''
122
120
  this.elements.template.innerHTML = ''
123
121
  if (dialog.template?.nodeType === 1) {
124
122
  this.elements.template.appendChild(dialog.template)
@@ -137,12 +135,13 @@ export default class Dialog extends WithTemplate {
137
135
  if (currentZIndex) {
138
136
  this.dialog.style.zIndex = currentZIndex + 1
139
137
  }
140
-
141
- this.toggle(true)
142
-
138
+ if (this.dialogSupported) {
139
+ this.dialog.show()
140
+ } else {
141
+ this.dialog.hidden = false
142
+ }
143
143
  if (this.hasFormData) this.focusable[0].focus()
144
144
  else this.elements.accept.focus()
145
-
146
145
  return this.waitForUser()
147
146
  }
148
147
 
@@ -151,37 +150,40 @@ export default class Dialog extends WithTemplate {
151
150
  }
152
151
 
153
152
  close() {
154
- this.toggle(false)
155
- this.dialog.returnValue = undefined
156
- }
157
-
158
- toggle(open = false) {
153
+ this._closing = true
159
154
  if (this.dialogSupported) {
160
- if (open) this.dialog.show()
161
- else this.dialog.close()
155
+ this.dialog.close()
162
156
  } else {
163
- this.dialog.hidden = !open
164
- if (this.elements.target && !open) {
165
- this.elements.target.focus()
166
- }
167
- if (!open) {
168
- this.dialog.dispatchEvent(new CustomEvent('close'))
169
- }
157
+ this.dialog.hidden = true
158
+ this.dialog.dispatchEvent(new CustomEvent('close'))
170
159
  }
171
160
  }
172
161
 
162
+ accept() {
163
+ this.dialog.returnValue = 'accept'
164
+ this.close()
165
+ }
166
+
173
167
  waitForUser() {
174
168
  return new Promise((resolve) => {
175
- this.dialog.addEventListener(
176
- 'close',
177
- (event) => {
178
- if (this.dialog.returnValue === 'accept') {
179
- const value = this.hasFormData ? this.collectFormData() : true
180
- resolve(value)
181
- }
182
- },
183
- { once: true }
184
- )
169
+ const onClose = () => {
170
+ this._closing = false
171
+ if (this.dialog.returnValue === 'accept') {
172
+ const value = this.hasFormData ? this.collectFormData() : true
173
+ resolve(value)
174
+ }
175
+ }
176
+ const waitForClose = () => {
177
+ this.dialog.returnValue = undefined
178
+ this.dialog.addEventListener('close', () => onClose(), { once: true })
179
+ }
180
+ if (this._closing) {
181
+ // We are opening a new dialog while another is not fully closed,
182
+ // so let's first wait for that one to be fully closed
183
+ this.dialog.addEventListener('close', () => waitForClose(), { once: true })
184
+ } else {
185
+ waitForClose()
186
+ }
185
187
  })
186
188
  }
187
189
 
@@ -26,12 +26,12 @@ export class Panel {
26
26
  }
27
27
 
28
28
  open({ content, className, highlight, actions = [] } = {}) {
29
+ let isOpen = false
29
30
  if (this.isOpen()) {
31
+ isOpen = true
30
32
  this.onClose()
31
33
  }
32
- this.container.className = `with-transition panel window ${this.className} ${
33
- this.mode || ''
34
- }`
34
+ this.container.className = `with-transition panel window ${this.className} ${this.mode || ''} ${isOpen ? 'on' : ''}`
35
35
  if (highlight) {
36
36
  this.container.dataset.highlight = highlight
37
37
  }
@@ -56,8 +56,22 @@ export class Panel {
56
56
  }
57
57
  if (className) DomUtil.addClass(body, className)
58
58
  const promise = new Promise((resolve, reject) => {
59
- DomUtil.addClass(this.container, 'on')
60
- resolve(this)
59
+ if (isOpen) {
60
+ resolve(this)
61
+ } else {
62
+ Promise.all(
63
+ this.container.getAnimations().map((animation) => animation.finished)
64
+ )
65
+ .then(() => {
66
+ resolve(this)
67
+ })
68
+ .catch(() => {
69
+ // Panel has been removed, so the DOM has changed, so the animations
70
+ // were cancelled, we want the new panel callabck to be called anyway.
71
+ resolve(this)
72
+ })
73
+ this.container.classList.add('on')
74
+ }
61
75
  })
62
76
  DomEvent.on(closeButton, 'click', this.close, this)
63
77
  DomEvent.on(resizeButton, 'click', this.resize, this)
@@ -83,8 +97,8 @@ export class Panel {
83
97
  }
84
98
 
85
99
  onClose() {
86
- if (DomUtil.hasClass(this.container, 'on')) {
87
- DomUtil.removeClass(this.container, 'on')
100
+ if (this.container.classList.contains('on')) {
101
+ this.container.classList.remove('on')
88
102
  this._leafletMap.invalidateSize({ pan: false })
89
103
  }
90
104
  }
@@ -4,11 +4,10 @@ import * as Utils from '../utils.js'
4
4
  import { Positioned } from './base.js'
5
5
 
6
6
  export default class Tooltip extends Positioned {
7
- constructor(parent) {
7
+ constructor() {
8
8
  super()
9
- this.parent = parent
9
+ this.parent = document.body
10
10
  this.container = Utils.loadTemplate('<div class="umap-tooltip-container"></div>')
11
- this.parent.appendChild(this.container)
12
11
  DomEvent.disableClickPropagation(this.container)
13
12
  this.container.addEventListener('contextmenu', (event) => event.stopPropagation()) // Do not activate our custom context menu.
14
13
  this.container.addEventListener('wheel', (event) => event.stopPropagation())
@@ -25,7 +24,7 @@ export default class Tooltip extends Positioned {
25
24
  } else {
26
25
  this.container.innerHTML = Utils.escapeHTML(opts.content)
27
26
  }
28
- this.parent.classList.add('umap-tooltip')
27
+ this.parent.appendChild(this.container)
29
28
  this.openAt(opts)
30
29
  }
31
30
  this.TOOLTIP_ID = window.setTimeout(L.bind(showIt, this), opts.delay || 0)
@@ -49,6 +48,8 @@ export default class Tooltip extends Positioned {
49
48
  this.toggleClassPosition()
50
49
  this.container.innerHTML = ''
51
50
  this.setPosition({})
52
- this.parent.classList.remove('umap-tooltip')
51
+ if (this.parent.contains(this.container)) {
52
+ this.parent.removeChild(this.container)
53
+ }
53
54
  }
54
55
  }