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,5 +1,5 @@
1
- import { DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
2
1
  import { translate } from '../i18n.js'
2
+ import * as DOMUtils from '../domutils.js'
3
3
 
4
4
  export class Importer {
5
5
  constructor(map, options) {
@@ -9,20 +9,20 @@ export class Importer {
9
9
  }
10
10
 
11
11
  async open(importer) {
12
- const container = DomUtil.create('div', 'formbox')
13
- DomUtil.element({ tagName: 'h3', textContent: this.name, parent: container })
14
- const select = DomUtil.create('select', '', container)
15
- const noPreset = DomUtil.element({
16
- tagName: 'option',
17
- parent: select,
18
- value: '',
19
- textContent: translate('Choose a dataset'),
20
- })
12
+ const [container, { select }] = DOMUtils.loadTemplateWithRefs(`
13
+ <div class="formbox">
14
+ <h3>${this.name}</h3>
15
+ <select data-ref="select">
16
+ <option value="">${translate('Choose a dataset')}</option>
17
+ </select>
18
+ </div>
19
+ `)
20
+
21
21
  for (const dataset of this.choices) {
22
- const option = DomUtil.create('option', '', select)
23
- option.value = dataset.url
24
- option.textContent = dataset.label
25
- option.dataset.format = dataset.format || 'geojson'
22
+ const option = DOMUtils.loadTemplate(
23
+ `<option value="${dataset.url}" data-format="${dataset.format || 'geojson'}">${dataset.label}</option>`
24
+ )
25
+ select.appendChild(option)
26
26
  }
27
27
  const confirm = () => {
28
28
  if (select.value) {
@@ -1,8 +1,8 @@
1
- import { DomEvent, DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
2
1
  import { uMapAlert as Alert } from '../../components/alerts/alert.js'
3
2
  import { BaseAjax, SingleMixin } from '../autocomplete.js'
4
3
  import { translate } from '../i18n.js'
5
4
  import * as Utils from '../utils.js'
5
+ import * as DOMUtils from '../domutils.js'
6
6
 
7
7
  const BOUNDARY_TYPES = {
8
8
  admin_6: 'département',
@@ -14,18 +14,20 @@ const BOUNDARY_TYPES = {
14
14
  }
15
15
 
16
16
  const TEMPLATE = `
17
- <h3>GeoDataMine</h3>
18
- <p>${translate('GeoDataMine: thematic data from OpenStreetMap')}.</p>
19
- <div class="formbox">
20
- <select name="theme">
21
- <option value="">${translate('Choose a theme')}</option>
22
- </select>
23
- <label>
24
- <input type="checkbox" name="aspoint" />
25
- ${translate('Simplify all geometries to points')}
26
- </label>
27
- <label id="boundary">
28
- </label>
17
+ <div>
18
+ <h3>GeoDataMine</h3>
19
+ <p>${translate('GeoDataMine: thematic data from OpenStreetMap')}.</p>
20
+ <div class="formbox">
21
+ <select name="theme" data-ref="select">
22
+ <option value="">${translate('Choose a theme')}</option>
23
+ </select>
24
+ <label>
25
+ <input type="checkbox" name="aspoint" />
26
+ ${translate('Simplify all geometries to points')}
27
+ </label>
28
+ <label id="boundary">
29
+ </label>
30
+ </div>
29
31
  </div>
30
32
  `
31
33
 
@@ -49,20 +51,16 @@ export class Importer {
49
51
  async open(importer) {
50
52
  let boundary = null
51
53
  let boundaryName = null
52
- const container = DomUtil.create('div')
53
- container.innerHTML = TEMPLATE
54
+ const [container, { select }] = DOMUtils.loadTemplateWithRefs(TEMPLATE)
54
55
  const response = await this.umap.request.get(`${this.baseUrl}/themes`)
55
- const select = container.querySelector('select')
56
56
  if (response?.ok) {
57
57
  const { themes } = await response.json()
58
58
  themes.sort((a, b) => Utils.naturalSort(a['name:fr'], b['name:fr']))
59
59
  for (const theme of themes) {
60
- DomUtil.element({
61
- tagName: 'option',
62
- value: theme.id,
63
- textContent: theme['name:fr'],
64
- parent: select,
65
- })
60
+ const option = DOMUtils.loadTemplate(
61
+ `<option value="${theme.id}">${theme['name:fr']}</option>`
62
+ )
63
+ select.appendChild(option)
66
64
  }
67
65
  } else {
68
66
  console.error(response)
@@ -63,6 +63,16 @@ const PORTALS = [
63
63
  url: 'https://admin.geospm.com',
64
64
  platform: 'prodige',
65
65
  },
66
+ {
67
+ name: 'SNCF',
68
+ url: 'https://ressources.data.sncf.com',
69
+ platform: 'opendatasoft',
70
+ },
71
+ {
72
+ name: 'Réseau STAR Rennes',
73
+ url: 'https://data.explore.star.fr',
74
+ platform: 'opendatasoft',
75
+ },
66
76
  {
67
77
  name: 'Toulouse Métropole',
68
78
  url: 'https://data.toulouse-metropole.fr',
@@ -1,22 +1,24 @@
1
- import { DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
2
1
  import { uMapAlert as Alert } from '../../components/alerts/alert.js'
3
2
  import { BaseAjax, SingleMixin } from '../autocomplete.js'
4
3
  import { translate } from '../i18n.js'
4
+ import * as DOMUtils from '../domutils.js'
5
5
 
6
6
  const TEMPLATE = `
7
- <h3>Overpass</h3>
8
- <label>
9
- <span data-help="overpassImporter">${translate('Expression')}</span>
10
- <input type="text" placeholder="amenity=drinking_water" name="tags" />
11
- </label>
12
- <label>
13
- ${translate('Geometry mode')}
14
- <select name="out">
15
- <option value="geom" selected>${translate('Default')}</option>
16
- <option value="center">${translate('Only geometry centers')}</option>
17
- </select>
18
- </label>
19
- <label id="area"><span>${translate('Search area')}</span></label>
7
+ <div>
8
+ <h3>Overpass</h3>
9
+ <label>
10
+ <span data-help="overpassImporter">${translate('Expression')}</span>
11
+ <input type="text" placeholder="amenity=drinking_water" name="tags" data-ref="tags" />
12
+ </label>
13
+ <label>
14
+ ${translate('Geometry mode')}
15
+ <select name="out">
16
+ <option value="geom" selected>${translate('Default')}</option>
17
+ <option value="center">${translate('Only geometry centers')}</option>
18
+ </select>
19
+ </label>
20
+ <label data-ref="area" id="area"><span>${translate('Search area')}</span></label>
21
+ </div>
20
22
  `
21
23
 
22
24
  class Autocomplete extends SingleMixin(BaseAjax) {
@@ -57,12 +59,11 @@ export class Importer {
57
59
  }
58
60
 
59
61
  async open(importer) {
60
- const container = DomUtil.create('div')
61
- container.innerHTML = TEMPLATE
62
+ const [container, { area, tags }] = DOMUtils.loadTemplateWithRefs(TEMPLATE)
62
63
  if (this.expression) {
63
- container.querySelector('[name=tags]').value = this.expression
64
+ tags.value = this.expression
64
65
  }
65
- this.autocomplete = new Autocomplete(container.querySelector('#area'), {
66
+ this.autocomplete = new Autocomplete(area, {
66
67
  url: this.searchUrl,
67
68
  placeholder: translate(
68
69
  'Type area name, or let empty to load data in current map view'
@@ -7,7 +7,7 @@ export class DataLayerManager extends Object {
7
7
  active() {
8
8
  return Object.values(this)
9
9
  .filter((datalayer) => !datalayer.isDeleted)
10
- .sort((a, b) => a.rank > b.rank)
10
+ .sort((a, b) => a.rank - b.rank)
11
11
  }
12
12
  reverse() {
13
13
  return this.active().reverse()
@@ -1,4 +1,3 @@
1
- import { DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
2
1
  import { uMapAlert as Alert } from '../components/alerts/alert.js'
3
2
  import { MutatingForm } from './form/builder.js'
4
3
  import { translate } from './i18n.js'
@@ -127,7 +126,11 @@ export class MapPermissions {
127
126
  ])
128
127
  collaboratorsFields.push([
129
128
  'properties.owner',
130
- { handler: 'ManageOwner', label: translate("Map's owner") },
129
+ {
130
+ handler: 'ManageOwner',
131
+ label: translate("Map's owner"),
132
+ url: this._umap.properties.urls.agnocomplete,
133
+ },
131
134
  ])
132
135
  if (this._umap.properties.user?.teams?.length) {
133
136
  collaboratorsFields.push([
@@ -142,7 +145,11 @@ export class MapPermissions {
142
145
  }
143
146
  collaboratorsFields.push([
144
147
  'properties.editors',
145
- { handler: 'ManageEditors', label: translate("Map's editors") },
148
+ {
149
+ handler: 'ManageEditors',
150
+ label: translate("Map's editors"),
151
+ url: this._umap.properties.urls.agnocomplete,
152
+ },
146
153
  ])
147
154
 
148
155
  const builder = new MutatingForm(this, topFields)
@@ -177,8 +184,11 @@ export class MapPermissions {
177
184
  Alert.info(translate('Please save the map first'))
178
185
  return
179
186
  }
180
- const container = DomUtil.create('div', 'umap-edit-permissions')
181
- DomUtil.createTitle(container, translate('Update permissions'), 'icon-key')
187
+ const container = DOMUtils.loadTemplate(`
188
+ <div class="umap-edit-permissions">
189
+ <h3><i class="icon icon-16 icon-key"></i> ${translate('Update permissions')}</h3>
190
+ </div>
191
+ `)
182
192
  if (this.isAnonymousMap()) this._editAnonymous(container)
183
193
  else this._editWithOwner(container)
184
194
  this._editDatalayers(container)
@@ -1,6 +1,17 @@
1
- import { Control } from '../../../vendors/leaflet/leaflet-src.esm.js'
1
+ import {
2
+ Control,
3
+ LayerGroup,
4
+ latLng,
5
+ Icon,
6
+ Marker,
7
+ } from '../../../vendors/leaflet/leaflet-src.esm.js'
8
+ import {
9
+ PhotonSearch,
10
+ PhotonReverse,
11
+ } from '../../../vendors/photon/leaflet.photon.esm.js'
2
12
  import * as Utils from '../utils.js'
3
13
  import { translate } from '../i18n.js'
14
+ import { uMapAlert as Alert } from '../../components/alerts/alert.js'
4
15
 
5
16
  export const HomeControl = Control.extend({
6
17
  options: {
@@ -9,8 +20,9 @@ export const HomeControl = Control.extend({
9
20
 
10
21
  onAdd: (map) => {
11
22
  const path = map._umap.getStaticPathFor('home.svg')
23
+ const homeURL = map._umap.urls.get('home')
12
24
  const container = Utils.loadTemplate(
13
- `<a href="/" class="home-button" title="${translate('Back to home')}"><img src="${path}" alt="${translate('Home logo')}" width="38px" height="38px" /></a>`
25
+ `<a href="${homeURL}" class="home-button" title="${translate('Back to home')}"><img src="${path}" alt="${translate('Home logo')}" width="38px" height="38px" /></a>`
14
26
  )
15
27
  return container
16
28
  },
@@ -124,6 +136,7 @@ const BaseButton = Control.extend({
124
136
  initialize: function (umap, options) {
125
137
  this._umap = umap
126
138
  Control.prototype.initialize.call(this, options)
139
+ this.afterInit()
127
140
  },
128
141
 
129
142
  onAdd: function (map) {
@@ -153,6 +166,7 @@ const BaseButton = Control.extend({
153
166
  this.afterRemove(map)
154
167
  },
155
168
 
169
+ afterInit: () => {},
156
170
  afterAdd: (container, map) => {},
157
171
  afterRemove: (map) => {},
158
172
  })
@@ -221,7 +235,7 @@ export const SearchControl = BaseButton.extend({
221
235
  },
222
236
 
223
237
  afterAdd(container, map) {
224
- this.layer = L.layerGroup().addTo(map)
238
+ this.layer = new LayerGroup().addTo(map)
225
239
  this.photonOptions = {
226
240
  limit: 10,
227
241
  noResultLabel: translate('No results'),
@@ -244,7 +258,7 @@ export const SearchControl = BaseButton.extend({
244
258
  const [container, { input, resultsContainer }] =
245
259
  Utils.loadTemplateWithRefs(template)
246
260
  const id = Math.random()
247
- this.search = new U.Search(
261
+ this.search = new Search(
248
262
  this._umap._leafletMap,
249
263
  input,
250
264
  this.layer,
@@ -252,10 +266,10 @@ export const SearchControl = BaseButton.extend({
252
266
  )
253
267
  this._umap.panel.open({ content: container }).then(() => {
254
268
  this.search.on('ajax:send', () => {
255
- this._umap.fire('dataloading', { id: id })
269
+ this._umap.loader.start(id)
256
270
  })
257
271
  this.search.on('ajax:return', () => {
258
- this._umap.fire('dataload', { id: id })
272
+ this._umap.loader.stop(id)
259
273
  })
260
274
  this.search.resultsContainer = resultsContainer
261
275
  input.focus()
@@ -282,19 +296,16 @@ export const AttributionControl = Control.Attribution.extend({
282
296
  ${originalCredits}
283
297
  <span data-ref="short"> — ${Utils.toHTML(shortCredit)}</span>
284
298
  <a href="#" data-ref="caption"> — ${translate('Open caption')}</a>
285
- <a href="/" data-ref="home"> — ${translate('Home')}</a>
286
299
  <a href="https://umap-project.org/" data-ref="site"> — ${translate('Powered by uMap')}</a>
287
300
  <a href="#" class="attribution-toggle"></a>
288
301
  </div>
289
302
  `
290
- const [container, { short, caption, home, site }] =
291
- Utils.loadTemplateWithRefs(template)
303
+ const [container, { short, caption, site }] = Utils.loadTemplateWithRefs(template)
292
304
  caption.addEventListener('click', () => this._map._umap.openCaption())
293
305
  this._container.appendChild(container)
294
306
  short.hidden = !shortCredit
295
307
  caption.hidden = !captionMenus
296
308
  site.hidden = !captionMenus
297
- home.hidden = this._map._umap.isEmbed || !captionMenus
298
309
  },
299
310
  })
300
311
 
@@ -359,3 +370,185 @@ export const TileLayerChooser = BaseButton.extend({
359
370
  return li
360
371
  },
361
372
  })
373
+
374
+ export const LocateControl = BaseButton.extend({
375
+ options: {
376
+ position: 'topleft',
377
+ title: translate('Center map on your location'),
378
+ icon: 'icon-locate',
379
+ },
380
+
381
+ async start() {
382
+ await this.loadPlugin()
383
+ this._locate.start()
384
+ },
385
+
386
+ stop() {
387
+ this._locate?.stop()
388
+ },
389
+
390
+ async loadPlugin() {
391
+ if (this._locate) return
392
+ const { LocateControl } = await import(
393
+ '../../../vendors/locatecontrol/L.Control.Locate.esm.js'
394
+ )
395
+ this._locate = new LocateControl({
396
+ strings: {
397
+ title: translate('Center map on your location'),
398
+ },
399
+ showPopup: false,
400
+ flyTo: this.options.easing,
401
+ onLocationError: (err) => Alert.error(err.message),
402
+ })
403
+ this._locate._map = this._umap._leafletMap
404
+ this._locate.onAdd(this._umap._leafletMap)
405
+ },
406
+
407
+ async onClick() {
408
+ if (this._locate?._active) {
409
+ this.stop()
410
+ } else {
411
+ this.start()
412
+ }
413
+ },
414
+
415
+ afterRemove() {
416
+ this.stop()
417
+ },
418
+
419
+ afterInit() {
420
+ this._umap._leafletMap.on('locateactivate', () => {
421
+ this._container.classList.add('active')
422
+ })
423
+ this._umap._leafletMap.on('locatedeactivate', () => {
424
+ this._container.classList.remove('active')
425
+ })
426
+ },
427
+ })
428
+
429
+ export const Search = PhotonSearch.extend({
430
+ initialize: function (map, input, layer, options) {
431
+ this.options.placeholder = translate('Type a place name or coordinates')
432
+ this.options.location_bias_scale = 0.5
433
+ PhotonSearch.prototype.initialize.call(this, map, input, options)
434
+ this.options.url = map.options.urls.search
435
+ if (map.options.maxBounds) this.options.bbox = map.options.maxBounds.toBBoxString()
436
+ this.reverse = new PhotonReverse({
437
+ handleResults: (geojson) => {
438
+ this.handleResultsWithReverse(geojson)
439
+ },
440
+ })
441
+ this.layer = layer
442
+ },
443
+
444
+ handleResultsWithReverse: function (geojson) {
445
+ const latlng = this.reverse.latlng
446
+ geojson.features.unshift({
447
+ type: 'Feature',
448
+ geometry: { type: 'Point', coordinates: [latlng.lng, latlng.lat] },
449
+ properties: {
450
+ name: translate('Go to "{coords}"', { coords: `${latlng.lat} ${latlng.lng}` }),
451
+ },
452
+ })
453
+
454
+ this.handleResults(geojson)
455
+ },
456
+
457
+ search: function () {
458
+ this.layer.clearLayers()
459
+ const pattern = /^(?<lat>[-+]?\d{1,2}[.,]\d+)\s*[ ,]\s*(?<lng>[-+]?\d{1,3}[.,]\d+)$/
460
+ if (pattern.test(this.input.value)) {
461
+ this.hide()
462
+ const { lat, lng } = pattern.exec(this.input.value).groups
463
+ const latlng = latLng(lat, lng)
464
+ if (Utils.LatLngIsValid(latlng)) {
465
+ this.reverse.doReverse(latlng)
466
+ } else {
467
+ Alert.error(translate('Invalid latitude or longitude'))
468
+ }
469
+ return
470
+ }
471
+ // Only numbers, abort.
472
+ if (/^[\d .,]*$/.test(this.input.value)) return
473
+ // Do normal search
474
+ this.options.includePosition = this.map.getZoom() > 10
475
+ PhotonSearch.prototype.search.call(this)
476
+ },
477
+
478
+ onBlur: function (e) {
479
+ // Overrided because we don't want to hide the results on blur.
480
+ this.fire('blur')
481
+ },
482
+
483
+ formatResult: function (feature, el) {
484
+ const [tools, { point, geom }] = Utils.loadTemplateWithRefs(`
485
+ <span class="search-result-tools">
486
+ <button type="button" title="${translate('Add this geometry to my map')}" data-ref=geom><i class="icon icon-16 icon-polygon-plus"></i></button>
487
+ <button type="button" title="${translate('Add this place to my map')}" data-ref=point><i class="icon icon-16 icon-marker-plus"></i></button>
488
+ </span>
489
+ `)
490
+ geom.hidden = !['R', 'W'].includes(feature.properties.osm_type)
491
+ point.addEventListener('mousedown', (event) => {
492
+ event.stopPropagation()
493
+ const datalayer = this.map._umap.defaultEditDataLayer()
494
+ const marker = datalayer.makeFeature(feature)
495
+ marker.edit()
496
+ })
497
+ geom.addEventListener('mousedown', async (event) => {
498
+ event.stopPropagation()
499
+ const osm_id = feature.properties.osm_id
500
+ const types = {
501
+ R: 'relation',
502
+ W: 'way',
503
+ N: 'node',
504
+ }
505
+ const osm_type = types[feature.properties.osm_type]
506
+ if (!osm_type || !osm_id) return
507
+ const importer = this.map._umap.importer
508
+ importer.build()
509
+ importer.format = 'geojson'
510
+ importer.raw = await this.getOSMObject(osm_type, osm_id)
511
+ importer.submit()
512
+ })
513
+ el.appendChild(tools)
514
+ this._formatResult(feature, el)
515
+ const path = this.map._umap.getStaticPathFor('target.svg')
516
+ const icon = new Icon({
517
+ iconUrl: path,
518
+ iconSize: [24, 24],
519
+ iconAnchor: [12, 12],
520
+ })
521
+ const coords = feature.geometry.coordinates
522
+ const target = new Marker([coords[1], coords[0]], { icon })
523
+ el.addEventListener('mouseover', (event) => {
524
+ target.addTo(this.layer)
525
+ })
526
+ el.addEventListener('mouseout', (event) => {
527
+ target.removeFrom(this.layer)
528
+ })
529
+ },
530
+
531
+ async getOSMObject(osm_type, osm_id) {
532
+ const url = `https://www.openstreetmap.org/api/0.6/${osm_type}/${osm_id}/full`
533
+ const response = await this.map._umap.request.get(url)
534
+ if (response?.ok) {
535
+ const data = await this.map._umap.formatter.fromOSM(await response.text())
536
+ data.features = data.features.filter(
537
+ (feature) => feature.properties.id === `${osm_type}/${osm_id}`
538
+ )
539
+ return JSON.stringify(data)
540
+ }
541
+ },
542
+
543
+ setChoice: function (choice) {
544
+ choice = choice || this.RESULTS[this.CURRENT]
545
+ if (choice) {
546
+ const feature = choice.feature
547
+ const zoom = Math.max(this.map.getZoom(), 14) // Never unzoom.
548
+ this.map.setView(
549
+ [feature.geometry.coordinates[1], feature.geometry.coordinates[0]],
550
+ zoom
551
+ )
552
+ }
553
+ },
554
+ })
@@ -237,14 +237,7 @@ const Ball = DefaultIcon.extend({
237
237
  _setIconStyles: function (img, name) {
238
238
  BaseIcon.prototype._setIconStyles.call(this, img, name)
239
239
  const color = this._getColor('color')
240
- let background
241
- if (L.Browser.ielt9) {
242
- background = color
243
- } else if (L.Browser.webkit) {
244
- background = `-webkit-gradient( radial, 6 38%, 0, 6 38%, 8, from(white), to(${color}) )`
245
- } else {
246
- background = `radial-gradient(circle at 6px 38% , white -4px, ${color} 8px) repeat scroll 0 0 transparent`
247
- }
240
+ const background = `radial-gradient(circle at 6px 38% , white -4px, ${color} 8px) repeat scroll 0 0 transparent`
248
241
  this.elements.ball.style.background = background
249
242
  this.elements.ball.style.opacity = this._getOpacity()
250
243
  },
@@ -309,5 +302,8 @@ export function setContrast(icon, parent, src, bgcolor) {
309
302
  }
310
303
 
311
304
  export function formatUrl(url, feature) {
312
- return Utils.greedyTemplate(url || '', feature ? feature.extendedProperties() : {})
305
+ if (Utils.hasVar(url)) {
306
+ return Utils.greedyTemplate(url || '', feature ? feature.extendedProperties() : {})
307
+ }
308
+ return url
313
309
  }
@@ -53,7 +53,7 @@ export const LayerMixin = {
53
53
  },
54
54
 
55
55
  onZoomEnd() {
56
- if (!this.datalayer.autoLoaded) return
56
+ if (!this.datalayer.autoVisibility) return
57
57
  if (!this.datalayer.showAtZoom() && this.datalayer.isVisible()) {
58
58
  this.datalayer.hide()
59
59
  }
@@ -1,5 +1,5 @@
1
1
  import colorbrewer from '../../../../vendors/colorbrewer/colorbrewer.js'
2
- import { DomUtil, FeatureGroup } from '../../../../vendors/leaflet/leaflet-src.esm.js'
2
+ import { FeatureGroup } from '../../../../vendors/leaflet/leaflet-src.esm.js'
3
3
  import { translate } from '../../i18n.js'
4
4
  import * as Utils from '../../utils.js'
5
5
  import * as DOMUtils from '../../domutils.js'
@@ -80,7 +80,7 @@ const ClassifiedMixin = {
80
80
  const ul = Utils.loadTemplate('<ul></ul>')
81
81
  const items = this.getLegendItems()
82
82
  for (const [color, label] of items) {
83
- const rgbColor = DOMUtils.hexToRGB(color)
83
+ const rgbColor = DOMUtils.colorToRGB(color)
84
84
  const opacity = this.datalayer.getOption('fillOpacity')
85
85
  const bgColor = `rgba(${rgbColor.join(',')}, ${opacity})`
86
86
  const li = Utils.loadTemplate(`
@@ -346,7 +346,8 @@ export const Circles = FeatureGroup.extend({
346
346
  },
347
347
 
348
348
  renderLegend: function (container) {
349
- const parent = DomUtil.create('ul', 'circles-layer-legend', container)
349
+ const parent = DOMUtils.loadTemplate('<ul class="circles-layer-legend"></ul>')
350
+ container.appendChild(parent)
350
351
  const color = this.datalayer.getProperty('color')
351
352
  const values = this.getValues()
352
353
  if (!values.length) return
@@ -360,14 +361,18 @@ export const Circles = FeatureGroup.extend({
360
361
  [this.options.maxPX, maxValue],
361
362
  ]
362
363
  for (const [size, label] of items) {
363
- const li = DomUtil.create('li', '', parent)
364
- const circleEl = DomUtil.create('span', 'circle', li)
365
- circleEl.style.backgroundColor = color
366
- circleEl.style.height = `${size * 2}px`
367
- circleEl.style.width = `${size * 2}px`
368
- circleEl.style.opacity = this.datalayer.getProperty('opacity')
369
- const labelEl = DomUtil.create('span', 'label', li)
370
- labelEl.textContent = label
364
+ parent.appendChild(
365
+ DOMUtils.loadTemplate(`
366
+ <li>
367
+ <span class="circle"
368
+ style="background-color: ${color};
369
+ height: ${size * 2}px;
370
+ width: ${size * 2}px;
371
+ opacity: ${this.datalayer.getProperty('fillOpacity')};"></span>
372
+ <span class="label">${label}</span>
373
+ </li>
374
+ `)
375
+ )
371
376
  }
372
377
  },
373
378
  })
@@ -102,6 +102,7 @@ export const Heat = L.HeatLayer.extend({
102
102
  }
103
103
  if (field === 'properties.heat.radius') {
104
104
  this.options.radius = this.datalayer.properties.heat.radius
105
+ this.redraw()
105
106
  }
106
107
  this._updateOptions()
107
108
  },