umap-project 3.3.6__py3-none-any.whl → 3.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. umap/__init__.py +1 -1
  2. umap/context_processors.py +4 -1
  3. umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  4. umap/locale/cs_CZ/LC_MESSAGES/django.po +43 -33
  5. umap/locale/da/LC_MESSAGES/django.mo +0 -0
  6. umap/locale/da/LC_MESSAGES/django.po +43 -33
  7. umap/locale/de/LC_MESSAGES/django.mo +0 -0
  8. umap/locale/de/LC_MESSAGES/django.po +35 -29
  9. umap/locale/el/LC_MESSAGES/django.mo +0 -0
  10. umap/locale/el/LC_MESSAGES/django.po +35 -29
  11. umap/locale/en/LC_MESSAGES/django.po +47 -41
  12. umap/locale/es/LC_MESSAGES/django.mo +0 -0
  13. umap/locale/es/LC_MESSAGES/django.po +43 -33
  14. umap/locale/et/LC_MESSAGES/django.mo +0 -0
  15. umap/locale/et/LC_MESSAGES/django.po +58 -54
  16. umap/locale/eu/LC_MESSAGES/django.mo +0 -0
  17. umap/locale/eu/LC_MESSAGES/django.po +43 -33
  18. umap/locale/fa_IR/LC_MESSAGES/django.mo +0 -0
  19. umap/locale/fa_IR/LC_MESSAGES/django.po +43 -33
  20. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  21. umap/locale/fr/LC_MESSAGES/django.po +36 -30
  22. umap/locale/gl/LC_MESSAGES/django.mo +0 -0
  23. umap/locale/gl/LC_MESSAGES/django.po +43 -33
  24. umap/locale/hu/LC_MESSAGES/django.mo +0 -0
  25. umap/locale/hu/LC_MESSAGES/django.po +35 -29
  26. umap/locale/is/LC_MESSAGES/django.mo +0 -0
  27. umap/locale/is/LC_MESSAGES/django.po +43 -33
  28. umap/locale/it/LC_MESSAGES/django.mo +0 -0
  29. umap/locale/it/LC_MESSAGES/django.po +43 -33
  30. umap/locale/nl/LC_MESSAGES/django.mo +0 -0
  31. umap/locale/nl/LC_MESSAGES/django.po +35 -29
  32. umap/locale/pl/LC_MESSAGES/django.mo +0 -0
  33. umap/locale/pl/LC_MESSAGES/django.po +114 -103
  34. umap/locale/pt/LC_MESSAGES/django.mo +0 -0
  35. umap/locale/pt/LC_MESSAGES/django.po +43 -33
  36. umap/locale/th_TH/LC_MESSAGES/django.mo +0 -0
  37. umap/locale/th_TH/LC_MESSAGES/django.po +310 -109
  38. umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
  39. umap/locale/zh_TW/LC_MESSAGES/django.po +80 -70
  40. umap/management/commands/switch_user.py +2 -2
  41. umap/migrations/0018_datalayer_uuid.py +1 -1
  42. umap/models.py +7 -3
  43. umap/settings/local.py.sample +1 -1
  44. umap/static/umap/base.css +89 -32
  45. umap/static/umap/content.css +129 -33
  46. umap/static/umap/css/bar.css +82 -20
  47. umap/static/umap/css/browser.css +163 -0
  48. umap/static/umap/css/contextmenu.css +15 -0
  49. umap/static/umap/css/dialog.css +36 -16
  50. umap/static/umap/css/form.css +123 -33
  51. umap/static/umap/css/icon.css +46 -3
  52. umap/static/umap/css/panel.css +7 -3
  53. umap/static/umap/css/popup.css +34 -8
  54. umap/static/umap/css/tooltip.css +8 -4
  55. umap/static/umap/img/16-white.svg +26 -8
  56. umap/static/umap/img/16.svg +1 -1
  57. umap/static/umap/img/source/16-white.svg +36 -18
  58. umap/static/umap/img/source/16.svg +1 -1
  59. umap/static/umap/js/components/alerts/alert.css +69 -31
  60. umap/static/umap/js/components/alerts/alert.js +20 -2
  61. umap/static/umap/js/components/base.js +1 -1
  62. umap/static/umap/js/modules/browser.js +69 -61
  63. umap/static/umap/js/modules/caption.js +10 -7
  64. umap/static/umap/js/modules/data/features.js +85 -60
  65. umap/static/umap/js/modules/data/fields.js +446 -0
  66. umap/static/umap/js/modules/data/layer.js +78 -184
  67. umap/static/umap/js/modules/domutils.js +109 -0
  68. umap/static/umap/js/modules/filters.js +780 -0
  69. umap/static/umap/js/modules/form/builder.js +8 -5
  70. umap/static/umap/js/modules/form/fields.js +111 -221
  71. umap/static/umap/js/modules/formatter.js +24 -1
  72. umap/static/umap/js/modules/help.js +4 -3
  73. umap/static/umap/js/modules/i18n.js +1 -1
  74. umap/static/umap/js/modules/importer.js +1 -1
  75. umap/static/umap/js/modules/importers/opendata.js +15 -0
  76. umap/static/umap/js/modules/importers/openrouteservice.js +6 -1
  77. umap/static/umap/js/modules/managers.js +2 -2
  78. umap/static/umap/js/modules/permissions.js +39 -31
  79. umap/static/umap/js/modules/rendering/controls.js +11 -9
  80. umap/static/umap/js/modules/rendering/icon.js +3 -8
  81. umap/static/umap/js/modules/rendering/layers/base.js +1 -1
  82. umap/static/umap/js/modules/rendering/layers/classified.js +18 -11
  83. umap/static/umap/js/modules/rendering/layers/cluster.js +5 -3
  84. umap/static/umap/js/modules/rendering/layers/heat.js +27 -21
  85. umap/static/umap/js/modules/rendering/template.js +50 -23
  86. umap/static/umap/js/modules/rendering/ui.js +29 -23
  87. umap/static/umap/js/modules/rules.js +38 -44
  88. umap/static/umap/js/modules/schema.js +3 -6
  89. umap/static/umap/js/modules/share.js +5 -4
  90. umap/static/umap/js/modules/tableeditor.js +50 -38
  91. umap/static/umap/js/modules/templates.js +2 -3
  92. umap/static/umap/js/modules/ui/bar.js +55 -23
  93. umap/static/umap/js/modules/ui/dialog.js +38 -27
  94. umap/static/umap/js/modules/ui/panel.js +23 -8
  95. umap/static/umap/js/modules/ui/tooltip.js +6 -5
  96. umap/static/umap/js/modules/umap.js +151 -56
  97. umap/static/umap/js/modules/utils.js +24 -2
  98. umap/static/umap/js/umap.core.js +1 -110
  99. umap/static/umap/locale/am_ET.js +52 -17
  100. umap/static/umap/locale/am_ET.json +52 -17
  101. umap/static/umap/locale/ar.js +52 -17
  102. umap/static/umap/locale/ar.json +52 -17
  103. umap/static/umap/locale/ast.js +52 -17
  104. umap/static/umap/locale/ast.json +52 -17
  105. umap/static/umap/locale/bg.js +52 -17
  106. umap/static/umap/locale/bg.json +52 -17
  107. umap/static/umap/locale/br.js +48 -22
  108. umap/static/umap/locale/br.json +48 -22
  109. umap/static/umap/locale/ca.js +52 -17
  110. umap/static/umap/locale/ca.json +52 -17
  111. umap/static/umap/locale/cs_CZ.js +52 -17
  112. umap/static/umap/locale/cs_CZ.json +52 -17
  113. umap/static/umap/locale/da.js +54 -17
  114. umap/static/umap/locale/da.json +54 -17
  115. umap/static/umap/locale/de.js +51 -16
  116. umap/static/umap/locale/de.json +51 -16
  117. umap/static/umap/locale/el.js +52 -17
  118. umap/static/umap/locale/el.json +52 -17
  119. umap/static/umap/locale/en.js +53 -16
  120. umap/static/umap/locale/en.json +53 -16
  121. umap/static/umap/locale/en_US.json +52 -17
  122. umap/static/umap/locale/es.js +54 -17
  123. umap/static/umap/locale/es.json +54 -17
  124. umap/static/umap/locale/et.js +91 -56
  125. umap/static/umap/locale/et.json +91 -56
  126. umap/static/umap/locale/eu.js +84 -49
  127. umap/static/umap/locale/eu.json +84 -49
  128. umap/static/umap/locale/fa_IR.js +52 -17
  129. umap/static/umap/locale/fa_IR.json +52 -17
  130. umap/static/umap/locale/fi.js +52 -17
  131. umap/static/umap/locale/fi.json +52 -17
  132. umap/static/umap/locale/fr.js +53 -16
  133. umap/static/umap/locale/fr.json +53 -16
  134. umap/static/umap/locale/gl.js +52 -17
  135. umap/static/umap/locale/gl.json +52 -17
  136. umap/static/umap/locale/he.js +52 -17
  137. umap/static/umap/locale/he.json +52 -17
  138. umap/static/umap/locale/hr.js +52 -17
  139. umap/static/umap/locale/hr.json +52 -17
  140. umap/static/umap/locale/hu.js +59 -24
  141. umap/static/umap/locale/hu.json +59 -24
  142. umap/static/umap/locale/id.js +52 -17
  143. umap/static/umap/locale/id.json +52 -17
  144. umap/static/umap/locale/is.js +52 -17
  145. umap/static/umap/locale/is.json +52 -17
  146. umap/static/umap/locale/it.js +52 -17
  147. umap/static/umap/locale/it.json +52 -17
  148. umap/static/umap/locale/ja.js +52 -17
  149. umap/static/umap/locale/ja.json +52 -17
  150. umap/static/umap/locale/ko.js +52 -17
  151. umap/static/umap/locale/ko.json +52 -17
  152. umap/static/umap/locale/lt.js +52 -17
  153. umap/static/umap/locale/lt.json +52 -17
  154. umap/static/umap/locale/ms.js +52 -17
  155. umap/static/umap/locale/ms.json +52 -17
  156. umap/static/umap/locale/nl.js +52 -17
  157. umap/static/umap/locale/nl.json +52 -17
  158. umap/static/umap/locale/no.js +52 -17
  159. umap/static/umap/locale/no.json +52 -17
  160. umap/static/umap/locale/pl.js +53 -17
  161. umap/static/umap/locale/pl.json +53 -17
  162. umap/static/umap/locale/pl_PL.json +52 -17
  163. umap/static/umap/locale/pt.js +52 -17
  164. umap/static/umap/locale/pt.json +52 -17
  165. umap/static/umap/locale/pt_BR.js +52 -17
  166. umap/static/umap/locale/pt_BR.json +52 -17
  167. umap/static/umap/locale/pt_PT.js +52 -17
  168. umap/static/umap/locale/pt_PT.json +52 -17
  169. umap/static/umap/locale/ro.js +52 -17
  170. umap/static/umap/locale/ro.json +52 -17
  171. umap/static/umap/locale/ru.js +52 -17
  172. umap/static/umap/locale/ru.json +52 -17
  173. umap/static/umap/locale/si.js +1 -1
  174. umap/static/umap/locale/si.json +1 -1
  175. umap/static/umap/locale/sk_SK.js +52 -17
  176. umap/static/umap/locale/sk_SK.json +52 -17
  177. umap/static/umap/locale/sl.js +52 -17
  178. umap/static/umap/locale/sl.json +52 -17
  179. umap/static/umap/locale/sr.js +52 -17
  180. umap/static/umap/locale/sr.json +52 -17
  181. umap/static/umap/locale/sv.js +52 -17
  182. umap/static/umap/locale/sv.json +52 -17
  183. umap/static/umap/locale/th_TH.js +52 -17
  184. umap/static/umap/locale/th_TH.json +52 -17
  185. umap/static/umap/locale/tr.js +52 -17
  186. umap/static/umap/locale/tr.json +52 -17
  187. umap/static/umap/locale/uk_UA.js +52 -17
  188. umap/static/umap/locale/uk_UA.json +52 -17
  189. umap/static/umap/locale/vi.js +52 -17
  190. umap/static/umap/locale/vi.json +52 -17
  191. umap/static/umap/locale/vi_VN.json +52 -17
  192. umap/static/umap/locale/zh.js +52 -17
  193. umap/static/umap/locale/zh.json +52 -17
  194. umap/static/umap/locale/zh_CN.json +52 -17
  195. umap/static/umap/locale/zh_TW.Big5.json +52 -17
  196. umap/static/umap/locale/zh_TW.js +52 -16
  197. umap/static/umap/locale/zh_TW.json +52 -16
  198. umap/static/umap/map.css +63 -226
  199. umap/static/umap/unittests/utils.js +18 -0
  200. umap/static/umap/vars.css +23 -5
  201. umap/templates/umap/components/alerts/alert.html +32 -29
  202. umap/templates/umap/css.html +2 -1
  203. umap/templates/umap/login_popup_end.html +18 -9
  204. umap/templates/umap/user_map_table.html +7 -2
  205. umap/tests/integration/conftest.py +10 -6
  206. umap/tests/integration/test_anonymous_owned_map.py +90 -37
  207. umap/tests/integration/test_basics.py +25 -1
  208. umap/tests/integration/test_browser.py +37 -0
  209. umap/tests/integration/test_conditional_rules.py +107 -52
  210. umap/tests/integration/test_draw_polygon.py +6 -0
  211. umap/tests/integration/test_draw_polyline.py +11 -0
  212. umap/tests/integration/test_edit_marker.py +1 -1
  213. umap/tests/integration/test_export_map.py +19 -0
  214. umap/tests/integration/test_fields.py +541 -0
  215. umap/tests/integration/test_filters.py +616 -0
  216. umap/tests/integration/test_iframe.py +1 -1
  217. umap/tests/integration/test_import.py +38 -42
  218. umap/tests/integration/test_map_preview.py +1 -1
  219. umap/tests/integration/test_picto.py +1 -1
  220. umap/tests/integration/test_popup.py +31 -0
  221. umap/tests/integration/test_remote_data.py +60 -4
  222. umap/tests/integration/test_save.py +1 -1
  223. umap/tests/integration/test_share.py +4 -4
  224. umap/tests/integration/test_tableeditor.py +31 -7
  225. umap/tests/integration/test_websocket_sync.py +71 -20
  226. umap/tests/test_dashboard.py +11 -1
  227. umap/tests/test_statics.py +2 -2
  228. umap/tests/test_utils.py +19 -2
  229. umap/tests/test_views.py +1 -1
  230. umap/urls.py +1 -0
  231. umap/utils.py +8 -1
  232. umap/views.py +5 -0
  233. {umap_project-3.3.6.dist-info → umap_project-3.4.0.dist-info}/METADATA +15 -15
  234. {umap_project-3.3.6.dist-info → umap_project-3.4.0.dist-info}/RECORD +237 -233
  235. umap/static/umap/js/modules/facets.js +0 -164
  236. umap/tests/integration/test_facets_browser.py +0 -279
  237. {umap_project-3.3.6.dist-info → umap_project-3.4.0.dist-info}/WHEEL +0 -0
  238. {umap_project-3.3.6.dist-info → umap_project-3.4.0.dist-info}/entry_points.txt +0 -0
  239. {umap_project-3.3.6.dist-info → umap_project-3.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -2,7 +2,6 @@ import { DomEvent, DomUtil, stamp } from '../../vendors/leaflet/leaflet-src.esm.
2
2
  import { Form } from './form/builder.js'
3
3
  import { EXPORT_FORMATS } from './formatter.js'
4
4
  import { translate } from './i18n.js'
5
- import * as Icon from './rendering/icon.js'
6
5
  import ContextMenu from './ui/contextmenu.js'
7
6
  import * as Utils from './utils.js'
8
7
  import { SCHEMA } from './schema.js'
@@ -23,28 +22,22 @@ export default class Browser {
23
22
  if (feature.isFiltered()) return
24
23
  if (this.options.inBbox && !feature.isOnScreen(this.bounds)) return
25
24
  const template = `
26
- <li class="feature ${feature.getClassName()}">
27
- <button class="icon icon-16 icon-zoom" title="${translate('Bring feature to center')}" data-ref=zoom></button>
28
- <button class="icon icon-16 show-on-edit icon-edit" title="${translate('Edit this feature')}" data-ref=edit></button>
29
- <button class="icon icon-16 show-on-edit icon-delete" title="${translate('Delete this feature')}" data-ref=remove></button>
30
- <i class="icon icon-16 icon-${feature.getClassName()} feature-color" data-ref=colorBox></i>
31
- <span class="feature-title" data-ref=label></span>
25
+ <li class="feature ${feature.getClassName()} ${feature.getUniqueClassName()} with-toolbox">
26
+ <span>
27
+ <i class="icon icon-16 icon-${feature.getClassName()} feature-color" data-ref=colorBox></i>
28
+ <span class="feature-title truncate" data-ref=label></span>
29
+ </span>
30
+ <span>
31
+ <button class="icon icon-16 icon-zoom" title="${translate('Bring feature to center')}" data-ref=zoom></button
32
+ ><button class="icon icon-16 show-on-edit icon-edit" title="${translate('Edit this feature')}" data-ref=edit></button
33
+ ><button class="icon icon-16 show-on-edit icon-delete" title="${translate('Delete this feature')}" data-ref=remove></button>
34
+ </span>
32
35
  </li>
33
36
  `
34
37
  const [row, { zoom, edit, remove, colorBox, label }] =
35
38
  Utils.loadTemplateWithRefs(template)
36
39
  label.textContent = label.title = feature.getDisplayName() || '—'
37
- const symbol = feature._getIconUrl
38
- ? Icon.formatUrl(feature._getIconUrl(), feature)
39
- : null
40
- const bgcolor = feature.getPreviewColor()
41
- colorBox.style.backgroundColor = bgcolor
42
- if (symbol && symbol !== SCHEMA.iconUrl.default) {
43
- const icon = Icon.makeElement(symbol, colorBox)
44
- Icon.setContrast(icon, colorBox, symbol, bgcolor)
45
- } else if (DomUtil.contrastedColor(colorBox, bgcolor)) {
46
- colorBox.classList.add('icon-white')
47
- }
40
+ feature.makePreview(colorBox)
48
41
  const viewFeature = (e) => {
49
42
  feature.zoomTo({ ...e, callback: () => feature.view() })
50
43
  }
@@ -65,21 +58,23 @@ export default class Browser {
65
58
  addDataLayer(datalayer, parent) {
66
59
  const open = this.mode !== 'layers' ? ' open' : ''
67
60
  const [container, { headline, toolbox, label }] = Utils.loadTemplateWithRefs(`
68
- <details class="datalayer ${datalayer.getHidableClass()}" id="${this.datalayerId(datalayer)}"${open}>
69
- <summary data-ref=headline>
61
+ <details class="datalayer ${datalayer.cssId}" id="${this.datalayerId(datalayer)}"${open}>
62
+ <summary data-ref=headline class="with-toolbox">
63
+ <span>
64
+ <span class="datalayer-name truncate" data-id="${datalayer.id}" data-ref=label></span>
65
+ <span class="datalayer-counter"></span>
66
+ </span>
70
67
  <span data-ref=toolbox></span>
71
- <span class="datalayer-name" data-id="${datalayer.id}" data-ref=label></span>
72
- <span class="datalayer-counter"></span>
73
68
  </summary>
74
69
  <ul></ul>
75
70
  </details>
76
71
  `)
77
72
  datalayer.renderToolbox(toolbox)
78
73
  parent.appendChild(container)
79
- this.updateDatalayer(datalayer)
74
+ this.updateFeaturesList(datalayer)
80
75
  }
81
76
 
82
- updateDatalayer(datalayer) {
77
+ updateFeaturesList(datalayer) {
83
78
  // Compute once, but use it for each feature later.
84
79
  this.bounds = this._leafletMap.getBounds()
85
80
  const id = this.datalayerId(datalayer)
@@ -102,14 +97,14 @@ export default class Browser {
102
97
  }
103
98
 
104
99
  toggleBadge() {
105
- Utils.toggleBadge(this.filtersTitle, this.hasFilters())
106
- Utils.toggleBadge('.umap-control-browse', this.hasFilters())
100
+ Utils.toggleBadge(this.filtersTitle, this.hasActiveFilters())
101
+ Utils.toggleBadge('.umap-control-browse', this.hasActiveFilters())
107
102
  }
108
103
 
109
104
  onFormChange() {
110
105
  this._umap.datalayers.browsable().map((datalayer) => {
111
106
  datalayer.resetLayer(true)
112
- this.updateDatalayer(datalayer)
107
+ this.updateFeaturesList(datalayer)
113
108
  if (this._umap.fullPanel?.isOpen()) datalayer.tableEdit()
114
109
  })
115
110
  this.toggleBadge()
@@ -123,25 +118,24 @@ export default class Browser {
123
118
  return !!document.querySelector('.on .umap-browser')
124
119
  }
125
120
 
126
- hasFilters() {
127
- return !!this.options.filter || this._umap.facets.isActive()
121
+ hasActiveFilters() {
122
+ return !!this.options.filter || this._umap.hasActiveFilters()
128
123
  }
129
124
 
130
125
  onMoveEnd() {
131
126
  if (!this.isOpen()) return
132
- const isListDynamic = this.options.inBbox
133
127
  this._umap.datalayers.browsable().map((datalayer) => {
134
- if (!isListDynamic && !datalayer.hasDynamicData()) return
135
- this.updateDatalayer(datalayer)
128
+ if (!this.options.inBbox && !datalayer.hasDynamicData()) return
129
+ this.updateFeaturesList(datalayer)
136
130
  })
137
131
  }
138
132
 
139
133
  update() {
140
134
  if (!this.isOpen()) return
141
135
  this.dataContainer.innerHTML = ''
142
- this._umap.datalayers.browsable().map((datalayer) => {
136
+ for (const datalayer of this._umap.datalayers.browsable()) {
143
137
  this.addDataLayer(datalayer, this.dataContainer)
144
- })
138
+ }
145
139
  }
146
140
 
147
141
  open(mode) {
@@ -151,11 +145,14 @@ export default class Browser {
151
145
  <div>
152
146
  <h3><i class="icon icon-16 icon-layers"></i>${translate('Data browser')}</h3>
153
147
  <details class="filters" data-ref="details">
154
- <summary data-ref=filtersTitle><i class="icon icon-16 icon-filters"></i>${translate('Filters')}</summary>
148
+ <summary data-ref=filtersTitle>
149
+ <i class="icon icon-16 icon-filters"></i>${translate('Filters')}
150
+ </summary>
151
+ <button type="button" class="show-on-edit flat" data-ref=manageFilters>${translate('Manage filters')}</button>
155
152
  <fieldset>
156
- <div data-ref=formContainer>
153
+ <div data-ref="formContainer" class="formbox">
157
154
  </div>
158
- <button class="flat" type="button" data-ref=reset><i class="icon icon-16 icon-restore" title=""></i>${translate('Reset all')}</button>
155
+ <button class="flat" type="button" data-ref=reset><i class="icon icon-16 icon-restore" title=""></i> ${translate('Reset all')}</button>
159
156
  </fieldset>
160
157
  </details>
161
158
  <div class="main-toolbox">
@@ -177,6 +174,7 @@ export default class Browser {
177
174
  dataContainer,
178
175
  formContainer,
179
176
  reset,
177
+ manageFilters,
180
178
  },
181
179
  ] = Utils.loadTemplateWithRefs(template)
182
180
  // HOTFIX. Remove when this is released:
@@ -187,43 +185,53 @@ export default class Browser {
187
185
  fitBounds.addEventListener('click', () => this._umap.fitDataBounds())
188
186
  download.addEventListener('click', () => this.downloadVisible(download))
189
187
  download.hidden = this._umap.getProperty('embedControl') === false
188
+ reset.addEventListener('click', () => this.resetFilters())
189
+ manageFilters.addEventListener('click', () => {
190
+ this._umap.edit().then((panel) => panel.scrollTo('details#fields-management'))
191
+ this._umap.filters.edit()
192
+ })
190
193
 
191
194
  this.filtersTitle = filtersTitle
192
195
  this.dataContainer = dataContainer
193
196
  this.formContainer = formContainer
194
197
  this.toggleBadge()
198
+ this.buildFilters()
199
+ this._umap.panel.open({
200
+ content: container,
201
+ className: 'umap-browser',
202
+ })
203
+
204
+ this.update()
205
+ }
195
206
 
196
- let fields = [
207
+ buildFilters() {
208
+ this.formContainer.innerHTML = ''
209
+ const fields = [
197
210
  [
198
211
  'options.filter',
199
212
  { handler: 'Input', placeholder: translate('Search map features…') },
200
213
  ],
201
214
  ['options.inBbox', { handler: 'Switch', label: translate('Current map view') }],
202
215
  ]
203
- const builder = new Form(this, fields)
204
- builder.on('set', () => this.onFormChange())
205
- let filtersBuilder
206
- this.formContainer.appendChild(builder.build())
207
- builder.form.addEventListener('reset', () => {
208
- window.setTimeout(builder.syncAll.bind(builder))
209
- })
210
- if (this._umap.properties.facetKey) {
211
- fields = this._umap.facets.build()
212
- filtersBuilder = new Form(this._umap.facets, fields)
213
- filtersBuilder.on('set', () => this.onFormChange())
214
- filtersBuilder.form.addEventListener('reset', () => {
215
- window.setTimeout(filtersBuilder.syncAll.bind(filtersBuilder))
216
+ const searchForm = new Form(this, fields, { className: 'formbox' })
217
+ const listenFormChanges = (form) => {
218
+ form.on('set', () => this.onFormChange())
219
+ form.form.addEventListener('reset', () => {
220
+ window.setTimeout(form.syncAll.bind(form))
216
221
  })
217
- this.formContainer.appendChild(filtersBuilder.build())
218
222
  }
219
- reset.addEventListener('click', () => this.resetFilters())
220
-
221
- this._umap.panel.open({
222
- content: container,
223
- className: 'umap-browser',
224
- })
225
-
226
- this.update()
223
+ this.formContainer.appendChild(searchForm.build())
224
+ listenFormChanges(searchForm)
225
+ if (this._umap.filters.size) {
226
+ const filtersForm = this._umap.filters.buildForm(this.formContainer)
227
+ listenFormChanges(filtersForm)
228
+ }
229
+ for (const datalayer of this._umap.datalayers.active()) {
230
+ if (datalayer.filters.size) {
231
+ const filtersForm = datalayer.filters.buildForm(this.formContainer)
232
+ listenFormChanges(filtersForm)
233
+ }
234
+ }
227
235
  }
228
236
 
229
237
  resetFilters() {
@@ -252,7 +260,7 @@ export default class Browser {
252
260
  if (datalayer.isVisible()) allHidden = false
253
261
  })
254
262
  this._umap.datalayers.browsable().map((datalayer) => {
255
- datalayer.autoLoaded = false
263
+ datalayer.autoVisibility = false
256
264
  if (allHidden) {
257
265
  datalayer.show()
258
266
  } else {
@@ -5,7 +5,7 @@ import * as Utils from './utils.js'
5
5
  const TEMPLATE = `
6
6
  <div class="umap-caption">
7
7
  <div class="header">
8
- <i class="icon icon-16 icon-caption icon-block"></i>
8
+ <i class="icon icon-16 icon-info icon-block"></i>
9
9
  <hgroup>
10
10
  <h3><span class="map-name" data-ref="name"></span></h3>
11
11
  <p data-ref="author"></p>
@@ -39,7 +39,7 @@ export default class Caption extends Utils.WithTemplate {
39
39
  this._leafletMap = leafletMap
40
40
  this.loadTemplate(TEMPLATE)
41
41
  this.elements.star.addEventListener('click', async () => {
42
- if (this._umap.properties.user?.id) {
42
+ if (this._umap.permissions.userIsAuth()) {
43
43
  await this._umap.star()
44
44
  this.refresh()
45
45
  } else {
@@ -96,11 +96,14 @@ export default class Caption extends Utils.WithTemplate {
96
96
  addDataLayer(datalayer, parent) {
97
97
  if (!datalayer.properties.inCaption) return
98
98
  const template = `
99
- <p class="caption-item ${datalayer.cssId}">
100
- <span class="datalayer-legend"></span>
101
- <strong data-ref="toolbox"></strong>
102
- <span class="text" data-ref="description"></span>
103
- </p>`
99
+ <div class="caption-item ${datalayer.cssId}">
100
+ <p>
101
+ <span class="datalayer-legend"></span>
102
+ <strong data-ref="toolbox"></strong>
103
+ </p>
104
+ <p class="text" data-ref="description"></p>
105
+ </div>
106
+ `
104
107
  const [element, { toolbox, description }] = Utils.loadTemplateWithRefs(template)
105
108
  if (datalayer.properties.description) {
106
109
  description.innerHTML = Utils.toHTML(datalayer.properties.description)
@@ -22,6 +22,8 @@ import {
22
22
  } from '../rendering/ui.js'
23
23
  import { SCHEMA } from '../schema.js'
24
24
  import * as Utils from '../utils.js'
25
+ import * as DOMUtils from '../domutils.js'
26
+ import * as Icon from '../rendering/icon.js'
25
27
 
26
28
  class Feature {
27
29
  constructor(umap, datalayer, geojson = {}, id = null) {
@@ -91,7 +93,7 @@ class Feature {
91
93
 
92
94
  get fields() {
93
95
  // Fields are user defined properties
94
- return [...this.datalayer.fields, ...this._umap.fields]
96
+ return [...this._umap.fields.all(), ...this.datalayer.fields.all()]
95
97
  }
96
98
 
97
99
  setter(key, value) {
@@ -136,6 +138,10 @@ class Feature {
136
138
  return this.staticOptions.className
137
139
  }
138
140
 
141
+ getUniqueClassName() {
142
+ return `feature-${this.datalayer.id}-${this.id}`
143
+ }
144
+
139
145
  getPreviewColor() {
140
146
  return this.getDynamicOption(this.staticOptions.mainColor)
141
147
  }
@@ -213,10 +219,22 @@ class Feature {
213
219
  return field.startsWith('properties.')
214
220
  })
215
221
  if (impactData) {
222
+ Utils.eachElement(`.${this.getUniqueClassName()} .feature-title`, (el) => {
223
+ el.textContent = this.getDisplayName()
224
+ el.title = this.getDisplayName()
225
+ })
216
226
  if (this._umap.currentFeature === this) {
217
227
  this.view()
218
228
  }
219
229
  }
230
+ const impactPreview = fields.some((field) => {
231
+ return field.startsWith('properties._umap_options')
232
+ })
233
+ if (impactPreview) {
234
+ Utils.eachElement(`.${this.getUniqueClassName()} .feature-color`, (el) => {
235
+ this.makePreview(el)
236
+ })
237
+ }
220
238
  this.redraw()
221
239
  }
222
240
 
@@ -233,7 +251,7 @@ class Feature {
233
251
  )
234
252
 
235
253
  let builder = new MutatingForm(this, [
236
- ['datalayer', { handler: 'DataLayerSwitcher' }],
254
+ ['datalayer', { handler: 'EditableDataLayerSwitcher' }],
237
255
  ])
238
256
  // removeLayer step will close the edit panel, let's reopen it
239
257
  builder.on('set', () => this.edit(event))
@@ -242,9 +260,19 @@ class Feature {
242
260
  const properties = []
243
261
  for (const field of this.fields) {
244
262
  const options = { handler: 'Input', label: field.key }
245
- if (field.key === 'description' || field.type === 'Text') {
263
+ if (field.key === 'description' || field.TYPE === 'Text') {
246
264
  options.handler = 'Textarea'
247
265
  options.helpEntries = ['textFormatting']
266
+ } else if (field.TYPE === 'Number') {
267
+ options.handler = 'FloatInput'
268
+ } else if (field.TYPE === 'Date') {
269
+ options.handler = 'DateInput'
270
+ } else if (field.TYPE === 'Datetime') {
271
+ options.handler = 'DateTimeInput'
272
+ } else if (field.TYPE === 'Boolean') {
273
+ options.handler = 'Switch'
274
+ } else if (field.TYPE === 'Enum') {
275
+ options.helpText = translate('Comma separated list of values')
248
276
  }
249
277
  properties.push([`properties.${field.key}`, options])
250
278
  }
@@ -257,13 +285,13 @@ class Feature {
257
285
  `<button type="button"><i class="icon icon-16 icon-add"></i>${translate('Add a new field')}</button>`
258
286
  )
259
287
  button.addEventListener('click', () => {
260
- this.datalayer.addProperty().then(() => this.edit({ force: true }))
288
+ this.datalayer.fields.editField().then(() => this.edit({ force: true }))
261
289
  })
262
290
  form.appendChild(button)
263
291
  this.appendEditFieldsets(container)
264
292
  const [details, { fieldset }] = Utils.loadTemplateWithRefs(`
265
293
  <details>
266
- <summary>${translate('Advanced actions')}</summary>
294
+ <summary><h4>${translate('Advanced actions')}</h4></summary>
267
295
  <fieldset class="button-bar by2" data-ref=fieldset></fieldset>
268
296
  </details>
269
297
  `)
@@ -298,7 +326,7 @@ class Feature {
298
326
  container.appendChild(button)
299
327
  }
300
328
 
301
- addExtraEditFieldset() {}
329
+ addExtraEditFieldset(container) {}
302
330
 
303
331
  appendEditFieldsets(container) {
304
332
  const optionsFields = this.getShapeOptions()
@@ -498,16 +526,16 @@ class Feature {
498
526
  return properties
499
527
  }
500
528
 
501
- deleteProperty(property) {
502
- const oldValue = this.properties[property]
503
- delete this.properties[property]
504
- this.sync.update(`properties.${property}`, undefined, oldValue)
529
+ deleteField(name) {
530
+ const oldValue = this.properties[name]
531
+ delete this.properties[name]
532
+ this.sync.update(`properties.${name}`, undefined, oldValue)
505
533
  }
506
534
 
507
- renameProperty(from, to) {
535
+ renameField(from, to) {
508
536
  const oldValue = this.properties[from]
509
537
  this.properties[to] = this.properties[from]
510
- this.deleteProperty(from)
538
+ this.deleteField(from)
511
539
  this.sync.update(`properties.${to}`, oldValue, undefined)
512
540
  }
513
541
 
@@ -523,12 +551,13 @@ class Feature {
523
551
  isFiltered() {
524
552
  const filterKeys = this.datalayer.getFilterKeys()
525
553
  const filter = this._umap.browser.options.filter
526
- if (filter && !this.matchFilter(filter, filterKeys)) return true
527
- if (!this.matchFacets()) return true
554
+ if (filter && !this.matchFullTextFilter(filter, filterKeys)) return true
555
+ if (this._umap.filters.matchFeature(this)) return true
556
+ if (this.datalayer.filters.matchFeature(this)) return true
528
557
  return false
529
558
  }
530
559
 
531
- matchFilter(filter, keys) {
560
+ matchFullTextFilter(filter, keys) {
532
561
  filter = filter.toLowerCase()
533
562
  // When user hasn't touched settings, when a feature has no name
534
563
  // it will use the datalayer's name, so let's make the filtering
@@ -546,28 +575,6 @@ class Feature {
546
575
  return false
547
576
  }
548
577
 
549
- matchFacets() {
550
- const selected = this._umap.facets.selected
551
- for (const [name, { type, min, max, choices }] of Object.entries(selected)) {
552
- let value = this.properties[name]
553
- const parser = this._umap.facets.getParser(type)
554
- value = parser(value)
555
- switch (type) {
556
- case 'date':
557
- case 'datetime':
558
- case 'number':
559
- if (!Number.isNaN(min) && !Number.isNaN(value) && min > value) return false
560
- if (!Number.isNaN(max) && !Number.isNaN(value) && max < value) return false
561
- break
562
- default:
563
- value = value || translate('<empty value>')
564
- if (choices?.length && !choices.includes(value)) return false
565
- break
566
- }
567
- }
568
- return true
569
- }
570
-
571
578
  isMulti() {
572
579
  return false
573
580
  }
@@ -593,6 +600,7 @@ class Feature {
593
600
  if (U.lang) properties.lang = U.lang
594
601
  properties.rank = this.getRank() + 1
595
602
  properties.layer = this.datalayer.getName()
603
+ properties.id = this.id
596
604
  if (this.ui._map && this.hasGeom()) {
597
605
  const center = this.center
598
606
  properties.lat = center.lat
@@ -611,7 +619,7 @@ class Feature {
611
619
  }
612
620
 
613
621
  redraw() {
614
- if (this.datalayer?.isVisible()) {
622
+ if (this.datalayer?.isVisible() && this.ui?.isVisible()) {
615
623
  if (this.getUIClass() !== this.ui.getClass()) {
616
624
  this.datalayer.hideFeature(this)
617
625
  this.makeUI()
@@ -647,8 +655,7 @@ class Feature {
647
655
  items.push({
648
656
  label: translate('Copy as GeoJSON'),
649
657
  action: () => {
650
- L.Util.copyToClipboard(JSON.stringify(this.toGeoJSON()))
651
- this._umap.tooltip.open({ content: L._('✅ Copied!') })
658
+ DOMUtils.copyToClipboard(JSON.stringify(this.toGeoJSON()))
652
659
  },
653
660
  })
654
661
  return items
@@ -707,6 +714,19 @@ class Feature {
707
714
  this.ui.closePopup()
708
715
  }
709
716
  }
717
+
718
+ makePreview(element) {
719
+ element.innerHTML = ''
720
+ const symbol = this._getIconUrl ? Icon.formatUrl(this._getIconUrl(), this) : null
721
+ const bgcolor = this.getPreviewColor()
722
+ element.style.backgroundColor = bgcolor
723
+ if (symbol && symbol !== SCHEMA.iconUrl.default) {
724
+ const icon = Icon.makeElement(symbol, element)
725
+ Icon.setContrast(icon, element, symbol, bgcolor)
726
+ } else if (DOMUtils.contrastedColor(element, bgcolor)) {
727
+ element.classList.add('icon-white')
728
+ }
729
+ }
710
730
  }
711
731
 
712
732
  export class Point extends Feature {
@@ -932,6 +952,23 @@ class Path extends Feature {
932
952
  }
933
953
  return items
934
954
  }
955
+
956
+ addExtraEditFieldset(container) {
957
+ const options = [
958
+ 'properties._umap_options.textPath',
959
+ 'properties._umap_options.textPathColor',
960
+ 'properties._umap_options.textPathRepeat',
961
+ 'properties._umap_options.textPathRotate',
962
+ 'properties._umap_options.textPathSize',
963
+ 'properties._umap_options.textPathOffset',
964
+ 'properties._umap_options.textPathPosition',
965
+ ]
966
+ const builder = new MutatingForm(this, options, {
967
+ id: 'umap-feature-line-decoration',
968
+ })
969
+ const fieldset = DomUtil.createFieldset(container, translate('Line decoration'))
970
+ fieldset.appendChild(builder.build())
971
+ }
935
972
  }
936
973
 
937
974
  export class LineString extends Path {
@@ -1230,26 +1267,6 @@ export class LineString extends Path {
1230
1267
  button.addEventListener('click', async () => this.computeRoute())
1231
1268
  }
1232
1269
 
1233
- addExtraEditFieldset(container) {
1234
- const options = [
1235
- 'properties._umap_options.textPath',
1236
- 'properties._umap_options.textPathColor',
1237
- 'properties._umap_options.textPathRepeat',
1238
- 'properties._umap_options.textPathRotate',
1239
- 'properties._umap_options.textPathSize',
1240
- 'properties._umap_options.textPathOffset',
1241
- 'properties._umap_options.textPathPosition',
1242
- ]
1243
- const builder = new MutatingForm(this, options, {
1244
- id: 'umap-feature-line-decoration',
1245
- })
1246
- const fieldset = DomUtil.createFieldset(container, translate('Line decoration'))
1247
- fieldset.appendChild(builder.build())
1248
- if (this._umap.properties.ORSAPIKey && this.isRoute()) {
1249
- this._editRoute(container)
1250
- }
1251
- }
1252
-
1253
1270
  async computeElevation() {
1254
1271
  if (!this._umap.properties.ORSAPIKey) return
1255
1272
  const importer = new OpenRouteService(this._umap)
@@ -1259,6 +1276,7 @@ export class LineString extends Path {
1259
1276
  this.geometry = geometry
1260
1277
  this.ui.resetTooltip()
1261
1278
  this.sync.update('geometry', this.geometry, oldGeometry)
1279
+ Alert.success(translate('Elevation has been added!'))
1262
1280
  }
1263
1281
  }
1264
1282
 
@@ -1274,6 +1292,13 @@ export class LineString extends Path {
1274
1292
  }
1275
1293
  })
1276
1294
  }
1295
+
1296
+ addExtraEditFieldset(container) {
1297
+ super.addExtraEditFieldset(container)
1298
+ if (this._umap.properties.ORSAPIKey && this.isRoute()) {
1299
+ this._editRoute(container)
1300
+ }
1301
+ }
1277
1302
  }
1278
1303
 
1279
1304
  export class Polygon extends Path {