umap-project 3.4.0b3__py3-none-any.whl → 3.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. umap/__init__.py +1 -1
  2. umap/locale/br/LC_MESSAGES/django.mo +0 -0
  3. umap/locale/br/LC_MESSAGES/django.po +71 -57
  4. umap/locale/da/LC_MESSAGES/django.mo +0 -0
  5. umap/locale/da/LC_MESSAGES/django.po +18 -14
  6. umap/locale/de/LC_MESSAGES/django.mo +0 -0
  7. umap/locale/de/LC_MESSAGES/django.po +20 -16
  8. umap/locale/en/LC_MESSAGES/django.po +18 -14
  9. umap/locale/es/LC_MESSAGES/django.mo +0 -0
  10. umap/locale/es/LC_MESSAGES/django.po +20 -16
  11. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  12. umap/locale/fr/LC_MESSAGES/django.po +18 -14
  13. umap/locale/hu/LC_MESSAGES/django.mo +0 -0
  14. umap/locale/hu/LC_MESSAGES/django.po +20 -16
  15. umap/locale/pl/LC_MESSAGES/django.mo +0 -0
  16. umap/locale/pl/LC_MESSAGES/django.po +101 -95
  17. umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
  18. umap/locale/zh_TW/LC_MESSAGES/django.po +20 -16
  19. umap/management/commands/clean_tilelayer.py +0 -1
  20. umap/management/commands/search_maps.py +95 -0
  21. umap/settings/__init__.py +9 -1
  22. umap/settings/base.py +7 -6
  23. umap/static/umap/content.css +0 -3
  24. umap/static/umap/css/bar.css +9 -6
  25. umap/static/umap/css/form.css +25 -9
  26. umap/static/umap/css/icon.css +8 -0
  27. umap/static/umap/css/popup.css +1 -0
  28. umap/static/umap/img/16-white.svg +5 -2
  29. umap/static/umap/img/16.svg +1 -1
  30. umap/static/umap/img/source/16-white.svg +7 -4
  31. umap/static/umap/img/source/16.svg +1 -1
  32. umap/static/umap/js/components/copiable.js +47 -0
  33. umap/static/umap/js/modules/autocomplete.js +32 -67
  34. umap/static/umap/js/modules/browser.js +31 -14
  35. umap/static/umap/js/modules/data/features.js +34 -36
  36. umap/static/umap/js/modules/data/fields.js +199 -23
  37. umap/static/umap/js/modules/data/layer.js +85 -96
  38. umap/static/umap/js/modules/domutils.js +25 -1
  39. umap/static/umap/js/modules/filters.js +24 -50
  40. umap/static/umap/js/modules/form/builder.js +17 -16
  41. umap/static/umap/js/modules/form/fields.js +20 -20
  42. umap/static/umap/js/modules/formatter.js +9 -1
  43. umap/static/umap/js/modules/help.js +12 -13
  44. umap/static/umap/js/modules/importer.js +17 -26
  45. umap/static/umap/js/modules/importers/banfr.js +0 -1
  46. umap/static/umap/js/modules/importers/cadastrefr.js +19 -19
  47. umap/static/umap/js/modules/importers/communesfr.js +7 -8
  48. umap/static/umap/js/modules/importers/datasets.js +14 -14
  49. umap/static/umap/js/modules/importers/geodatamine.js +20 -22
  50. umap/static/umap/js/modules/importers/opendata.js +10 -0
  51. umap/static/umap/js/modules/importers/overpass.js +19 -18
  52. umap/static/umap/js/modules/managers.js +1 -1
  53. umap/static/umap/js/modules/permissions.js +15 -5
  54. umap/static/umap/js/modules/rendering/controls.js +203 -10
  55. umap/static/umap/js/modules/rendering/icon.js +5 -9
  56. umap/static/umap/js/modules/rendering/layers/base.js +1 -1
  57. umap/static/umap/js/modules/rendering/layers/classified.js +16 -11
  58. umap/static/umap/js/modules/rendering/layers/heat.js +1 -0
  59. umap/static/umap/js/modules/rendering/map.js +67 -57
  60. umap/static/umap/js/modules/rendering/popup.js +6 -3
  61. umap/static/umap/js/modules/rendering/template.js +40 -40
  62. umap/static/umap/js/modules/rendering/ui.js +1 -2
  63. umap/static/umap/js/modules/rules.js +34 -41
  64. umap/static/umap/js/modules/schema.js +0 -7
  65. umap/static/umap/js/modules/share.js +36 -69
  66. umap/static/umap/js/modules/slideshow.js +3 -3
  67. umap/static/umap/js/modules/tableeditor.js +0 -1
  68. umap/static/umap/js/modules/ui/bar.js +53 -33
  69. umap/static/umap/js/modules/ui/hash.js +36 -0
  70. umap/static/umap/js/modules/ui/loader.js +26 -0
  71. umap/static/umap/js/modules/ui/panel.js +33 -21
  72. umap/static/umap/js/modules/ui/tooltip.js +1 -1
  73. umap/static/umap/js/modules/umap.js +81 -80
  74. umap/static/umap/js/modules/utils.js +13 -3
  75. umap/static/umap/js/umap.controls.js +16 -179
  76. umap/static/umap/locale/am_ET.js +7 -8
  77. umap/static/umap/locale/am_ET.json +7 -8
  78. umap/static/umap/locale/ar.js +7 -8
  79. umap/static/umap/locale/ar.json +7 -8
  80. umap/static/umap/locale/ast.js +7 -8
  81. umap/static/umap/locale/ast.json +7 -8
  82. umap/static/umap/locale/bg.js +7 -8
  83. umap/static/umap/locale/bg.json +7 -8
  84. umap/static/umap/locale/br.js +44 -36
  85. umap/static/umap/locale/br.json +44 -36
  86. umap/static/umap/locale/ca.js +7 -8
  87. umap/static/umap/locale/ca.json +7 -8
  88. umap/static/umap/locale/cs_CZ.js +7 -8
  89. umap/static/umap/locale/cs_CZ.json +7 -8
  90. umap/static/umap/locale/da.js +8 -9
  91. umap/static/umap/locale/da.json +8 -9
  92. umap/static/umap/locale/de.js +62 -63
  93. umap/static/umap/locale/de.json +62 -63
  94. umap/static/umap/locale/el.js +7 -8
  95. umap/static/umap/locale/el.json +7 -8
  96. umap/static/umap/locale/en.js +7 -8
  97. umap/static/umap/locale/en.json +7 -8
  98. umap/static/umap/locale/en_US.json +7 -8
  99. umap/static/umap/locale/es.js +19 -20
  100. umap/static/umap/locale/es.json +19 -20
  101. umap/static/umap/locale/et.js +7 -8
  102. umap/static/umap/locale/et.json +7 -8
  103. umap/static/umap/locale/eu.js +23 -24
  104. umap/static/umap/locale/eu.json +23 -24
  105. umap/static/umap/locale/fa_IR.js +7 -8
  106. umap/static/umap/locale/fa_IR.json +7 -8
  107. umap/static/umap/locale/fi.js +7 -8
  108. umap/static/umap/locale/fi.json +7 -8
  109. umap/static/umap/locale/fr.js +11 -12
  110. umap/static/umap/locale/fr.json +11 -12
  111. umap/static/umap/locale/gl.js +147 -148
  112. umap/static/umap/locale/gl.json +147 -148
  113. umap/static/umap/locale/he.js +7 -8
  114. umap/static/umap/locale/he.json +7 -8
  115. umap/static/umap/locale/hr.js +7 -8
  116. umap/static/umap/locale/hr.json +7 -8
  117. umap/static/umap/locale/hu.js +8 -9
  118. umap/static/umap/locale/hu.json +8 -9
  119. umap/static/umap/locale/id.js +7 -8
  120. umap/static/umap/locale/id.json +7 -8
  121. umap/static/umap/locale/is.js +7 -8
  122. umap/static/umap/locale/is.json +7 -8
  123. umap/static/umap/locale/it.js +7 -8
  124. umap/static/umap/locale/it.json +7 -8
  125. umap/static/umap/locale/ja.js +7 -8
  126. umap/static/umap/locale/ja.json +7 -8
  127. umap/static/umap/locale/ko.js +7 -8
  128. umap/static/umap/locale/ko.json +7 -8
  129. umap/static/umap/locale/lt.js +7 -8
  130. umap/static/umap/locale/lt.json +7 -8
  131. umap/static/umap/locale/ms.js +7 -8
  132. umap/static/umap/locale/ms.json +7 -8
  133. umap/static/umap/locale/nl.js +7 -8
  134. umap/static/umap/locale/nl.json +7 -8
  135. umap/static/umap/locale/no.js +7 -8
  136. umap/static/umap/locale/no.json +7 -8
  137. umap/static/umap/locale/pl.js +53 -54
  138. umap/static/umap/locale/pl.json +53 -54
  139. umap/static/umap/locale/pl_PL.json +7 -8
  140. umap/static/umap/locale/pt.js +7 -8
  141. umap/static/umap/locale/pt.json +7 -8
  142. umap/static/umap/locale/pt_BR.js +7 -8
  143. umap/static/umap/locale/pt_BR.json +7 -8
  144. umap/static/umap/locale/pt_PT.js +7 -8
  145. umap/static/umap/locale/pt_PT.json +7 -8
  146. umap/static/umap/locale/ro.js +7 -8
  147. umap/static/umap/locale/ro.json +7 -8
  148. umap/static/umap/locale/ru.js +7 -8
  149. umap/static/umap/locale/ru.json +7 -8
  150. umap/static/umap/locale/sk_SK.js +7 -8
  151. umap/static/umap/locale/sk_SK.json +7 -8
  152. umap/static/umap/locale/sl.js +7 -8
  153. umap/static/umap/locale/sl.json +7 -8
  154. umap/static/umap/locale/sr.js +7 -8
  155. umap/static/umap/locale/sr.json +7 -8
  156. umap/static/umap/locale/sv.js +7 -8
  157. umap/static/umap/locale/sv.json +7 -8
  158. umap/static/umap/locale/th_TH.js +7 -8
  159. umap/static/umap/locale/th_TH.json +7 -8
  160. umap/static/umap/locale/tr.js +7 -8
  161. umap/static/umap/locale/tr.json +7 -8
  162. umap/static/umap/locale/uk_UA.js +7 -8
  163. umap/static/umap/locale/uk_UA.json +7 -8
  164. umap/static/umap/locale/vi.js +7 -8
  165. umap/static/umap/locale/vi.json +7 -8
  166. umap/static/umap/locale/vi_VN.json +7 -8
  167. umap/static/umap/locale/zh.js +7 -8
  168. umap/static/umap/locale/zh.json +7 -8
  169. umap/static/umap/locale/zh_CN.json +7 -8
  170. umap/static/umap/locale/zh_TW.Big5.json +7 -8
  171. umap/static/umap/locale/zh_TW.js +20 -21
  172. umap/static/umap/locale/zh_TW.json +20 -21
  173. umap/static/umap/map.css +6 -21
  174. umap/static/umap/unittests/utils.js +7 -7
  175. umap/static/umap/vendors/locatecontrol/L.Control.Locate.esm.js +942 -0
  176. umap/static/umap/vendors/photon/leaflet.photon.esm.js +472 -0
  177. umap/sync/app.py +4 -1
  178. umap/templates/umap/content_footer.html +1 -0
  179. umap/templates/umap/css.html +0 -4
  180. umap/templates/umap/js.html +1 -8
  181. umap/templates/umap/team_form.html +2 -1
  182. umap/tests/integration/conftest.py +3 -2
  183. umap/tests/integration/test_anonymous_owned_map.py +1 -1
  184. umap/tests/integration/test_conditional_rules.py +106 -51
  185. umap/tests/integration/test_draw_polygon.py +4 -0
  186. umap/tests/integration/test_draw_polyline.py +11 -0
  187. umap/tests/integration/test_edit_datalayer.py +1 -1
  188. umap/tests/integration/test_edit_map.py +2 -0
  189. umap/tests/integration/test_fields.py +19 -0
  190. umap/tests/integration/test_filters.py +24 -0
  191. umap/tests/integration/test_iframe.py +1 -1
  192. umap/tests/integration/test_import.py +26 -0
  193. umap/tests/integration/test_map.py +3 -3
  194. umap/tests/integration/test_optimistic_merge.py +7 -1
  195. umap/tests/integration/test_owned_map.py +2 -2
  196. umap/tests/integration/test_popup.py +31 -0
  197. umap/tests/integration/test_remote_data.py +5 -5
  198. umap/tests/integration/test_search.py +41 -0
  199. umap/tests/integration/test_share.py +2 -2
  200. umap/tests/integration/test_team.py +1 -1
  201. umap/tests/integration/test_websocket_sync.py +6 -1
  202. umap/tests/test_search_maps_command.py +44 -0
  203. umap/tests/test_utils.py +4 -1
  204. umap/utils.py +10 -3
  205. umap/views.py +17 -4
  206. {umap_project-3.4.0b3.dist-info → umap_project-3.6.0.dist-info}/METADATA +29 -23
  207. {umap_project-3.4.0b3.dist-info → umap_project-3.6.0.dist-info}/RECORD +210 -214
  208. {umap_project-3.4.0b3.dist-info → umap_project-3.6.0.dist-info}/WHEEL +1 -1
  209. umap/static/umap/js/umap.core.js +0 -93
  210. umap/static/umap/vendors/editinosm/Leaflet.EditInOSM.css +0 -46
  211. umap/static/umap/vendors/editinosm/Leaflet.EditInOSM.js +0 -240
  212. umap/static/umap/vendors/editinosm/edit-in-osm.png +0 -0
  213. umap/static/umap/vendors/hash/leaflet-hash.js +0 -162
  214. umap/static/umap/vendors/loading/Control.Loading.css +0 -26
  215. umap/static/umap/vendors/loading/Control.Loading.js +0 -351
  216. umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.css +0 -1
  217. umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.css.map +0 -1
  218. umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.js +0 -4
  219. umap/static/umap/vendors/locatecontrol/L.Control.Locate.min.js.map +0 -1
  220. umap/static/umap/vendors/photon/leaflet.photon.js +0 -487
  221. {umap_project-3.4.0b3.dist-info → umap_project-3.6.0.dist-info}/entry_points.txt +0 -0
  222. {umap_project-3.4.0b3.dist-info → umap_project-3.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,8 +1,3 @@
1
- import {
2
- DomUtil,
3
- Util as LeafletUtil,
4
- latLngBounds,
5
- } from '../../vendors/leaflet/leaflet-src.esm.js'
6
1
  import {
7
2
  uMapAlert as Alert,
8
3
  uMapAlertCreation as AlertCreation,
@@ -36,6 +31,8 @@ import * as Utils from './utils.js'
36
31
  import * as DOMUtils from './domutils.js'
37
32
  import { DataLayerManager } from './managers.js'
38
33
  import { Importer as OpenRouteService } from './importers/openrouteservice.js'
34
+ import Loader from './ui/loader.js'
35
+ import Hash from './ui/hash.js'
39
36
 
40
37
  export default class Umap {
41
38
  constructor(element, geojson) {
@@ -115,6 +112,10 @@ export default class Umap {
115
112
  this.properties.homeControl = false
116
113
  }
117
114
 
115
+ this.loader = new Loader(this._leafletMap._container)
116
+ if (this.properties.hash) {
117
+ this.hash = new Hash()
118
+ }
118
119
  this._leafletMap.setup()
119
120
 
120
121
  this.panel = new Panel(this, this._leafletMap)
@@ -261,15 +262,6 @@ export default class Umap {
261
262
  return window.self !== window.top
262
263
  }
263
264
 
264
- get fieldKeys() {
265
- return Array.from(
266
- new Set([
267
- ...this.fields.keys(),
268
- ...this.datalayers.active().reduce((acc, dl) => acc.concat(dl.fieldKeys), []),
269
- ])
270
- )
271
- }
272
-
273
265
  setPropertiesFromQueryString() {
274
266
  const asBoolean = (key) => {
275
267
  const value = this.searchParams.get(key)
@@ -681,7 +673,7 @@ export default class Umap {
681
673
  const parent = this._leafletMap.getPane('overlayPane')
682
674
  const datalayers = Object.values(this.datalayers)
683
675
  .filter((datalayer) => !datalayer._isDeleted)
684
- .sort((datalayer1, datalayer2) => datalayer1.rank > datalayer2.rank)
676
+ .sort((datalayer1, datalayer2) => datalayer1.rank - datalayer2.rank)
685
677
  for (const datalayer of datalayers) {
686
678
  const child = parent.querySelector(`[data-id="${datalayer.id}"]`)
687
679
  parent.appendChild(child)
@@ -773,14 +765,19 @@ export default class Umap {
773
765
  editCaption() {
774
766
  if (!this.editEnabled) return
775
767
  if (this.properties.editMode !== 'advanced') return
776
- const container = DomUtil.create('div')
768
+ const container = DOMUtils.loadTemplate(`
769
+ <div>
770
+ <h3>
771
+ <i class="icon icon-16 icon-info"></i>
772
+ ${translate('Edit map details')}
773
+ </h3>
774
+ </div>
775
+ `)
777
776
  const metadataFields = [
778
777
  'properties.name',
779
778
  'properties.description',
780
779
  'properties.is_template',
781
780
  ]
782
-
783
- DomUtil.createTitle(container, translate('Edit map details'), 'icon-info')
784
781
  const builder = new MutatingForm(this, metadataFields, {
785
782
  className: 'map-metadata',
786
783
  umap: this,
@@ -788,13 +785,13 @@ export default class Umap {
788
785
  const form = builder.build()
789
786
  container.appendChild(form)
790
787
 
791
- const tags = DomUtil.createFieldset(container, translate('Tags'))
788
+ const tags = DOMUtils.createFieldset(container, translate('Tags'))
792
789
  const tagsFields = ['properties.tags']
793
790
  const tagsBuilder = new MutatingForm(this, tagsFields, {
794
791
  umap: this,
795
792
  })
796
793
  tags.appendChild(tagsBuilder.build())
797
- const credits = DomUtil.createFieldset(container, translate('Credits'))
794
+ const credits = DOMUtils.createFieldset(container, translate('Credits'))
798
795
  const creditsFields = [
799
796
  'properties.licence',
800
797
  'properties.shortCredit',
@@ -810,7 +807,11 @@ export default class Umap {
810
807
  editCenter() {
811
808
  if (!this.editEnabled) return
812
809
  if (this.properties.editMode !== 'advanced') return
813
- const container = DomUtil.create('div')
810
+ const container = DOMUtils.loadTemplate(`
811
+ <div>
812
+ <h3><i class="icon icon-16 icon-zoom"></i>${translate('Edit map default view')}</h3>
813
+ </div>
814
+ `)
814
815
  const metadataFields = [
815
816
  ['properties.zoom', { handler: 'IntInput', label: translate('Default zoom') }],
816
817
  [
@@ -824,13 +825,12 @@ export default class Umap {
824
825
  'properties.defaultView',
825
826
  ]
826
827
 
827
- DomUtil.createTitle(container, translate('Edit map default view'), 'icon-zoom')
828
828
  const builder = new MutatingForm(this, metadataFields, {
829
829
  className: 'map-metadata',
830
830
  umap: this,
831
831
  })
832
832
  const form = builder.build()
833
- const button = Utils.loadTemplate(
833
+ const button = DOMUtils.loadTemplate(
834
834
  `<button type="button">${translate('Use current center and zoom')}</button>`
835
835
  )
836
836
  button.addEventListener('click', () => {
@@ -859,7 +859,7 @@ export default class Umap {
859
859
  'properties.layerSwitcher',
860
860
  ])
861
861
  const builder = new MutatingForm(this, UIFields, { umap: this })
862
- const controlsOptions = DomUtil.createFieldset(
862
+ const controlsOptions = DOMUtils.createFieldset(
863
863
  container,
864
864
  translate('User interface options')
865
865
  )
@@ -883,7 +883,7 @@ export default class Umap {
883
883
  ]
884
884
 
885
885
  const builder = new MutatingForm(this, shapeOptions, { umap: this })
886
- const defaultShapeProperties = DomUtil.createFieldset(
886
+ const defaultShapeProperties = DOMUtils.createFieldset(
887
887
  container,
888
888
  translate('Default shape properties')
889
889
  )
@@ -901,7 +901,7 @@ export default class Umap {
901
901
  ]
902
902
 
903
903
  const builder = new MutatingForm(this, shapeOptions, { umap: this })
904
- const defaultShapeProperties = DomUtil.createFieldset(
904
+ const defaultShapeProperties = DOMUtils.createFieldset(
905
905
  container,
906
906
  translate('Default properties')
907
907
  )
@@ -919,7 +919,7 @@ export default class Umap {
919
919
  'properties.outlinkTarget',
920
920
  ]
921
921
  const builder = new MutatingForm(this, popupFields, { umap: this })
922
- const popupFieldset = DomUtil.createFieldset(
922
+ const popupFieldset = DOMUtils.createFieldset(
923
923
  container,
924
924
  translate('Default interaction options')
925
925
  )
@@ -971,7 +971,7 @@ export default class Umap {
971
971
  { handler: 'Switch', label: translate('TMS format') },
972
972
  ],
973
973
  ]
974
- const customTilelayer = DomUtil.createFieldset(
974
+ const customTilelayer = DOMUtils.createFieldset(
975
975
  container,
976
976
  translate('Custom background')
977
977
  )
@@ -1022,7 +1022,7 @@ export default class Umap {
1022
1022
  ],
1023
1023
  ['properties.overlay.tms', { handler: 'Switch', label: translate('TMS format') }],
1024
1024
  ]
1025
- const overlay = DomUtil.createFieldset(container, translate('Custom overlay'))
1025
+ const overlay = DOMUtils.createFieldset(container, translate('Custom overlay'))
1026
1026
  const builder = new MutatingForm(this, overlayFields, { umap: this })
1027
1027
  overlay.appendChild(builder.build())
1028
1028
  }
@@ -1031,7 +1031,7 @@ export default class Umap {
1031
1031
  if (!Utils.isObject(this.properties.limitBounds)) {
1032
1032
  this.properties.limitBounds = {}
1033
1033
  }
1034
- const limitBounds = DomUtil.createFieldset(container, translate('Limit bounds'))
1034
+ const limitBounds = DOMUtils.createFieldset(container, translate('Limit bounds'))
1035
1035
  const boundsFields = [
1036
1036
  [
1037
1037
  'properties.limitBounds.south',
@@ -1052,28 +1052,29 @@ export default class Umap {
1052
1052
  ]
1053
1053
  const boundsBuilder = new MutatingForm(this, boundsFields, { umap: this })
1054
1054
  limitBounds.appendChild(boundsBuilder.build())
1055
- const boundsButtons = DomUtil.create('div', 'button-bar half', limitBounds)
1056
- DomUtil.createButton(
1057
- 'button',
1058
- boundsButtons,
1059
- translate('Use current bounds'),
1060
- () => {
1061
- const bounds = this._leafletMap.getBounds()
1062
- const oldLimitBounds = { ...this.properties.limitBounds }
1063
- this.properties.limitBounds.south = LeafletUtil.formatNum(bounds.getSouth())
1064
- this.properties.limitBounds.west = LeafletUtil.formatNum(bounds.getWest())
1065
- this.properties.limitBounds.north = LeafletUtil.formatNum(bounds.getNorth())
1066
- this.properties.limitBounds.east = LeafletUtil.formatNum(bounds.getEast())
1067
- boundsBuilder.fetchAll()
1068
- this.sync.update(
1069
- 'properties.limitBounds',
1070
- this.properties.limitBounds,
1071
- oldLimitBounds
1072
- )
1073
- this._leafletMap.handleLimitBounds()
1074
- }
1075
- )
1076
- DomUtil.createButton('button', boundsButtons, translate('Empty'), () => {
1055
+ const [boundsButtons, { current, empty }] = DOMUtils.loadTemplateWithRefs(`
1056
+ <div class="button-bar half">
1057
+ <button type="button" data-ref="current">${translate('Use current bounds')}</button>
1058
+ <button type="button" data-ref="empty">${translate('Empty')}</button>
1059
+ </div>
1060
+ `)
1061
+ limitBounds.appendChild(boundsButtons)
1062
+ current.addEventListener('click', () => {
1063
+ const bounds = this._leafletMap.getBounds()
1064
+ const oldLimitBounds = { ...this.properties.limitBounds }
1065
+ this.properties.limitBounds.south = bounds.getSouth().toFixed(6)
1066
+ this.properties.limitBounds.west = bounds.getWest().toFixed(6)
1067
+ this.properties.limitBounds.north = bounds.getNorth().toFixed(6)
1068
+ this.properties.limitBounds.east = bounds.getEast().toFixed(6)
1069
+ boundsBuilder.fetchAll()
1070
+ this.sync.update(
1071
+ 'properties.limitBounds',
1072
+ this.properties.limitBounds,
1073
+ oldLimitBounds
1074
+ )
1075
+ this._leafletMap.handleLimitBounds()
1076
+ })
1077
+ empty.addEventListener('click', () => {
1077
1078
  const oldLimitBounds = { ...this.properties.limitBounds }
1078
1079
  this.properties.limitBounds.south = null
1079
1080
  this.properties.limitBounds.west = null
@@ -1090,7 +1091,7 @@ export default class Umap {
1090
1091
  }
1091
1092
 
1092
1093
  _editSlideshow(container) {
1093
- const slideshow = DomUtil.createFieldset(container, translate('Slideshow'))
1094
+ const slideshow = DOMUtils.createFieldset(container, translate('Slideshow'))
1094
1095
  const slideshowFields = [
1095
1096
  [
1096
1097
  'properties.slideshow.active',
@@ -1123,7 +1124,10 @@ export default class Umap {
1123
1124
  }
1124
1125
 
1125
1126
  _editSync(container) {
1126
- const sync = DomUtil.createFieldset(container, translate('Real-time collaboration'))
1127
+ const sync = DOMUtils.createFieldset(
1128
+ container,
1129
+ translate('Real-time collaboration')
1130
+ )
1127
1131
  const builder = new MutatingForm(this, ['properties.syncEnabled'], {
1128
1132
  umap: this,
1129
1133
  })
@@ -1131,7 +1135,7 @@ export default class Umap {
1131
1135
  }
1132
1136
 
1133
1137
  _advancedActions(container) {
1134
- const advancedActions = DomUtil.createFieldset(
1138
+ const advancedActions = DOMUtils.createFieldset(
1135
1139
  container,
1136
1140
  translate('Advanced actions')
1137
1141
  )
@@ -1155,7 +1159,7 @@ export default class Umap {
1155
1159
  </div>
1156
1160
  `
1157
1161
  const [bar, { del, clear, empty, clone, download }] =
1158
- Utils.loadTemplateWithRefs(tpl)
1162
+ DOMUtils.loadTemplateWithRefs(tpl)
1159
1163
  advancedActions.appendChild(bar)
1160
1164
  if (this.permissions.isOwner()) {
1161
1165
  del.hidden = false
@@ -1172,12 +1176,11 @@ export default class Umap {
1172
1176
  edit() {
1173
1177
  if (!this.editEnabled) return
1174
1178
  if (this.properties.editMode !== 'advanced') return
1175
- const container = DomUtil.create('div')
1176
- DomUtil.createTitle(
1177
- container,
1178
- translate('Map advanced properties'),
1179
- 'icon-settings'
1180
- )
1179
+ const container = DOMUtils.loadTemplate(`
1180
+ <div>
1181
+ <h3><i class="icon icon-16 icon-settings"></i>${translate('Map advanced properties')}</h3>
1182
+ </div>
1183
+ `)
1181
1184
  this._editControls(container)
1182
1185
  this._editShapeProperties(container)
1183
1186
  this._editDefaultKeys(container)
@@ -1609,9 +1612,11 @@ export default class Umap {
1609
1612
  else if (finalIndex > initialIndex) movedLayer.insertBefore(targetLayer)
1610
1613
  else movedLayer.insertAfter(targetLayer)
1611
1614
  this.sync.startBatch()
1612
- this.datalayers.reverse().map((datalayer) => {
1615
+ this.datalayers.reverse().map(async (datalayer) => {
1613
1616
  const rank = datalayer.getDOMOrder()
1614
1617
  if (rank >= minIndex && rank <= maxIndex) {
1618
+ // TODO allow to save only metadata instead of force loading data
1619
+ if (!datalayer.isLoaded()) await datalayer.fetchData()
1615
1620
  const oldRank = datalayer.rank
1616
1621
  datalayer.rank = rank
1617
1622
  datalayer.sync.update('options.rank', rank, oldRank)
@@ -1623,14 +1628,13 @@ export default class Umap {
1623
1628
  }
1624
1629
  const orderable = new Orderable(ul, onReorder)
1625
1630
 
1626
- const bar = DomUtil.create('div', 'button-bar', container)
1627
- DomUtil.createButton(
1628
- 'show-on-edit block add-datalayer button',
1629
- bar,
1630
- translate('Add a layer'),
1631
- this.newDataLayer,
1632
- this
1633
- )
1631
+ const [bar, { button }] = DOMUtils.loadTemplateWithRefs(`
1632
+ <div class="button-bar">
1633
+ <button type="button" class="show-on-edit block add-datalayer" data-ref="button">${translate('Add a layer')}</button>
1634
+ </div>
1635
+ `)
1636
+ button.addEventListener('click', () => this.newDataLayer())
1637
+ container.appendChild(bar)
1634
1638
 
1635
1639
  this.editPanel.open({ content: container, highlight: 'layers' })
1636
1640
  }
@@ -1738,6 +1742,7 @@ export default class Umap {
1738
1742
  const fields = Object.keys(importedData.properties).map(
1739
1743
  (field) => `properties.${field}`
1740
1744
  )
1745
+ this.fields.pull()
1741
1746
  this.filters.load()
1742
1747
  this.render(fields)
1743
1748
  this._leafletMap._setDefaultCenter()
@@ -1790,16 +1795,12 @@ export default class Umap {
1790
1795
  await this.server.post(sendLink, {}, formData)
1791
1796
  }
1792
1797
 
1793
- getLayersBounds() {
1794
- const bounds = new latLngBounds()
1795
- this.datalayers.browsable().map((d) => {
1796
- if (d.isVisible()) bounds.extend(d.layer.getBounds())
1797
- })
1798
- return bounds
1799
- }
1800
-
1801
1798
  fitDataBounds() {
1802
- const bounds = this.getLayersBounds()
1799
+ const layers = this.datalayers
1800
+ .browsable()
1801
+ .filter((d) => d.isVisible())
1802
+ .map((d) => d.layer)
1803
+ const bounds = this._leafletMap.getLayersBounds(layers)
1803
1804
  if (!this.hasData() || !bounds.isValid()) return false
1804
1805
  this._leafletMap.fitBounds(bounds)
1805
1806
  }
@@ -177,15 +177,15 @@ export function toHTML(r, options) {
177
177
  // iframe
178
178
  r = r.replace(
179
179
  /{{{(https?[^|{]*)}}}/g,
180
- '<div><iframe frameborder="0" src="$1" width="100%" height="300px"></iframe></div>'
180
+ '<div><iframe allowfullscreen src="$1" style="width: 100%; height: 300px; border: 0;"></iframe></div>'
181
181
  )
182
182
  r = r.replace(
183
183
  /{{{(https?[^|{]*)\|(\d*)(px)?}}}/g,
184
- '<div><iframe frameborder="0" src="$1" width="100%" height="$2px"></iframe></div>'
184
+ '<div><iframe allowfullscreen src="$1" style="width: 100%; height: $2px; border: 0;"></iframe></div>'
185
185
  )
186
186
  r = r.replace(
187
187
  /{{{(https?[^|{]*)\|(\d*)(px)?\*(\d*)(px)?}}}/g,
188
- '<div><iframe frameborder="0" src="$1" width="$4px" height="$2px"></iframe></div>'
188
+ '<div><iframe allowfullscreen src="$1" style="width: $4px; height: $2px; border: 0;"></iframe></div>'
189
189
  )
190
190
 
191
191
  // images
@@ -681,3 +681,13 @@ export const COLORS = [
681
681
  'Ivory',
682
682
  'White',
683
683
  ]
684
+
685
+ export const LatLngIsValid = (latlng) => {
686
+ const [lat, lng] = Array.isArray(latlng) ? latlng : [latlng.lat, latlng.lng]
687
+ return (
688
+ Number.isFinite(lat) &&
689
+ Math.abs(lat) <= 90 &&
690
+ Number.isFinite(lng) &&
691
+ Math.abs(lng) <= 180
692
+ )
693
+ }
@@ -45,171 +45,17 @@ U.TileLayerControl = L.Control.IconLayers.extend({
45
45
  const lastRow = this._container.querySelector(
46
46
  '.leaflet-iconLayers-layersRow:last-child'
47
47
  )
48
- const button = L.DomUtil.element({
49
- tagName: 'button',
50
- className:
51
- 'leaflet-iconLayers-layerCell leaflet-iconLayers-layerCell-plus button',
52
- textContent: '+',
53
- parent: lastRow,
54
- })
55
- L.DomEvent.on(button, 'click', () =>
48
+ const button = document.createElement('button')
49
+ button.className =
50
+ 'leaflet-iconLayers-layerCell leaflet-iconLayers-layerCell-plus button'
51
+ button.textContent = '+'
52
+ lastRow.appendChild(button)
53
+ button.addEventListener('click', () =>
56
54
  this.map._controls.tilelayersChooser.openSwitcher()
57
55
  )
58
56
  },
59
57
  })
60
58
 
61
- /*
62
- * Take control over L.Control.Locate to be able to
63
- * call start() before adding the control (and thus the button) to the map.
64
- */
65
- U.Locate = L.Control.Locate.extend({
66
- initialize: function (map, options) {
67
- // When calling start(), it will try to add a location marker
68
- // on the layer, which is normally added in the addTo/onAdd method
69
- this._layer = this.options.layer = new L.LayerGroup()
70
- // When calling start(), it will call _activate(), which then adds
71
- // location related event listeners on the map
72
- this.map = map
73
- L.Control.Locate.prototype.initialize.call(this, options)
74
- },
75
-
76
- onAdd: function (map) {
77
- const active = this._active
78
- const container = L.Control.Locate.prototype.onAdd.call(this, map)
79
- this._active = active
80
- return container
81
- },
82
-
83
- _activate: function () {
84
- this._map = this.map
85
- L.Control.Locate.prototype._activate.call(this)
86
- },
87
-
88
- remove: function () {
89
- // Prevent to call remove if the control is not really added to the map
90
- // This occurs because we do create the control and call its activate
91
- // method before adding the control button itself to the map, in the
92
- // case where the map defaultView is set to "location"
93
- if (!this._container || !this._container.parentNode) return
94
- return L.Control.Locate.prototype.remove.call(this)
95
- },
96
- })
97
-
98
- U.Search = L.PhotonSearch.extend({
99
- initialize: function (map, input, layer, options) {
100
- this.options.placeholder = L._('Type a place name or coordinates')
101
- this.options.location_bias_scale = 0.5
102
- L.PhotonSearch.prototype.initialize.call(this, map, input, options)
103
- this.options.url = map.options.urls.search
104
- if (map.options.maxBounds) this.options.bbox = map.options.maxBounds.toBBoxString()
105
- this.reverse = new L.PhotonReverse({
106
- handleResults: (geojson) => {
107
- this.handleResultsWithReverse(geojson)
108
- },
109
- })
110
- this.layer = layer
111
- },
112
-
113
- handleResultsWithReverse: function (geojson) {
114
- const latlng = this.reverse.latlng
115
- geojson.features.unshift({
116
- type: 'Feature',
117
- geometry: { type: 'Point', coordinates: [latlng.lng, latlng.lat] },
118
- properties: {
119
- name: L._('Go to "{coords}"', { coords: `${latlng.lat} ${latlng.lng}` }),
120
- },
121
- })
122
-
123
- this.handleResults(geojson)
124
- },
125
-
126
- search: function () {
127
- this.layer.clearLayers()
128
- const pattern = /^(?<lat>[-+]?\d{1,2}[.,]\d+)\s*[ ,]\s*(?<lng>[-+]?\d{1,3}[.,]\d+)$/
129
- if (pattern.test(this.input.value)) {
130
- this.hide()
131
- const { lat, lng } = pattern.exec(this.input.value).groups
132
- const latlng = L.latLng(lat, lng)
133
- if (latlng.isValid()) {
134
- this.reverse.doReverse(latlng)
135
- } else {
136
- U.Alert.error(L._('Invalid latitude or longitude'))
137
- }
138
- return
139
- }
140
- // Only numbers, abort.
141
- if (/^[\d .,]*$/.test(this.input.value)) return
142
- // Do normal search
143
- this.options.includePosition = this.map.getZoom() > 10
144
- L.PhotonSearch.prototype.search.call(this)
145
- },
146
-
147
- onBlur: function (e) {
148
- // Overrided because we don't want to hide the results on blur.
149
- this.fire('blur')
150
- },
151
-
152
- formatResult: function (feature, el) {
153
- const [tools, { point, geom }] = U.Utils.loadTemplateWithRefs(`
154
- <span class="search-result-tools">
155
- <button type="button" title="${L._('Add this geometry to my map')}" data-ref=geom><i class="icon icon-16 icon-polygon-plus"></i></button>
156
- <button type="button" title="${L._('Add this place to my map')}" data-ref=point><i class="icon icon-16 icon-marker-plus"></i></button>
157
- </span>
158
- `)
159
- geom.hidden = !['R', 'W'].includes(feature.properties.osm_type)
160
- point.addEventListener('mousedown', (event) => {
161
- event.stopPropagation()
162
- const datalayer = this.map._umap.defaultEditDataLayer()
163
- const marker = datalayer.makeFeature(feature)
164
- marker.edit()
165
- })
166
- geom.addEventListener('mousedown', async (event) => {
167
- event.stopPropagation()
168
- const osm_id = feature.properties.osm_id
169
- const types = {
170
- R: 'relation',
171
- W: 'way',
172
- N: 'node',
173
- }
174
- const osm_type = types[feature.properties.osm_type]
175
- if (!osm_type || !osm_id) return
176
- const importer = this.map._umap.importer
177
- importer.build()
178
- importer.format = 'osm'
179
- importer.url = `https://www.openstreetmap.org/api/0.6/${osm_type}/${osm_id}/full`
180
- importer.submit()
181
- })
182
- el.appendChild(tools)
183
- this._formatResult(feature, el)
184
- const path = this.map._umap.getStaticPathFor('target.svg')
185
- const icon = L.icon({
186
- iconUrl: path,
187
- iconSize: [24, 24],
188
- iconAnchor: [12, 12],
189
- })
190
- const coords = feature.geometry.coordinates
191
- const target = L.marker([coords[1], coords[0]], { icon })
192
- el.addEventListener('mouseover', (event) => {
193
- target.addTo(this.layer)
194
- })
195
- el.addEventListener('mouseout', (event) => {
196
- target.removeFrom(this.layer)
197
- })
198
- },
199
-
200
- setChoice: function (choice) {
201
- choice = choice || this.RESULTS[this.CURRENT]
202
- if (choice) {
203
- const feature = choice.feature
204
- const zoom = Math.max(this.map.getZoom(), 14) // Never unzoom.
205
- this.map.setView(
206
- [feature.geometry.coordinates[1], feature.geometry.coordinates[0]],
207
- zoom
208
- )
209
- }
210
- },
211
- })
212
-
213
59
  L.Control.MiniMap.include({
214
60
  initialize: function (layer, options) {
215
61
  L.Util.setOptions(this, options)
@@ -228,23 +74,6 @@ L.Control.MiniMap.include({
228
74
  _cloneLayer: (layer) => new L.TileLayer(layer._url, L.Util.extend({}, layer.options)),
229
75
  })
230
76
 
231
- L.Control.Loading.include({
232
- onAdd: function (map) {
233
- this._container = L.DomUtil.create('div', 'umap-loader', map._controlContainer)
234
- map.on('baselayerchange', this._layerAdd, this)
235
- this._addMapListeners(map)
236
- this._map = map
237
- },
238
-
239
- _showIndicator: function () {
240
- this._map._container.classList.add('umap-loading')
241
- },
242
-
243
- _hideIndicator: function () {
244
- this._map._container.classList.remove('umap-loading')
245
- },
246
- })
247
-
248
77
  U.Editable = L.Editable.extend({
249
78
  initialize: function (umap, options) {
250
79
  this._umap = umap
@@ -252,9 +81,10 @@ U.Editable = L.Editable.extend({
252
81
  this.on('editable:drawing:click editable:drawing:move', this.drawingTooltip)
253
82
  // Layer for items added by users
254
83
  this.on('editable:drawing:cancel', (event) => {
255
- if (event.layer instanceof U.LeafletMarker) event.layer.feature.del()
84
+ this.resetButtons()
256
85
  })
257
86
  this.on('editable:drawing:commit', function (event) {
87
+ this.resetButtons()
258
88
  if (this._umap.editedFeature !== event.layer) {
259
89
  const promise = event.layer.feature.edit(event)
260
90
  if (event.layer.feature.isRoute?.()) {
@@ -278,6 +108,13 @@ U.Editable = L.Editable.extend({
278
108
  this.on('editable:vertex:rawclick', this.onVertexRawClick)
279
109
  },
280
110
 
111
+ resetButtons: () => {
112
+ const buttons = document.querySelectorAll('.umap-edit-bar .drawing-tool')
113
+ for (const button of buttons) {
114
+ button.classList.remove('on')
115
+ }
116
+ },
117
+
281
118
  startRoute: function (latlng) {
282
119
  const feature = this.createLineString()
283
120
  feature.askForRouteSettings().then(async () => {
@@ -402,7 +239,7 @@ U.Editable = L.Editable.extend({
402
239
  // (eg. line has only one drawn point)
403
240
  // So let's check if the layer has no more shape
404
241
  event.layer.feature.pullGeometry(false)
405
- if (!event.layer.feature.hasGeom()) {
242
+ if (!event.layer.feature.hasGeom() || event.layer instanceof U.LeafletMarker) {
406
243
  event.layer.feature.del()
407
244
  } else {
408
245
  event.layer.feature.onCommit()