umap-project 2.7.2__py3-none-any.whl → 2.8.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 (293) hide show
  1. umap/__init__.py +1 -1
  2. umap/forms.py +4 -14
  3. umap/locale/am_ET/LC_MESSAGES/django.mo +0 -0
  4. umap/locale/am_ET/LC_MESSAGES/django.po +278 -151
  5. umap/locale/ar/LC_MESSAGES/django.mo +0 -0
  6. umap/locale/ar/LC_MESSAGES/django.po +335 -141
  7. umap/locale/bg/LC_MESSAGES/django.mo +0 -0
  8. umap/locale/bg/LC_MESSAGES/django.po +279 -152
  9. umap/locale/br/LC_MESSAGES/django.mo +0 -0
  10. umap/locale/br/LC_MESSAGES/django.po +95 -79
  11. umap/locale/ca/LC_MESSAGES/django.mo +0 -0
  12. umap/locale/ca/LC_MESSAGES/django.po +85 -68
  13. umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  14. umap/locale/cs_CZ/LC_MESSAGES/django.po +78 -66
  15. umap/locale/da/LC_MESSAGES/django.mo +0 -0
  16. umap/locale/da/LC_MESSAGES/django.po +280 -153
  17. umap/locale/de/LC_MESSAGES/django.mo +0 -0
  18. umap/locale/de/LC_MESSAGES/django.po +80 -64
  19. umap/locale/el/LC_MESSAGES/django.mo +0 -0
  20. umap/locale/el/LC_MESSAGES/django.po +82 -66
  21. umap/locale/en/LC_MESSAGES/django.po +73 -61
  22. umap/locale/es/LC_MESSAGES/django.mo +0 -0
  23. umap/locale/es/LC_MESSAGES/django.po +75 -63
  24. umap/locale/et/LC_MESSAGES/django.mo +0 -0
  25. umap/locale/et/LC_MESSAGES/django.po +280 -153
  26. umap/locale/eu/LC_MESSAGES/django.mo +0 -0
  27. umap/locale/eu/LC_MESSAGES/django.po +82 -66
  28. umap/locale/fa_IR/LC_MESSAGES/django.mo +0 -0
  29. umap/locale/fa_IR/LC_MESSAGES/django.po +80 -64
  30. umap/locale/fi/LC_MESSAGES/django.mo +0 -0
  31. umap/locale/fi/LC_MESSAGES/django.po +278 -151
  32. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  33. umap/locale/fr/LC_MESSAGES/django.po +75 -63
  34. umap/locale/gl/LC_MESSAGES/django.mo +0 -0
  35. umap/locale/gl/LC_MESSAGES/django.po +280 -153
  36. umap/locale/he/LC_MESSAGES/django.mo +0 -0
  37. umap/locale/he/LC_MESSAGES/django.po +281 -154
  38. umap/locale/hu/LC_MESSAGES/django.mo +0 -0
  39. umap/locale/hu/LC_MESSAGES/django.po +80 -64
  40. umap/locale/is/LC_MESSAGES/django.mo +0 -0
  41. umap/locale/is/LC_MESSAGES/django.po +280 -153
  42. umap/locale/it/LC_MESSAGES/django.mo +0 -0
  43. umap/locale/it/LC_MESSAGES/django.po +82 -66
  44. umap/locale/ja/LC_MESSAGES/django.mo +0 -0
  45. umap/locale/ja/LC_MESSAGES/django.po +280 -153
  46. umap/locale/ko/LC_MESSAGES/django.mo +0 -0
  47. umap/locale/ko/LC_MESSAGES/django.po +280 -153
  48. umap/locale/lt/LC_MESSAGES/django.mo +0 -0
  49. umap/locale/lt/LC_MESSAGES/django.po +280 -153
  50. umap/locale/ms/LC_MESSAGES/django.mo +0 -0
  51. umap/locale/ms/LC_MESSAGES/django.po +82 -66
  52. umap/locale/nl/LC_MESSAGES/django.mo +0 -0
  53. umap/locale/nl/LC_MESSAGES/django.po +280 -153
  54. umap/locale/pl/LC_MESSAGES/django.mo +0 -0
  55. umap/locale/pl/LC_MESSAGES/django.po +82 -66
  56. umap/locale/pt/LC_MESSAGES/django.mo +0 -0
  57. umap/locale/pt/LC_MESSAGES/django.po +75 -63
  58. umap/locale/pt_BR/LC_MESSAGES/django.mo +0 -0
  59. umap/locale/pt_BR/LC_MESSAGES/django.po +280 -153
  60. umap/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  61. umap/locale/pt_PT/LC_MESSAGES/django.po +280 -153
  62. umap/locale/ru/LC_MESSAGES/django.mo +0 -0
  63. umap/locale/ru/LC_MESSAGES/django.po +280 -153
  64. umap/locale/sk_SK/LC_MESSAGES/django.mo +0 -0
  65. umap/locale/sk_SK/LC_MESSAGES/django.po +280 -153
  66. umap/locale/sl/LC_MESSAGES/django.mo +0 -0
  67. umap/locale/sl/LC_MESSAGES/django.po +280 -153
  68. umap/locale/sr/LC_MESSAGES/django.mo +0 -0
  69. umap/locale/sr/LC_MESSAGES/django.po +280 -153
  70. umap/locale/sv/LC_MESSAGES/django.mo +0 -0
  71. umap/locale/sv/LC_MESSAGES/django.po +81 -65
  72. umap/locale/th_TH/LC_MESSAGES/django.mo +0 -0
  73. umap/locale/th_TH/LC_MESSAGES/django.po +257 -185
  74. umap/locale/tr/LC_MESSAGES/django.mo +0 -0
  75. umap/locale/tr/LC_MESSAGES/django.po +280 -153
  76. umap/locale/uk_UA/LC_MESSAGES/django.mo +0 -0
  77. umap/locale/uk_UA/LC_MESSAGES/django.po +280 -153
  78. umap/locale/vi/LC_MESSAGES/django.mo +0 -0
  79. umap/locale/vi/LC_MESSAGES/django.po +278 -151
  80. umap/locale/zh/LC_MESSAGES/django.mo +0 -0
  81. umap/locale/zh/LC_MESSAGES/django.po +278 -151
  82. umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
  83. umap/locale/zh_TW/LC_MESSAGES/django.po +97 -81
  84. umap/management/commands/empty_trash.py +35 -0
  85. umap/management/commands/migrate_to_S3.py +29 -0
  86. umap/migrations/0023_alter_datalayer_uuid.py +19 -0
  87. umap/migrations/0024_alter_map_share_status.py +30 -0
  88. umap/migrations/0025_alter_datalayer_geojson.py +24 -0
  89. umap/models.py +68 -116
  90. umap/settings/base.py +23 -3
  91. umap/settings/local_s3.py +45 -0
  92. umap/static/umap/base.css +3 -603
  93. umap/static/umap/content.css +5 -3
  94. umap/static/umap/css/bar.css +202 -0
  95. umap/static/umap/css/form.css +620 -0
  96. umap/static/umap/css/icon.css +21 -1
  97. umap/static/umap/css/popup.css +125 -0
  98. umap/static/umap/img/16-white.svg +16 -4
  99. umap/static/umap/img/16.svg +1 -1
  100. umap/static/umap/img/source/16-white.svg +46 -45
  101. umap/static/umap/img/source/16.svg +1 -753
  102. umap/static/umap/js/components/fragment.js +3 -1
  103. umap/static/umap/js/modules/browser.js +20 -19
  104. umap/static/umap/js/modules/caption.js +21 -22
  105. umap/static/umap/js/modules/data/features.js +120 -78
  106. umap/static/umap/js/modules/data/layer.js +195 -153
  107. umap/static/umap/js/modules/facets.js +9 -9
  108. umap/static/umap/js/modules/formatter.js +5 -5
  109. umap/static/umap/js/modules/global.js +4 -52
  110. umap/static/umap/js/modules/help.js +18 -21
  111. umap/static/umap/js/modules/importer.js +133 -56
  112. umap/static/umap/js/modules/importers/cadastrefr.js +4 -0
  113. umap/static/umap/js/modules/importers/geodatamine.js +3 -3
  114. umap/static/umap/js/modules/importers/overpass.js +5 -0
  115. umap/static/umap/js/modules/permissions.js +85 -87
  116. umap/static/umap/js/modules/rendering/icon.js +2 -1
  117. umap/static/umap/js/modules/rendering/layers/base.js +15 -15
  118. umap/static/umap/js/modules/rendering/layers/classified.js +1 -1
  119. umap/static/umap/js/modules/rendering/layers/cluster.js +1 -1
  120. umap/static/umap/js/modules/rendering/layers/heat.js +1 -1
  121. umap/static/umap/js/modules/rendering/map.js +390 -0
  122. umap/static/umap/js/modules/rendering/popup.js +19 -19
  123. umap/static/umap/js/modules/rendering/template.js +88 -21
  124. umap/static/umap/js/modules/rendering/ui.js +63 -14
  125. umap/static/umap/js/modules/request.js +2 -2
  126. umap/static/umap/js/modules/rules.js +22 -25
  127. umap/static/umap/js/modules/saving.js +47 -0
  128. umap/static/umap/js/modules/schema.js +6 -0
  129. umap/static/umap/js/modules/share.js +21 -24
  130. umap/static/umap/js/modules/slideshow.js +24 -20
  131. umap/static/umap/js/modules/sync/updaters.js +7 -9
  132. umap/static/umap/js/modules/tableeditor.js +20 -19
  133. umap/static/umap/js/modules/ui/bar.js +196 -0
  134. umap/static/umap/js/modules/ui/dialog.js +6 -1
  135. umap/static/umap/js/modules/ui/panel.js +10 -9
  136. umap/static/umap/js/modules/umap.js +1691 -0
  137. umap/static/umap/js/modules/urls.js +2 -2
  138. umap/static/umap/js/modules/utils.js +22 -6
  139. umap/static/umap/js/umap.controls.js +81 -305
  140. umap/static/umap/js/umap.core.js +29 -50
  141. umap/static/umap/js/umap.forms.js +78 -27
  142. umap/static/umap/keycloak.png +0 -0
  143. umap/static/umap/locale/am_ET.js +26 -10
  144. umap/static/umap/locale/am_ET.json +26 -10
  145. umap/static/umap/locale/ar.js +26 -10
  146. umap/static/umap/locale/ar.json +26 -10
  147. umap/static/umap/locale/ast.js +26 -10
  148. umap/static/umap/locale/ast.json +26 -10
  149. umap/static/umap/locale/bg.js +26 -10
  150. umap/static/umap/locale/bg.json +26 -10
  151. umap/static/umap/locale/br.js +27 -20
  152. umap/static/umap/locale/br.json +27 -20
  153. umap/static/umap/locale/ca.js +32 -29
  154. umap/static/umap/locale/ca.json +32 -29
  155. umap/static/umap/locale/cs_CZ.js +24 -17
  156. umap/static/umap/locale/cs_CZ.json +24 -17
  157. umap/static/umap/locale/da.js +26 -10
  158. umap/static/umap/locale/da.json +26 -10
  159. umap/static/umap/locale/de.js +21 -14
  160. umap/static/umap/locale/de.json +21 -14
  161. umap/static/umap/locale/el.js +28 -12
  162. umap/static/umap/locale/el.json +28 -12
  163. umap/static/umap/locale/en.js +14 -9
  164. umap/static/umap/locale/en.json +14 -9
  165. umap/static/umap/locale/en_US.json +26 -10
  166. umap/static/umap/locale/es.js +16 -13
  167. umap/static/umap/locale/es.json +16 -13
  168. umap/static/umap/locale/et.js +26 -10
  169. umap/static/umap/locale/et.json +26 -10
  170. umap/static/umap/locale/eu.js +16 -9
  171. umap/static/umap/locale/eu.json +16 -9
  172. umap/static/umap/locale/fa_IR.js +16 -9
  173. umap/static/umap/locale/fa_IR.json +16 -9
  174. umap/static/umap/locale/fi.js +26 -10
  175. umap/static/umap/locale/fi.json +26 -10
  176. umap/static/umap/locale/fr.js +14 -9
  177. umap/static/umap/locale/fr.json +14 -9
  178. umap/static/umap/locale/gl.js +26 -10
  179. umap/static/umap/locale/gl.json +26 -10
  180. umap/static/umap/locale/he.js +26 -10
  181. umap/static/umap/locale/he.json +26 -10
  182. umap/static/umap/locale/hr.js +26 -10
  183. umap/static/umap/locale/hr.json +26 -10
  184. umap/static/umap/locale/hu.js +16 -9
  185. umap/static/umap/locale/hu.json +16 -9
  186. umap/static/umap/locale/id.js +26 -10
  187. umap/static/umap/locale/id.json +26 -10
  188. umap/static/umap/locale/is.js +26 -10
  189. umap/static/umap/locale/is.json +26 -10
  190. umap/static/umap/locale/it.js +26 -10
  191. umap/static/umap/locale/it.json +26 -10
  192. umap/static/umap/locale/ja.js +26 -10
  193. umap/static/umap/locale/ja.json +26 -10
  194. umap/static/umap/locale/ko.js +26 -10
  195. umap/static/umap/locale/ko.json +26 -10
  196. umap/static/umap/locale/lt.js +26 -10
  197. umap/static/umap/locale/lt.json +26 -10
  198. umap/static/umap/locale/ms.js +28 -12
  199. umap/static/umap/locale/ms.json +28 -12
  200. umap/static/umap/locale/nl.js +28 -12
  201. umap/static/umap/locale/nl.json +28 -12
  202. umap/static/umap/locale/no.js +26 -10
  203. umap/static/umap/locale/no.json +26 -10
  204. umap/static/umap/locale/pl.js +28 -12
  205. umap/static/umap/locale/pl.json +28 -12
  206. umap/static/umap/locale/pl_PL.json +26 -10
  207. umap/static/umap/locale/pt.js +16 -9
  208. umap/static/umap/locale/pt.json +16 -9
  209. umap/static/umap/locale/pt_BR.js +26 -10
  210. umap/static/umap/locale/pt_BR.json +26 -10
  211. umap/static/umap/locale/pt_PT.js +16 -9
  212. umap/static/umap/locale/pt_PT.json +16 -9
  213. umap/static/umap/locale/ro.js +26 -10
  214. umap/static/umap/locale/ro.json +26 -10
  215. umap/static/umap/locale/ru.js +26 -10
  216. umap/static/umap/locale/ru.json +26 -10
  217. umap/static/umap/locale/si.js +7 -7
  218. umap/static/umap/locale/si.json +7 -7
  219. umap/static/umap/locale/sk_SK.js +26 -10
  220. umap/static/umap/locale/sk_SK.json +26 -10
  221. umap/static/umap/locale/sl.js +26 -10
  222. umap/static/umap/locale/sl.json +26 -10
  223. umap/static/umap/locale/sr.js +26 -10
  224. umap/static/umap/locale/sr.json +26 -10
  225. umap/static/umap/locale/sv.js +27 -11
  226. umap/static/umap/locale/sv.json +27 -11
  227. umap/static/umap/locale/th_TH.js +28 -12
  228. umap/static/umap/locale/th_TH.json +28 -12
  229. umap/static/umap/locale/tr.js +26 -10
  230. umap/static/umap/locale/tr.json +26 -10
  231. umap/static/umap/locale/uk_UA.js +26 -10
  232. umap/static/umap/locale/uk_UA.json +26 -10
  233. umap/static/umap/locale/vi.js +26 -10
  234. umap/static/umap/locale/vi.json +26 -10
  235. umap/static/umap/locale/vi_VN.json +26 -10
  236. umap/static/umap/locale/zh.js +26 -10
  237. umap/static/umap/locale/zh.json +26 -10
  238. umap/static/umap/locale/zh_CN.json +26 -10
  239. umap/static/umap/locale/zh_TW.Big5.json +26 -10
  240. umap/static/umap/locale/zh_TW.js +34 -27
  241. umap/static/umap/locale/zh_TW.json +34 -27
  242. umap/static/umap/map.css +39 -530
  243. umap/static/umap/unittests/URLs.js +15 -15
  244. umap/static/umap/unittests/utils.js +23 -1
  245. umap/static/umap/vars.css +2 -1
  246. umap/static/umap/vendors/formbuilder/Leaflet.FormBuilder.js +5 -1
  247. umap/storage/__init__.py +3 -0
  248. umap/storage/fs.py +101 -0
  249. umap/storage/s3.py +61 -0
  250. umap/templates/base.html +2 -0
  251. umap/templates/registration/login.html +7 -6
  252. umap/templates/umap/components/alerts/alert.html +4 -0
  253. umap/templates/umap/css.html +6 -0
  254. umap/templates/umap/js.html +3 -2
  255. umap/templates/umap/map_init.html +6 -5
  256. umap/templates/umap/user_dashboard.html +20 -19
  257. umap/tests/base.py +11 -1
  258. umap/tests/fixtures/empty_tile.png +0 -0
  259. umap/tests/fixtures/test_upload_simple_marker.json +19 -0
  260. umap/tests/integration/conftest.py +4 -1
  261. umap/tests/integration/test_anonymous_owned_map.py +18 -10
  262. umap/tests/integration/test_browser.py +16 -1
  263. umap/tests/integration/test_dashboard.py +1 -1
  264. umap/tests/integration/test_edit_datalayer.py +29 -7
  265. umap/tests/integration/test_import.py +28 -4
  266. umap/tests/integration/test_optimistic_merge.py +31 -8
  267. umap/tests/integration/test_owned_map.py +22 -16
  268. umap/tests/integration/test_popup.py +44 -0
  269. umap/tests/integration/test_save.py +35 -0
  270. umap/tests/integration/test_view_marker.py +12 -0
  271. umap/tests/integration/test_view_polyline.py +257 -0
  272. umap/tests/integration/test_websocket_sync.py +81 -9
  273. umap/tests/test_dashboard.py +82 -0
  274. umap/tests/test_datalayer.py +6 -7
  275. umap/tests/test_datalayer_s3.py +135 -0
  276. umap/tests/test_datalayer_views.py +28 -10
  277. umap/tests/test_empty_trash.py +34 -0
  278. umap/tests/test_map.py +12 -3
  279. umap/tests/test_map_views.py +69 -37
  280. umap/tests/test_statics.py +1 -1
  281. umap/tests/test_team_views.py +35 -1
  282. umap/tests/test_views.py +31 -52
  283. umap/urls.py +3 -3
  284. umap/views.py +126 -90
  285. {umap_project-2.7.2.dist-info → umap_project-2.8.0.dist-info}/METADATA +16 -14
  286. {umap_project-2.7.2.dist-info → umap_project-2.8.0.dist-info}/RECORD +290 -269
  287. {umap_project-2.7.2.dist-info → umap_project-2.8.0.dist-info}/WHEEL +1 -1
  288. umap/management/commands/purge_purgatory.py +0 -28
  289. umap/static/umap/js/umap.js +0 -1903
  290. umap/tests/test_purge_purgatory.py +0 -25
  291. /umap/{storage.py → storage/staticfiles.py} +0 -0
  292. {umap_project-2.7.2.dist-info → umap_project-2.8.0.dist-info}/entry_points.txt +0 -0
  293. {umap_project-2.7.2.dist-info → umap_project-2.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -3,8 +3,8 @@ import { translate } from './i18n.js'
3
3
  import * as Utils from './utils.js'
4
4
 
5
5
  export default class Facets {
6
- constructor(map) {
7
- this.map = map
6
+ constructor(umap) {
7
+ this._umap = umap
8
8
  this.selected = {}
9
9
  }
10
10
 
@@ -24,7 +24,7 @@ export default class Facets {
24
24
  this.selected[name] = selected
25
25
  }
26
26
 
27
- this.map.eachBrowsableDataLayer((datalayer) => {
27
+ this._umap.eachBrowsableDataLayer((datalayer) => {
28
28
  datalayer.eachFeature((feature) => {
29
29
  for (const name of names) {
30
30
  let value = feature.properties[name]
@@ -108,8 +108,8 @@ export default class Facets {
108
108
  const defaultType = 'checkbox'
109
109
  const allowedTypes = [defaultType, 'radio', 'number', 'date', 'datetime']
110
110
  const defined = new Map()
111
- if (!this.map.options.facetKey) return defined
112
- return (this.map.options.facetKey || '').split(',').reduce((acc, curr) => {
111
+ if (!this._umap.properties.facetKey) return defined
112
+ return (this._umap.properties.facetKey || '').split(',').reduce((acc, curr) => {
113
113
  let [name, label, type] = curr.split('|')
114
114
  type = allowedTypes.includes(type) ? type : defaultType
115
115
  acc.set(name, { label: label || name, type: type })
@@ -146,15 +146,15 @@ export default class Facets {
146
146
  const defined = this.getDefined()
147
147
  if (!defined.has(property)) {
148
148
  defined.set(property, { label, type })
149
- this.map.options.facetKey = this.dumps(defined)
150
- this.map.isDirty = true
149
+ this._umap.properties.facetKey = this.dumps(defined)
150
+ this._umap.isDirty = true
151
151
  }
152
152
  }
153
153
 
154
154
  remove(property) {
155
155
  const defined = this.getDefined()
156
156
  defined.delete(property)
157
- this.map.options.facetKey = this.dumps(defined)
158
- this.map.isDirty = true
157
+ this._umap.properties.facetKey = this.dumps(defined)
158
+ this._umap.isDirty = true
159
159
  }
160
160
  }
@@ -3,24 +3,24 @@ import { translate } from './i18n.js'
3
3
 
4
4
  export const EXPORT_FORMATS = {
5
5
  geojson: {
6
- formatter: async (map) => JSON.stringify(map.toGeoJSON(), null, 2),
6
+ formatter: async (umap) => JSON.stringify(umap.toGeoJSON(), null, 2),
7
7
  ext: '.geojson',
8
8
  filetype: 'application/json',
9
9
  },
10
10
  gpx: {
11
- formatter: async (map) => await map.formatter.toGPX(map.toGeoJSON()),
11
+ formatter: async (umap) => await umap.formatter.toGPX(umap.toGeoJSON()),
12
12
  ext: '.gpx',
13
13
  filetype: 'application/gpx+xml',
14
14
  },
15
15
  kml: {
16
- formatter: async (map) => await map.formatter.toKML(map.toGeoJSON()),
16
+ formatter: async (umap) => await umap.formatter.toKML(umap.toGeoJSON()),
17
17
  ext: '.kml',
18
18
  filetype: 'application/vnd.google-earth.kml+xml',
19
19
  },
20
20
  csv: {
21
- formatter: async (map) => {
21
+ formatter: async (umap) => {
22
22
  const table = []
23
- map.eachFeature((feature) => {
23
+ umap.eachFeature((feature) => {
24
24
  const row = feature.toGeoJSON().properties
25
25
  const center = feature.center
26
26
  delete row._umap_options
@@ -1,34 +1,11 @@
1
- import {
2
- uMapAlert as Alert,
3
- uMapAlertCreation as AlertCreation,
4
- } from '../components/alerts/alert.js'
5
- import {
6
- AjaxAutocomplete,
7
- AjaxAutocompleteMultiple,
8
- AutocompleteDatalist,
9
- } from './autocomplete.js'
10
- import Browser from './browser.js'
11
- import Caption from './caption.js'
12
- import ContextMenu from './ui/contextmenu.js'
13
- import Facets from './facets.js'
14
- import { Formatter } from './formatter.js'
1
+ import { uMapAlert as Alert } from '../components/alerts/alert.js'
2
+ import { AjaxAutocomplete, AjaxAutocompleteMultiple, AutocompleteDatalist } from './autocomplete.js'
15
3
  import Help from './help.js'
16
- import Importer from './importer.js'
17
- import Orderable from './orderable.js'
18
- import { HTTPError, NOKError, Request, RequestError, ServerRequest } from './request.js'
19
- import Rules from './rules.js'
4
+ import { ServerRequest } from './request.js'
20
5
  import { SCHEMA } from './schema.js'
21
- import Share from './share.js'
22
- import Slideshow from './slideshow.js'
23
- import { SyncEngine } from './sync/engine.js'
24
- import Dialog from './ui/dialog.js'
25
- import { EditPanel, FullPanel, Panel } from './ui/panel.js'
26
- import Tooltip from './ui/tooltip.js'
27
- import URLs from './urls.js'
28
6
  import * as Utils from './utils.js'
29
7
  import * as Icon from './rendering/icon.js'
30
- import { DataLayer, LAYER_TYPES } from './data/layer.js'
31
- import { DataLayerPermissions, MapPermissions } from './permissions.js'
8
+ import { LAYER_TYPES } from './data/layer.js'
32
9
  import { Point, LineString, Polygon } from './data/features.js'
33
10
  import { LeafletMarker, LeafletPolyline, LeafletPolygon } from './rendering/ui.js'
34
11
 
@@ -38,44 +15,19 @@ import { LeafletMarker, LeafletPolyline, LeafletPolygon } from './rendering/ui.j
38
15
  // By alphabetic order
39
16
  window.U = {
40
17
  Alert,
41
- AlertCreation,
42
18
  AjaxAutocomplete,
43
19
  AjaxAutocompleteMultiple,
44
20
  AutocompleteDatalist,
45
- Browser,
46
- Caption,
47
- ContextMenu,
48
- DataLayer,
49
- DataLayerPermissions,
50
- Dialog,
51
- EditPanel,
52
- Facets,
53
- Formatter,
54
- FullPanel,
55
21
  Help,
56
- HTTPError,
57
22
  Icon,
58
- Importer,
59
23
  LAYER_TYPES,
60
24
  LeafletMarker,
61
25
  LeafletPolygon,
62
26
  LeafletPolyline,
63
27
  LineString,
64
- MapPermissions,
65
- NOKError,
66
- Orderable,
67
- Panel,
68
28
  Point,
69
29
  Polygon,
70
- Request,
71
- RequestError,
72
- Rules,
73
30
  SCHEMA,
74
31
  ServerRequest,
75
- Share,
76
- Slideshow,
77
- SyncEngine,
78
- Tooltip,
79
- URLs,
80
32
  Utils,
81
33
  }
@@ -1,5 +1,7 @@
1
1
  import { DomEvent, DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
2
2
  import { translate } from './i18n.js'
3
+ import * as Utils from './utils.js'
4
+ import Dialog from './ui/dialog.js'
3
5
 
4
6
  const SHORTCUTS = {
5
7
  DRAW_MARKER: {
@@ -133,13 +135,13 @@ const ENTRIES = {
133
135
  <li>${translate('# one hash for main heading')}</li>
134
136
  <li>${translate('## two hashes for second heading')}</li>
135
137
  <li>${translate('### three hashes for third heading')}</li>
136
- <li>${translate('Simple link: [[http://example.com]]')}</li>
137
- <li>${translate('Link with text: [[http://example.com|text of the link]]')}</li>
138
- <li>${translate('Image: {{http://image.url.com}}')}</li>
139
- <li>${translate('Image with custom width (in px): {{http://image.url.com|width}}')}</li>
140
- <li>${translate('Iframe: {{{http://iframe.url.com}}}')}</li>
141
- <li>${translate('Iframe with custom height (in px): {{{http://iframe.url.com|height}}}')}</li>
142
- <li>${translate('Iframe with custom height and width (in px): {{{http://iframe.url.com|height*width}}}')}</li>
138
+ <li>${translate('Simple link: [[https://example.com]]')}</li>
139
+ <li>${translate('Link with text: [[https://example.com|text of the link]]')}</li>
140
+ <li>${translate('Image: {{https://image.url.com}}')}</li>
141
+ <li>${translate('Image with custom width (in px): {{https://image.url.com|width}}')}</li>
142
+ <li>${translate('Iframe: {{{https://iframe.url.com}}}')}</li>
143
+ <li>${translate('Iframe with custom height (in px): {{{https://iframe.url.com|height}}}')}</li>
144
+ <li>${translate('Iframe with custom height and width (in px): {{{https://iframe.url.com|height*width}}}')}</li>
143
145
  <li>${translate('--- for a horizontal rule')}</li>
144
146
  </ul>
145
147
  </div>
@@ -163,9 +165,9 @@ const ENTRIES = {
163
165
  }
164
166
 
165
167
  export default class Help {
166
- constructor(map) {
167
- this.map = map
168
- this.dialog = new U.Dialog()
168
+ constructor(umap) {
169
+ this.umap = umap
170
+ this.dialog = new Dialog({ className: 'dark', accept: false, cancel: false })
169
171
  this.isMacOS = /mac/i.test(
170
172
  // eslint-disable-next-line compat/compat -- Fallback available.
171
173
  navigator.userAgentData ? navigator.userAgentData.platform : navigator.platform
@@ -199,7 +201,7 @@ export default class Help {
199
201
  innerHTML: ENTRIES[name],
200
202
  })
201
203
  }
202
- this.dialog.open({ template: container, className: 'dark', cancel: false, accept: false })
204
+ this.dialog.open({ template: container })
203
205
  }
204
206
 
205
207
  // Special dynamic case. Do we still think this dialog is useful?
@@ -211,7 +213,7 @@ export default class Help {
211
213
  className: 'umap-help-entry',
212
214
  parent: container,
213
215
  }).appendChild(this._buildEditEntry())
214
- this.map.dialog.open({ content: container, className: 'dark' })
216
+ this.dialog.open({ template: container })
215
217
  }
216
218
 
217
219
  button(container, entries) {
@@ -224,13 +226,6 @@ export default class Help {
224
226
  return button
225
227
  }
226
228
 
227
- getStartedLink(container) {
228
- const button = DomUtil.createButton('umap-help-link', container, translate('Help'))
229
- button.textContent = translate('Help')
230
- button.addEventListener('click', () => this.showGetStarted())
231
- return button
232
- }
233
-
234
229
  parse(container) {
235
230
  for (const element of container.querySelectorAll('[data-help]')) {
236
231
  this.button(element, element.dataset.help.split(','))
@@ -247,9 +242,11 @@ export default class Help {
247
242
  DomEvent.on(actionContainer, 'click', action.addHooks, action)
248
243
  DomEvent.on(actionContainer, 'click', this.dialog.close, this.dialog)
249
244
  }
250
- for (const id in this.map.helpMenuActions) {
251
- addAction(this.map.helpMenuActions[id])
245
+ for (const action of Object.values(Help.MENU_ACTIONS)) {
246
+ addAction(action)
252
247
  }
253
248
  return container
254
249
  }
255
250
  }
251
+
252
+ Help.MENU_ACTIONS = {}
@@ -1,4 +1,8 @@
1
- import { DomEvent, DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
1
+ import {
2
+ DomEvent,
3
+ DomUtil,
4
+ LatLngBounds,
5
+ } from '../../vendors/leaflet/leaflet-src.esm.js'
2
6
  import { uMapAlert as Alert } from '../components/alerts/alert.js'
3
7
  import { translate } from './i18n.js'
4
8
  import { SCHEMA } from './schema.js'
@@ -6,17 +10,14 @@ import Dialog from './ui/dialog.js'
6
10
  import * as Utils from './utils.js'
7
11
 
8
12
  const TEMPLATE = `
13
+ <div class="umap-upload">
9
14
  <h3><i class="icon icon-16 icon-upload"></i><span>${translate('Import data')}</span></h3>
10
15
  <fieldset class="formbox">
11
16
  <legend class="counter">${translate('Choose data')}</legend>
12
17
  <input type="file" multiple autofocus onchange />
13
- <input type="url" placeholder="${translate('Provide an URL here')}" onchange />
14
18
  <textarea onchange placeholder="${translate('Paste your data here')}"></textarea>
15
- <div class="importers" hidden>
16
- <h4>${translate('Import helpers:')}</h4>
17
- <ul class="grid-container">
18
- </ul>
19
- </div>
19
+ <input class="highlightable" type="url" placeholder="${translate('Provide an URL here')}" onchange />
20
+ <button class="flat importers" hidden data-ref="importersButton"><i class="icon icon-16 icon-magic"></i>${translate('Import helpers')}</button>
20
21
  </fieldset>
21
22
  <fieldset class="formbox">
22
23
  <legend class="counter" data-help="importFormats">${translate(
@@ -36,30 +37,45 @@ const TEMPLATE = `
36
37
  <fieldset id="import-mode" class="formbox">
37
38
  <legend class="counter" data-help="importMode">${translate('Choose import mode')}</legend>
38
39
  <label>
39
- <input type="radio" name="action" value="copy" />
40
+ <input type="radio" name="action" value="copy" checked onchange />
40
41
  ${translate('Copy into the layer')}
41
42
  </label>
42
43
  <label>
43
- <input type="radio" name="action" value="link" />
44
+ <input type="radio" name="action" value="link" onchange />
44
45
  ${translate('Link to the layer as remote data')}
45
46
  </label>
46
47
  </fieldset>
47
- <input type="button" class="button" name="submit" value="${translate('Import data')}" />
48
+ <input type="button" class="button primary" name="submit" value="${translate('Import data')}" disabled />
49
+ </div>
48
50
  `
49
51
 
50
- export default class Importer {
51
- constructor(map) {
52
- this.map = map
52
+ const GRID_TEMPLATE = `
53
+ <div>
54
+ <h3><i class="icon icon-16 icon-magic"></i>${translate('Import helpers')}</h3>
55
+ <p>${translate('Import helpers will fill the URL field for you.')}</p>
56
+ <ul class="grid-container by4" data-ref="grid"></ul>
57
+ </div>
58
+ `
59
+
60
+ export default class Importer extends Utils.WithTemplate {
61
+ constructor(umap) {
62
+ super()
63
+ this._umap = umap
53
64
  this.TYPES = ['geojson', 'csv', 'gpx', 'kml', 'osm', 'georss', 'umap']
54
65
  this.IMPORTERS = []
55
66
  this.loadImporters()
56
- this.dialog = new Dialog()
67
+ this.dialog = new Dialog({
68
+ className: 'importers dark',
69
+ back: () => this.showImporters(),
70
+ })
57
71
  }
58
72
 
59
73
  loadImporters() {
60
- for (const [name, config] of Object.entries(this.map.options.importers || {})) {
74
+ for (const [name, config] of Object.entries(
75
+ this._umap.properties.importers || {}
76
+ )) {
61
77
  const register = (mod) => {
62
- this.IMPORTERS.push(new mod.Importer(this.map, config))
78
+ this.IMPORTERS.push(new mod.Importer(this._umap, config))
63
79
  }
64
80
  // We need to have explicit static paths for Django's collectstatic with hashes.
65
81
  switch (name) {
@@ -112,6 +128,11 @@ export default class Importer {
112
128
  return this.qs('textarea').value
113
129
  }
114
130
 
131
+ set raw(value) {
132
+ this.qs('textarea').value = value
133
+ this.onChange()
134
+ }
135
+
115
136
  get clear() {
116
137
  return Boolean(this.qs('[name=clear]').checked)
117
138
  }
@@ -139,25 +160,31 @@ export default class Importer {
139
160
 
140
161
  get layer() {
141
162
  return (
142
- this.map.datalayers[this.layerId] ||
143
- this.map.createDataLayer({ name: this.layerName })
163
+ this._umap.datalayers[this.layerId] ||
164
+ this._umap.createDataLayer({ name: this.layerName })
144
165
  )
145
166
  }
146
167
 
168
+ showImporters() {
169
+ if (!this.IMPORTERS.length) return
170
+ const [element, { grid }] = Utils.loadTemplateWithRefs(GRID_TEMPLATE)
171
+ for (const plugin of this.IMPORTERS.sort((a, b) => (a.id > b.id ? 1 : -1))) {
172
+ const button = Utils.loadTemplate(
173
+ `<li><button type="button" class="${plugin.id}">${plugin.name}</button></li>`
174
+ )
175
+ button.addEventListener('click', () => plugin.open(this))
176
+ grid.appendChild(button)
177
+ }
178
+ this.dialog.open({ template: element, cancel: false, accept: false, back: false })
179
+ }
180
+
147
181
  build() {
148
- this.container = DomUtil.create('div', 'umap-upload')
149
- this.container.innerHTML = TEMPLATE
182
+ this.container = this.loadTemplate(TEMPLATE)
150
183
  if (this.IMPORTERS.length) {
151
- const parent = this.container.querySelector('.importers ul')
152
- for (const plugin of this.IMPORTERS.sort((a, b) => (a.id > b.id ? 1 : -1))) {
153
- L.DomUtil.createButton(
154
- plugin.id,
155
- DomUtil.element({ tagName: 'li', parent }),
156
- plugin.name,
157
- () => plugin.open(this)
158
- )
159
- }
160
- this.qs('.importers').toggleAttribute('hidden', false)
184
+ // TODO use this.elements instead of this.qs
185
+ const button = this.qs('[data-ref=importersButton]')
186
+ button.addEventListener('click', () => this.showImporters())
187
+ button.toggleAttribute('hidden', false)
161
188
  }
162
189
  for (const type of this.TYPES) {
163
190
  DomUtil.element({
@@ -167,8 +194,8 @@ export default class Importer {
167
194
  textContent: type,
168
195
  })
169
196
  }
170
- this.map.help.parse(this.container)
171
- DomEvent.on(this.qs('[name=submit]'), 'click', this.submit, this)
197
+ this._umap.help.parse(this.container)
198
+ this.qs('[name=submit]').addEventListener('click', () => this.submit())
172
199
  DomEvent.on(this.qs('[type=file]'), 'change', this.onFileChange, this)
173
200
  for (const element of this.container.querySelectorAll('[onchange]')) {
174
201
  DomEvent.on(element, 'change', this.onChange, this)
@@ -183,6 +210,7 @@ export default class Importer {
183
210
  )
184
211
  this.qs('[name=layer-name]').toggleAttribute('hidden', Boolean(this.layerId))
185
212
  this.qs('#clear').toggleAttribute('hidden', !this.layerId)
213
+ this.qs('[name=submit').toggleAttribute('disabled', !this.canSubmit())
186
214
  }
187
215
 
188
216
  onFileChange(e) {
@@ -204,9 +232,10 @@ export default class Importer {
204
232
  this.url = null
205
233
  this.format = undefined
206
234
  this.layerName = null
235
+ this.raw = null
207
236
  const layerSelect = this.qs('[name="layer-id"]')
208
237
  layerSelect.innerHTML = ''
209
- this.map.eachDataLayerReverse((datalayer) => {
238
+ this._umap.eachDataLayerReverse((datalayer) => {
210
239
  if (datalayer.isLoaded() && !datalayer.isRemoteLayer()) {
211
240
  DomUtil.element({
212
241
  tagName: 'option',
@@ -227,7 +256,7 @@ export default class Importer {
227
256
 
228
257
  open() {
229
258
  if (!this.container) this.build()
230
- const onLoad = this.map.editPanel.open({ content: this.container })
259
+ const onLoad = this._umap.editPanel.open({ content: this.container })
231
260
  onLoad.then(() => this.onLoad())
232
261
  }
233
262
 
@@ -236,34 +265,41 @@ export default class Importer {
236
265
  this.qs('[type=file]').showPicker()
237
266
  }
238
267
 
268
+ canSubmit() {
269
+ if (!this.format) return false
270
+ const hasFiles = Boolean(this.files.length)
271
+ const hasRaw = Boolean(this.raw)
272
+ const hasUrl = Boolean(this.url)
273
+ const hasAction = Boolean(this.action)
274
+ if (!hasFiles && !hasRaw && !hasUrl) return false
275
+ if (this.url) return hasAction
276
+ return true
277
+ }
278
+
239
279
  submit() {
240
- let hasErrors
241
280
  if (this.format === 'umap') {
242
- hasErrors = !this.full()
281
+ this.full()
243
282
  } else if (!this.url) {
244
- hasErrors = !this.copy()
283
+ this.copy()
245
284
  } else if (this.action) {
246
- hasErrors = !this[this.action]()
247
- }
248
- if (hasErrors === false) {
249
- Alert.info(translate('Data successfully imported!'))
285
+ this[this.action]()
250
286
  }
251
287
  }
252
288
 
253
289
  full() {
254
- this.map.once('postsync', this.map._setDefaultCenter)
255
290
  try {
256
291
  if (this.files.length) {
257
292
  for (const file of this.files) {
258
- this.map.processFileToImport(file, null, 'umap')
293
+ this._umap.processFileToImport(file, null, 'umap')
259
294
  }
260
295
  } else if (this.raw) {
261
- this.map.importRaw(this.raw)
296
+ this._umap.importRaw(this.raw)
262
297
  } else if (this.url) {
263
- this.map.importFromUrl(this.url, this.format)
298
+ this._umap.importFromUrl(this.url, this.format)
264
299
  }
300
+ this.onSuccess()
265
301
  } catch (e) {
266
- Alert.error(translate('Invalid umap data'))
302
+ this.onError(translate('Invalid umap data'))
267
303
  console.error(e)
268
304
  return false
269
305
  }
@@ -274,7 +310,7 @@ export default class Importer {
274
310
  return false
275
311
  }
276
312
  if (!this.format) {
277
- Alert.error(translate('Please choose a format'))
313
+ this.onError(translate('Please choose a format'))
278
314
  return false
279
315
  }
280
316
  const layer = this.layer
@@ -282,30 +318,71 @@ export default class Importer {
282
318
  url: this.url,
283
319
  format: this.format,
284
320
  }
285
- if (this.map.options.urls.ajax_proxy) {
321
+ if (this._umap.properties.urls.ajax_proxy) {
286
322
  layer.options.remoteData.proxy = true
287
323
  layer.options.remoteData.ttl = SCHEMA.ttl.default
288
324
  }
289
- layer.fetchRemoteData(true)
325
+ layer.fetchRemoteData(true).then((features) => {
326
+ if (features?.length) {
327
+ layer.zoomTo()
328
+ this.onSuccess()
329
+ } else {
330
+ this.onError()
331
+ }
332
+ })
290
333
  }
291
334
 
292
- copy() {
335
+ async copy() {
293
336
  // Format may be guessed from file later.
294
337
  // Usefull in case of multiple files with different formats.
295
338
  if (!this.format && !this.files.length) {
296
- Alert.error(translate('Please choose a format'))
339
+ this.onError(translate('Please choose a format'))
297
340
  return false
298
341
  }
342
+ let promise
299
343
  const layer = this.layer
300
344
  if (this.clear) layer.empty()
301
345
  if (this.files.length) {
302
- for (const file of this.files) {
303
- this.map.processFileToImport(file, layer, this.format)
304
- }
346
+ promise = layer.importFromFiles(this.files, this.format)
305
347
  } else if (this.raw) {
306
- layer.importRaw(this.raw, this.format)
348
+ promise = layer.importRaw(this.raw, this.format)
307
349
  } else if (this.url) {
308
- layer.importFromUrl(this.url, this.format)
350
+ promise = layer.importFromUrl(this.url, this.format)
351
+ }
352
+ if (promise) promise.then((data) => this.onCopyFinished(layer, data))
353
+ }
354
+
355
+ onError(message = translate('No data has been found for import')) {
356
+ Alert.error(message)
357
+ }
358
+
359
+ onSuccess(count) {
360
+ if (count) {
361
+ Alert.success(
362
+ translate('Successfully imported {count} feature(s)', {
363
+ count: count,
364
+ })
365
+ )
366
+ } else {
367
+ Alert.success(translate('Data successfully imported!'))
368
+ }
369
+ }
370
+
371
+ onCopyFinished(layer, features) {
372
+ // undefined features means error, let original error message pop
373
+ if (!features) return
374
+ if (!features.length) {
375
+ this.onError()
376
+ } else {
377
+ const bounds = new LatLngBounds()
378
+ for (const feature of features) {
379
+ const featureBounds = feature.ui.getBounds
380
+ ? feature.ui.getBounds()
381
+ : feature.ui.getCenter()
382
+ bounds.extend(featureBounds)
383
+ }
384
+ this.onSuccess(features.length)
385
+ layer.zoomTo(bounds)
309
386
  }
310
387
  }
311
388
  }
@@ -2,6 +2,8 @@ import { DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
2
2
  import { BaseAjax, SingleMixin } from '../autocomplete.js'
3
3
  import * as Util from '../utils.js'
4
4
  import { AutocompleteCommunes } from './communesfr.js'
5
+ import { translate } from '../i18n.js'
6
+ import { uMapAlert as Alert } from '../../components/alerts/alert.js'
5
7
 
6
8
  const TEMPLATE = `
7
9
  <h3>Cadastre</h3>
@@ -56,6 +58,8 @@ export class Importer {
56
58
  .open({
57
59
  template: container,
58
60
  className: `${this.id} importer dark`,
61
+ cancel: false,
62
+ accept: translate('Choose this data'),
59
63
  })
60
64
  .then(confirm)
61
65
  }
@@ -37,8 +37,8 @@ class Autocomplete extends SingleMixin(BaseAjax) {
37
37
  }
38
38
 
39
39
  export class Importer {
40
- constructor(map, options = {}) {
41
- this.map = map
40
+ constructor(umap, options = {}) {
41
+ this.umap = umap
42
42
  this.name = options.name || 'GeoDataMine'
43
43
  this.baseUrl = options?.url || 'https://geodatamine.fr'
44
44
  this.id = 'geodatamine'
@@ -49,7 +49,7 @@ export class Importer {
49
49
  let boundaryName = null
50
50
  const container = DomUtil.create('div')
51
51
  container.innerHTML = TEMPLATE
52
- const response = await importer.map.request.get(`${this.baseUrl}/themes`)
52
+ const response = await this.umap.request.get(`${this.baseUrl}/themes`)
53
53
  const select = container.querySelector('select')
54
54
  if (response?.ok) {
55
55
  const { themes } = await response.json()
@@ -53,11 +53,15 @@ export class Importer {
53
53
  'https://photon.komoot.io/api?q={q}&layer=county&layer=city&layer=state'
54
54
  this.id = 'overpass'
55
55
  this.boundaryChoice = null
56
+ this.expression = null
56
57
  }
57
58
 
58
59
  async open(importer) {
59
60
  const container = DomUtil.create('div')
60
61
  container.innerHTML = TEMPLATE
62
+ if (this.expression) {
63
+ container.querySelector('[name=tags]').value = this.expression
64
+ }
61
65
  this.autocomplete = new Autocomplete(container.querySelector('#area'), {
62
66
  url: this.searchUrl,
63
67
  placeholder: translate(
@@ -80,6 +84,7 @@ export class Importer {
80
84
  Alert.error(translate('Expression is empty'))
81
85
  return
82
86
  }
87
+ this.expression = form.tags
83
88
  let tags = form.tags
84
89
  if (!tags.startsWith('[')) tags = `[${tags}]`
85
90
  let area = '{south},{west},{north},{east}'