umap-project 2.9.3__py3-none-any.whl → 3.0.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.

Potentially problematic release.


This version of umap-project might be problematic. Click here for more details.

Files changed (217) hide show
  1. umap/__init__.py +1 -1
  2. umap/context_processors.py +1 -0
  3. umap/forms.py +1 -2
  4. umap/locale/de/LC_MESSAGES/django.mo +0 -0
  5. umap/locale/de/LC_MESSAGES/django.po +218 -96
  6. umap/locale/en/LC_MESSAGES/django.po +128 -52
  7. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  8. umap/locale/fr/LC_MESSAGES/django.po +128 -52
  9. umap/locale/hu/LC_MESSAGES/django.mo +0 -0
  10. umap/locale/hu/LC_MESSAGES/django.po +209 -88
  11. umap/locale/is/LC_MESSAGES/django.mo +0 -0
  12. umap/locale/is/LC_MESSAGES/django.po +296 -175
  13. umap/migrations/0027_map_tags.py +23 -0
  14. umap/models.py +13 -2
  15. umap/settings/base.py +23 -5
  16. umap/static/umap/base.css +41 -8
  17. umap/static/umap/content.css +72 -37
  18. umap/static/umap/css/bar.css +43 -21
  19. umap/static/umap/css/dialog.css +4 -1
  20. umap/static/umap/css/form.css +40 -27
  21. umap/static/umap/css/icon.css +11 -1
  22. umap/static/umap/css/importers.css +7 -0
  23. umap/static/umap/img/16-white.svg +23 -2
  24. umap/static/umap/img/16.svg +1 -1
  25. umap/static/umap/img/24.svg +4 -4
  26. umap/static/umap/img/home.svg +7 -0
  27. umap/static/umap/img/importers/banfr.svg +1 -0
  28. umap/static/umap/img/marker.svg +2 -5
  29. umap/static/umap/img/source/16-white.svg +24 -3
  30. umap/static/umap/img/source/16.svg +1 -1
  31. umap/static/umap/img/source/24.svg +5 -5
  32. umap/static/umap/img/target.svg +1 -0
  33. umap/static/umap/js/components/alerts/alert.js +0 -1
  34. umap/static/umap/js/modules/browser.js +4 -4
  35. umap/static/umap/js/modules/caption.js +1 -1
  36. umap/static/umap/js/modules/data/features.js +25 -25
  37. umap/static/umap/js/modules/data/layer.js +91 -97
  38. umap/static/umap/js/modules/facets.js +9 -5
  39. umap/static/umap/js/modules/form/builder.js +21 -29
  40. umap/static/umap/js/modules/form/fields.js +40 -14
  41. umap/static/umap/js/modules/formatter.js +1 -1
  42. umap/static/umap/js/modules/global.js +9 -5
  43. umap/static/umap/js/modules/help.js +18 -5
  44. umap/static/umap/js/modules/importer.js +5 -2
  45. umap/static/umap/js/modules/importers/banfr.js +93 -0
  46. umap/static/umap/js/modules/importers/cadastrefr.js +2 -2
  47. umap/static/umap/js/modules/importers/communesfr.js +1 -1
  48. umap/static/umap/js/modules/permissions.js +20 -10
  49. umap/static/umap/js/modules/rendering/icon.js +15 -2
  50. umap/static/umap/js/modules/rendering/layers/classified.js +7 -7
  51. umap/static/umap/js/modules/rendering/layers/cluster.js +2 -2
  52. umap/static/umap/js/modules/rendering/layers/heat.js +4 -4
  53. umap/static/umap/js/modules/rendering/map.js +14 -6
  54. umap/static/umap/js/modules/rendering/popup.js +2 -2
  55. umap/static/umap/js/modules/rendering/template.js +3 -3
  56. umap/static/umap/js/modules/rendering/ui.js +17 -11
  57. umap/static/umap/js/modules/rules.js +13 -16
  58. umap/static/umap/js/modules/schema.js +23 -1
  59. umap/static/umap/js/modules/share.js +1 -1
  60. umap/static/umap/js/modules/slideshow.js +1 -0
  61. umap/static/umap/js/modules/sync/engine.js +141 -19
  62. umap/static/umap/js/modules/sync/undo.js +101 -0
  63. umap/static/umap/js/modules/sync/updaters.js +51 -28
  64. umap/static/umap/js/modules/tableeditor.js +1 -1
  65. umap/static/umap/js/modules/ui/bar.js +61 -21
  66. umap/static/umap/js/modules/ui/tooltip.js +1 -1
  67. umap/static/umap/js/modules/umap.js +190 -176
  68. umap/static/umap/js/modules/utils.js +30 -4
  69. umap/static/umap/js/umap.controls.js +82 -38
  70. umap/static/umap/locale/am_ET.js +11 -6
  71. umap/static/umap/locale/am_ET.json +11 -6
  72. umap/static/umap/locale/ar.js +11 -6
  73. umap/static/umap/locale/ar.json +11 -6
  74. umap/static/umap/locale/ast.js +11 -6
  75. umap/static/umap/locale/ast.json +11 -6
  76. umap/static/umap/locale/bg.js +11 -6
  77. umap/static/umap/locale/bg.json +11 -6
  78. umap/static/umap/locale/br.js +12 -7
  79. umap/static/umap/locale/br.json +12 -7
  80. umap/static/umap/locale/ca.js +11 -6
  81. umap/static/umap/locale/ca.json +11 -6
  82. umap/static/umap/locale/cs_CZ.js +11 -6
  83. umap/static/umap/locale/cs_CZ.json +11 -6
  84. umap/static/umap/locale/da.js +11 -6
  85. umap/static/umap/locale/da.json +11 -6
  86. umap/static/umap/locale/de.js +47 -42
  87. umap/static/umap/locale/de.json +47 -42
  88. umap/static/umap/locale/el.js +11 -6
  89. umap/static/umap/locale/el.json +11 -6
  90. umap/static/umap/locale/en.js +11 -6
  91. umap/static/umap/locale/en.json +11 -6
  92. umap/static/umap/locale/en_US.json +11 -6
  93. umap/static/umap/locale/es.js +11 -6
  94. umap/static/umap/locale/es.json +11 -6
  95. umap/static/umap/locale/et.js +11 -6
  96. umap/static/umap/locale/et.json +11 -6
  97. umap/static/umap/locale/eu.js +11 -6
  98. umap/static/umap/locale/eu.json +11 -6
  99. umap/static/umap/locale/fa_IR.js +11 -6
  100. umap/static/umap/locale/fa_IR.json +11 -6
  101. umap/static/umap/locale/fi.js +11 -6
  102. umap/static/umap/locale/fi.json +11 -6
  103. umap/static/umap/locale/fr.js +11 -6
  104. umap/static/umap/locale/fr.json +11 -6
  105. umap/static/umap/locale/gl.js +12 -7
  106. umap/static/umap/locale/gl.json +12 -7
  107. umap/static/umap/locale/he.js +11 -6
  108. umap/static/umap/locale/he.json +11 -6
  109. umap/static/umap/locale/hr.js +11 -6
  110. umap/static/umap/locale/hr.json +11 -6
  111. umap/static/umap/locale/hu.js +25 -20
  112. umap/static/umap/locale/hu.json +25 -20
  113. umap/static/umap/locale/id.js +11 -6
  114. umap/static/umap/locale/id.json +11 -6
  115. umap/static/umap/locale/is.js +151 -146
  116. umap/static/umap/locale/is.json +151 -146
  117. umap/static/umap/locale/it.js +11 -6
  118. umap/static/umap/locale/it.json +11 -6
  119. umap/static/umap/locale/ja.js +11 -6
  120. umap/static/umap/locale/ja.json +11 -6
  121. umap/static/umap/locale/ko.js +11 -6
  122. umap/static/umap/locale/ko.json +11 -6
  123. umap/static/umap/locale/lt.js +11 -6
  124. umap/static/umap/locale/lt.json +11 -6
  125. umap/static/umap/locale/ms.js +11 -6
  126. umap/static/umap/locale/ms.json +11 -6
  127. umap/static/umap/locale/nl.js +12 -7
  128. umap/static/umap/locale/nl.json +12 -7
  129. umap/static/umap/locale/no.js +11 -6
  130. umap/static/umap/locale/no.json +11 -6
  131. umap/static/umap/locale/pl.js +11 -6
  132. umap/static/umap/locale/pl.json +11 -6
  133. umap/static/umap/locale/pl_PL.json +11 -6
  134. umap/static/umap/locale/pt.js +11 -6
  135. umap/static/umap/locale/pt.json +11 -6
  136. umap/static/umap/locale/pt_BR.js +11 -6
  137. umap/static/umap/locale/pt_BR.json +11 -6
  138. umap/static/umap/locale/pt_PT.js +11 -6
  139. umap/static/umap/locale/pt_PT.json +11 -6
  140. umap/static/umap/locale/ro.js +11 -6
  141. umap/static/umap/locale/ro.json +11 -6
  142. umap/static/umap/locale/ru.js +11 -6
  143. umap/static/umap/locale/ru.json +11 -6
  144. umap/static/umap/locale/sk_SK.js +11 -6
  145. umap/static/umap/locale/sk_SK.json +11 -6
  146. umap/static/umap/locale/sl.js +11 -6
  147. umap/static/umap/locale/sl.json +11 -6
  148. umap/static/umap/locale/sr.js +11 -6
  149. umap/static/umap/locale/sr.json +11 -6
  150. umap/static/umap/locale/sv.js +11 -6
  151. umap/static/umap/locale/sv.json +11 -6
  152. umap/static/umap/locale/th_TH.js +11 -6
  153. umap/static/umap/locale/th_TH.json +11 -6
  154. umap/static/umap/locale/tr.js +11 -6
  155. umap/static/umap/locale/tr.json +11 -6
  156. umap/static/umap/locale/uk_UA.js +11 -6
  157. umap/static/umap/locale/uk_UA.json +11 -6
  158. umap/static/umap/locale/vi.js +11 -6
  159. umap/static/umap/locale/vi.json +11 -6
  160. umap/static/umap/locale/vi_VN.json +11 -6
  161. umap/static/umap/locale/zh.js +11 -6
  162. umap/static/umap/locale/zh.json +11 -6
  163. umap/static/umap/locale/zh_CN.json +11 -6
  164. umap/static/umap/locale/zh_TW.Big5.json +11 -6
  165. umap/static/umap/locale/zh_TW.js +19 -14
  166. umap/static/umap/locale/zh_TW.json +19 -14
  167. umap/static/umap/map.css +58 -28
  168. umap/static/umap/unittests/sync.js +0 -57
  169. umap/static/umap/unittests/utils.js +47 -0
  170. umap/static/umap/vars.css +5 -2
  171. umap/static/umap/vendors/photon/leaflet.photon.js +3 -0
  172. umap/sync/payloads.py +3 -2
  173. umap/templates/auth/user_detail.html +1 -1
  174. umap/templates/auth/user_stars.html +1 -1
  175. umap/templates/umap/content.html +17 -12
  176. umap/templates/umap/home.html +7 -5
  177. umap/templates/umap/map_fragment.html +1 -1
  178. umap/templates/umap/map_list.html +20 -13
  179. umap/templates/umap/search.html +7 -3
  180. umap/templates/umap/search_bar.html +13 -11
  181. umap/templates/umap/team_detail.html +1 -1
  182. umap/tests/base.py +2 -1
  183. umap/tests/fixtures/remote_data.umap +55 -0
  184. umap/tests/fixtures/test_upload_data_with_iconurl.umap +122 -0
  185. umap/tests/integration/test_browser.py +1 -3
  186. umap/tests/integration/test_conditional_rules.py +3 -0
  187. umap/tests/integration/test_edit_datalayer.py +2 -7
  188. umap/tests/integration/test_edit_map.py +15 -0
  189. umap/tests/integration/test_edit_polygon.py +1 -2
  190. umap/tests/integration/test_import.py +59 -2
  191. umap/tests/integration/test_optimistic_merge.py +4 -3
  192. umap/tests/integration/test_owned_map.py +0 -1
  193. umap/tests/integration/test_save.py +2 -4
  194. umap/tests/integration/test_undo_redo.py +267 -0
  195. umap/tests/integration/test_websocket_sync.py +78 -11
  196. umap/tests/settings.py +1 -3
  197. umap/tests/test_datalayer_s3.py +1 -0
  198. umap/tests/test_map_views.py +1 -0
  199. umap/tests/test_views.py +34 -0
  200. umap/utils.py +1 -1
  201. umap/views.py +23 -2
  202. {umap_project-2.9.3.dist-info → umap_project-3.0.0.dist-info}/METADATA +13 -12
  203. {umap_project-2.9.3.dist-info → umap_project-3.0.0.dist-info}/RECORD +206 -208
  204. umap/static/umap/js/modules/saving.js +0 -52
  205. umap/static/umap/test/.eslintrc +0 -21
  206. umap/static/umap/test/DataLayer.js +0 -463
  207. umap/static/umap/test/Feature.js +0 -131
  208. umap/static/umap/test/Map.js +0 -37
  209. umap/static/umap/test/Marker.js +0 -126
  210. umap/static/umap/test/Polygon.js +0 -111
  211. umap/static/umap/test/Polyline.js +0 -286
  212. umap/static/umap/test/Util.js +0 -28
  213. umap/static/umap/test/_pre.js +0 -455
  214. umap/static/umap/test/index.html +0 -139
  215. {umap_project-2.9.3.dist-info → umap_project-3.0.0.dist-info}/WHEEL +0 -0
  216. {umap_project-2.9.3.dist-info → umap_project-3.0.0.dist-info}/entry_points.txt +0 -0
  217. {umap_project-2.9.3.dist-info → umap_project-3.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,7 +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
3
  import Dialog from './ui/dialog.js'
4
+ import * as Utils from './utils.js'
5
5
 
6
6
  const SHORTCUTS = {
7
7
  DRAW_MARKER: {
@@ -36,9 +36,13 @@ const SHORTCUTS = {
36
36
  shortcut: 'Modifier+F',
37
37
  label: translate('Search location'),
38
38
  },
39
- CANCEL: {
39
+ UNDO: {
40
40
  shortcut: 'Modifier+Z',
41
- label: translate('Cancel edits'),
41
+ label: translate('Cancel last edit'),
42
+ },
43
+ REDO: {
44
+ shortcut: 'Modifier+Shift+Z',
45
+ label: translate('Redo last edit'),
42
46
  },
43
47
  PREVIEW: {
44
48
  shortcut: 'Modifier+E',
@@ -135,14 +139,23 @@ const ENTRIES = {
135
139
  <li>${translate('# one hash for main heading')}</li>
136
140
  <li>${translate('## two hashes for second heading')}</li>
137
141
  <li>${translate('### three hashes for third heading')}</li>
142
+ <li>${translate('--- for a horizontal rule')}</li>
143
+ </ul>
144
+ <h4>${translate('Links')}</h4>
145
+ <ul>
138
146
  <li>${translate('Simple link: [[https://example.com]]')}</li>
139
147
  <li>${translate('Link with text: [[https://example.com|text of the link]]')}</li>
148
+ </ul>
149
+ <h4>${translate('Images')}</h4>
150
+ <ul>
140
151
  <li>${translate('Image: {{https://image.url.com}}')}</li>
141
152
  <li>${translate('Image with custom width (in px): {{https://image.url.com|width}}')}</li>
153
+ </ul>
154
+ <h4>${translate('Iframes')}</h4>
155
+ <ul>
142
156
  <li>${translate('Iframe: {{{https://iframe.url.com}}}')}</li>
143
157
  <li>${translate('Iframe with custom height (in px): {{{https://iframe.url.com|height}}}')}</li>
144
158
  <li>${translate('Iframe with custom height and width (in px): {{{https://iframe.url.com|height*width}}}')}</li>
145
- <li>${translate('--- for a horizontal rule')}</li>
146
159
  </ul>
147
160
  </div>
148
161
  `,
@@ -183,7 +196,7 @@ export default class Help {
183
196
  .split('+')
184
197
  .map((el) => `<kbd>${el}</kbd>`)
185
198
  .join('+')
186
- label += ` ${shortcut}`
199
+ label += ` <span class="nobr">${shortcut}</span>`
187
200
  } else {
188
201
  label += ` (${shortcut})`
189
202
  }
@@ -94,6 +94,9 @@ export default class Importer extends Utils.WithTemplate {
94
94
  case 'datasets':
95
95
  import('./importers/datasets.js').then(register)
96
96
  break
97
+ case 'banfr':
98
+ import('./importers/banfr.js').then(register)
99
+ break
97
100
  }
98
101
  }
99
102
  }
@@ -173,7 +176,7 @@ export default class Importer extends Utils.WithTemplate {
173
176
  showImporters() {
174
177
  if (!this.IMPORTERS.length) return
175
178
  const [element, { grid }] = Utils.loadTemplateWithRefs(GRID_TEMPLATE)
176
- for (const plugin of this.IMPORTERS.sort((a, b) => (a.id > b.id ? 1 : -1))) {
179
+ for (const plugin of this.IMPORTERS.sort((a, b) => (a.name > b.name ? 1 : -1))) {
177
180
  const button = Utils.loadTemplate(
178
181
  `<li><button type="button" class="${plugin.id}">${plugin.name}</button></li>`
179
182
  )
@@ -246,7 +249,7 @@ export default class Importer extends Utils.WithTemplate {
246
249
  tagName: 'option',
247
250
  parent: layerSelect,
248
251
  textContent: datalayer.options.name,
249
- value: L.stamp(datalayer),
252
+ value: datalayer.id,
250
253
  })
251
254
  }
252
255
  })
@@ -0,0 +1,93 @@
1
+ import { DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
2
+ import { uMapAlert as Alert } from '../../components/alerts/alert.js'
3
+ import { BaseAjax, SingleMixin } from '../autocomplete.js'
4
+ import { translate } from '../i18n.js'
5
+ import * as Utils from '../utils.js'
6
+ import { AutocompleteCommunes } from './communesfr.js'
7
+
8
+ const TEMPLATE = `
9
+ <div>
10
+ <h3>Géocodage d’adresses en France</h3>
11
+ <p>Géocoder un fichier CSV avec la base adresse nationale.</p>
12
+ <fieldset class="formbox">
13
+ <legend>Choisir un fichier CSV (encodé en UTF-8)</legend>
14
+ <input type=file name=file data-ref=csvFile accept=".csv" />
15
+ </fieldset>
16
+ <fieldset class="formbox">
17
+ <legend>Aperçu des données</legend>
18
+ <table class="table-scrollable" data-ref=table></table>
19
+ </fieldset>
20
+ <fieldset class="formbox">
21
+ <legend>Sélectionner les colonnes à utiliser</legend>
22
+ <span data-ref="columns"></span>
23
+ </fieldset>
24
+ </div>
25
+ `
26
+
27
+ export class Importer {
28
+ constructor(umap, options) {
29
+ this._umap = umap
30
+ this.name = options.name || 'Géocodage FR'
31
+ this.id = 'banfr'
32
+ }
33
+
34
+ async open(importer) {
35
+ let data
36
+ const [container, { table, columns, csvFile }] =
37
+ Utils.loadTemplateWithRefs(TEMPLATE)
38
+ csvFile.addEventListener('change', () => {
39
+ const reader = new FileReader()
40
+ reader.onload = (evt) => {
41
+ data = evt.target.result
42
+ const rows = csv2geojson.auto(data).slice(0, 5)
43
+ const cols = Object.keys(rows[0])
44
+ table.innerHTML = ''
45
+ columns.innerHTML = ''
46
+ const tr = document.createElement('tr')
47
+ for (const column of cols) {
48
+ tr.appendChild(Utils.loadTemplate(`<th>${column}</th>`))
49
+ columns.appendChild(
50
+ Utils.loadTemplate(
51
+ `<label><input type="checkbox" value="${column}" /> ${column}</label>`
52
+ )
53
+ )
54
+ }
55
+ table.appendChild(tr)
56
+ for (const row of rows) {
57
+ const tr = document.createElement('tr')
58
+ for (const column of cols) {
59
+ tr.appendChild(Utils.loadTemplate(`<td>${row[column]}</td>`))
60
+ }
61
+ table.appendChild(tr)
62
+ }
63
+ }
64
+ reader.readAsText(csvFile.files[0])
65
+ })
66
+
67
+ const confirm = async (form) => {
68
+ const formData = new FormData()
69
+ formData.append('data', csvFile.files[0])
70
+ for (const option of columns.querySelectorAll('input:checked')) {
71
+ formData.append('columns', option.value)
72
+ }
73
+ const response = await this._umap.request.post(
74
+ 'https://api-adresse.data.gouv.fr/search/csv/',
75
+ {},
76
+ formData
77
+ )
78
+ if (response?.ok) {
79
+ importer.raw = await response.text()
80
+ importer.format = 'csv'
81
+ }
82
+ }
83
+
84
+ importer.dialog
85
+ .open({
86
+ template: container,
87
+ className: `${this.id} importer dark`,
88
+ cancel: false,
89
+ accept: translate('Geocode'),
90
+ })
91
+ .then(confirm)
92
+ }
93
+ }
@@ -1,9 +1,9 @@
1
1
  import { DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
2
+ import { uMapAlert as Alert } from '../../components/alerts/alert.js'
2
3
  import { BaseAjax, SingleMixin } from '../autocomplete.js'
4
+ import { translate } from '../i18n.js'
3
5
  import * as Util from '../utils.js'
4
6
  import { AutocompleteCommunes } from './communesfr.js'
5
- import { translate } from '../i18n.js'
6
- import { uMapAlert as Alert } from '../../components/alerts/alert.js'
7
7
 
8
8
  const TEMPLATE = `
9
9
  <h3>Cadastre</h3>
@@ -15,7 +15,7 @@ export class AutocompleteCommunes extends SingleMixin(BaseAjax) {
15
15
  let options = { q: encodeURIComponent(value) }
16
16
  const re = /^(0[1-9]|[1-9][ABab\d])\d{3}$/gm
17
17
  if (re.test(value)) {
18
- url = "https://geo.api.gouv.fr/communes?code={code}&limit=5"
18
+ url = 'https://geo.api.gouv.fr/communes?code={code}&limit=5'
19
19
  options = { code: encodeURIComponent(value) }
20
20
  }
21
21
  return Util.template(url, options)
@@ -1,18 +1,16 @@
1
1
  import { DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
2
- import { translate } from './i18n.js'
3
2
  import { uMapAlert as Alert } from '../components/alerts/alert.js'
4
- import { ServerStored } from './saving.js'
5
- import * as Utils from './utils.js'
6
3
  import { MutatingForm } from './form/builder.js'
4
+ import { translate } from './i18n.js'
5
+ import * as Utils from './utils.js'
7
6
 
8
7
  // Dedicated object so we can deal with a separate dirty status, and thus
9
8
  // call the endpoint only when needed, saving one call at each save.
10
- export class MapPermissions extends ServerStored {
9
+ export class MapPermissions {
11
10
  constructor(umap) {
12
- super()
13
11
  this.setProperties(umap.properties.permissions)
14
12
  this._umap = umap
15
- this._isDirty = false
13
+ this.sync = umap.syncEngine.proxy(this)
16
14
  }
17
15
 
18
16
  setProperties(properties) {
@@ -28,6 +26,13 @@ export class MapPermissions extends ServerStored {
28
26
  )
29
27
  }
30
28
 
29
+ getSyncMetadata() {
30
+ return {
31
+ subject: 'mappermissions',
32
+ metadata: {},
33
+ }
34
+ }
35
+
31
36
  render() {
32
37
  this._umap.render(['properties.permissions'])
33
38
  }
@@ -188,7 +193,6 @@ export class MapPermissions extends ServerStored {
188
193
  }
189
194
 
190
195
  async save() {
191
- if (!this.isDirty) return
192
196
  const formData = new FormData()
193
197
  if (!this.isAnonymousMap() && this.properties.editors) {
194
198
  const editors = this.properties.editors.map((u) => u.id)
@@ -247,9 +251,8 @@ export class MapPermissions extends ServerStored {
247
251
  }
248
252
  }
249
253
 
250
- export class DataLayerPermissions extends ServerStored {
254
+ export class DataLayerPermissions {
251
255
  constructor(umap, datalayer) {
252
- super()
253
256
  this._umap = umap
254
257
  this.properties = Object.assign(
255
258
  {
@@ -259,6 +262,14 @@ export class DataLayerPermissions extends ServerStored {
259
262
  )
260
263
 
261
264
  this.datalayer = datalayer
265
+ this.sync = umap.syncEngine.proxy(this)
266
+ }
267
+
268
+ getSyncMetadata() {
269
+ return {
270
+ subject: 'datalayerpermissions',
271
+ metadata: { id: this.datalayer.id },
272
+ }
262
273
  }
263
274
 
264
275
  edit(container) {
@@ -289,7 +300,6 @@ export class DataLayerPermissions extends ServerStored {
289
300
  }
290
301
 
291
302
  async save() {
292
- if (!this.isDirty) return
293
303
  const formData = new FormData()
294
304
  formData.append('edit_status', this.properties.edit_status)
295
305
  const [data, response, error] = await this._umap.server.post(
@@ -1,11 +1,11 @@
1
1
  import {
2
+ DivIcon,
2
3
  DomEvent,
3
4
  DomUtil,
4
- DivIcon,
5
5
  Icon,
6
6
  } from '../../../vendors/leaflet/leaflet-src.esm.js'
7
- import * as Utils from '../utils.js'
8
7
  import { SCHEMA } from '../schema.js'
8
+ import * as Utils from '../utils.js'
9
9
 
10
10
  export function getClass(name) {
11
11
  switch (name) {
@@ -15,6 +15,8 @@ export function getClass(name) {
15
15
  return Ball
16
16
  case 'Drop':
17
17
  return Drop
18
+ case 'Raw':
19
+ return Raw
18
20
  default:
19
21
  return DefaultIcon
20
22
  }
@@ -152,6 +154,17 @@ const Circle = BaseIcon.extend({
152
154
  },
153
155
  })
154
156
 
157
+ const Raw = DefaultIcon.extend({
158
+ default_options: {
159
+ iconSize: new L.Point(48, 48),
160
+ popupAnchor: new L.Point(0, 0),
161
+ tooltipAnchor: new L.Point(0, 0),
162
+ className: 'umap-raw-icon',
163
+ },
164
+
165
+ _getColor: () => 'transparent',
166
+ })
167
+
155
168
  const Drop = DefaultIcon.extend({
156
169
  default_options: {
157
170
  iconAnchor: new L.Point(16, 42),
@@ -1,9 +1,9 @@
1
- import { FeatureGroup, DomUtil } from '../../../../vendors/leaflet/leaflet-src.esm.js'
1
+ import colorbrewer from '../../../../vendors/colorbrewer/colorbrewer.js'
2
+ import { DomUtil, FeatureGroup } from '../../../../vendors/leaflet/leaflet-src.esm.js'
2
3
  import { translate } from '../../i18n.js'
3
- import { LayerMixin } from './base.js'
4
4
  import * as Utils from '../../utils.js'
5
5
  import { CircleMarker } from '../ui.js'
6
- import colorbrewer from '../../../../vendors/colorbrewer/colorbrewer.js'
6
+ import { LayerMixin } from './base.js'
7
7
 
8
8
  // Layer where each feature color is relative to the others,
9
9
  // so we need all features before behing able to set one
@@ -117,7 +117,7 @@ export const Choropleth = FeatureGroup.extend({
117
117
  },
118
118
 
119
119
  _getValue: function (feature) {
120
- const key = this.datalayer.options.choropleth.property || 'value'
120
+ const key = this.datalayer.options.choropleth?.property || 'value'
121
121
  const value = +feature.properties[key]
122
122
  if (!Number.isNaN(value)) return value
123
123
  },
@@ -130,12 +130,12 @@ export const Choropleth = FeatureGroup.extend({
130
130
  this.options.colors = []
131
131
  return
132
132
  }
133
- const mode = this.datalayer.options.choropleth.mode
134
- let classes = +this.datalayer.options.choropleth.classes || 5
133
+ const mode = this.datalayer.options.choropleth?.mode
134
+ let classes = +this.datalayer.options.choropleth?.classes || 5
135
135
  let breaks
136
136
  classes = Math.min(classes, values.length)
137
137
  if (mode === 'manual') {
138
- const manualBreaks = this.datalayer.options.choropleth.breaks
138
+ const manualBreaks = this.datalayer.options.choropleth?.breaks
139
139
  if (manualBreaks) {
140
140
  breaks = manualBreaks
141
141
  .split(',')
@@ -1,10 +1,10 @@
1
+ import { Evented } from '../../../../vendors/leaflet/leaflet-src.esm.js'
1
2
  // WARNING must be loaded dynamically, or at least after leaflet.markercluster
2
3
  // Uses global L.MarkerCluster and L.MarkerClusterGroup, not exposed as ESM
3
4
  import { translate } from '../../i18n.js'
4
- import { LayerMixin } from './base.js'
5
5
  import * as Utils from '../../utils.js'
6
- import { Evented } from '../../../../vendors/leaflet/leaflet-src.esm.js'
7
6
  import { Cluster as ClusterIcon } from '../icon.js'
7
+ import { LayerMixin } from './base.js'
8
8
 
9
9
  const MarkerCluster = L.MarkerCluster.extend({
10
10
  // Custom class so we can call computeTextColor
@@ -1,14 +1,14 @@
1
1
  // Uses global L.HeatLayer, not exposed as ESM
2
2
  import {
3
- Marker,
3
+ Bounds,
4
4
  LatLng,
5
+ Marker,
5
6
  latLngBounds,
6
- Bounds,
7
7
  point,
8
8
  } from '../../../../vendors/leaflet/leaflet-src.esm.js'
9
- import { LayerMixin } from './base.js'
10
- import * as Utils from '../../utils.js'
11
9
  import { translate } from '../../i18n.js'
10
+ import * as Utils from '../../utils.js'
11
+ import { LayerMixin } from './base.js'
12
12
 
13
13
  export const Heat = L.HeatLayer.extend({
14
14
  statics: {
@@ -1,18 +1,18 @@
1
1
  // Goes here all code related to Leaflet, DOM and user interactions.
2
2
  import {
3
3
  Map as BaseMap,
4
- DomUtil,
4
+ Control,
5
5
  DomEvent,
6
- latLngBounds,
6
+ DomUtil,
7
7
  latLng,
8
- Control,
8
+ latLngBounds,
9
9
  setOptions,
10
10
  } from '../../../vendors/leaflet/leaflet-src.esm.js'
11
- import { translate } from '../i18n.js'
12
11
  import { uMapAlert as Alert } from '../../components/alerts/alert.js'
12
+ import DropControl from '../drop.js'
13
+ import { translate } from '../i18n.js'
13
14
  import * as Utils from '../utils.js'
14
15
  import * as Icon from './icon.js'
15
- import DropControl from '../drop.js'
16
16
 
17
17
  // Those options are not saved on the server, so they can live here
18
18
  // instead of in umap.properties
@@ -91,6 +91,10 @@ const ControlsMixin = {
91
91
  }
92
92
  if (this.options.noControl) return
93
93
 
94
+ // Do not display in an iframe.
95
+ if (window.self === window.top) {
96
+ this._controls.home = new U.HomeControl().addTo(this)
97
+ }
94
98
  this._controls.attribution = new U.AttributionControl().addTo(this)
95
99
  if (this.options.miniMap) {
96
100
  this.whenReady(function () {
@@ -265,8 +269,12 @@ export const LeafletMap = BaseMap.extend({
265
269
  this.renderUI()
266
270
  },
267
271
 
268
- renderUI: function () {
272
+ pullProperties() {
269
273
  setOptions(this, this._umap.properties)
274
+ },
275
+
276
+ renderUI: function () {
277
+ this.pullProperties()
270
278
  if (this.options.scrollWheelZoom) {
271
279
  this.scrollWheelZoom.enable()
272
280
  this.dragging.enable()
@@ -1,11 +1,11 @@
1
1
  import {
2
+ Popup as BasePopup,
2
3
  DomEvent,
3
4
  DomUtil,
4
5
  Path,
5
- Popup as BasePopup,
6
6
  } from '../../../vendors/leaflet/leaflet-src.esm.js'
7
- import loadTemplate from './template.js'
8
7
  import Browser from '../browser.js'
8
+ import loadTemplate from './template.js'
9
9
 
10
10
  export default function loadPopup(name) {
11
11
  switch (name) {
@@ -1,8 +1,8 @@
1
- import { DomUtil, DomEvent } from '../../../vendors/leaflet/leaflet-src.esm.js'
2
- import { translate, getLocale } from '../i18n.js'
1
+ import { DomEvent, DomUtil } from '../../../vendors/leaflet/leaflet-src.esm.js'
2
+ import { getLocale, translate } from '../i18n.js'
3
+ import { Request } from '../request.js'
3
4
  import * as Utils from '../utils.js'
4
5
  import * as Icon from './icon.js'
5
- import { Request } from '../request.js'
6
6
 
7
7
  export default async function loadTemplate(name, feature, container) {
8
8
  let klass = PopupTemplate
@@ -1,18 +1,18 @@
1
1
  // Goes here all code related to Leaflet, DOM and user interactions.
2
2
  import {
3
- Marker,
4
- Polyline,
5
- Polygon,
6
3
  CircleMarker as BaseCircleMarker,
4
+ DomEvent,
7
5
  DomUtil,
8
- LineUtil,
9
- latLng,
10
6
  LatLng,
11
7
  LatLngBounds,
12
- DomEvent,
8
+ LineUtil,
9
+ Marker,
10
+ Polygon,
11
+ Polyline,
12
+ latLng,
13
13
  } from '../../../vendors/leaflet/leaflet-src.esm.js'
14
- import { translate } from '../i18n.js'
15
14
  import { uMapAlert as Alert } from '../../components/alerts/alert.js'
15
+ import { translate } from '../i18n.js'
16
16
  import * as Utils from '../utils.js'
17
17
  import * as Icon from './icon.js'
18
18
 
@@ -97,7 +97,6 @@ const FeatureMixin = {
97
97
  },
98
98
 
99
99
  onCommit: function () {
100
- this.feature.pullGeometry(false)
101
100
  this.feature.onCommit()
102
101
  },
103
102
  }
@@ -112,7 +111,7 @@ const PointMixin = {
112
111
  this.on('dragend', (event) => {
113
112
  this.isDirty = true
114
113
  this.feature.edit(event)
115
- this.feature.pullGeometry(false)
114
+ // this.feature.pullGeometry(false)
116
115
  })
117
116
  if (!this.feature.isReadOnly()) this.on('mouseover', this._enableDragging)
118
117
  this.on('mouseout', this._onMouseOut)
@@ -303,13 +302,13 @@ const PathMixin = {
303
302
  this._container = null
304
303
  FeatureMixin.onAdd.call(this, map)
305
304
  this.setStyle()
306
- if (this.editing?.enabled()) this.editing.addHooks()
305
+ if (this.editor?.enabled()) this.editor.addHooks()
307
306
  this.resetTooltip()
308
307
  this._path.dataset.feature = this.feature.id
309
308
  },
310
309
 
311
310
  onRemove: function (map) {
312
- if (this.editing?.enabled()) this.editing.removeHooks()
311
+ if (this.editor?.enabled()) this.editor.removeHooks()
313
312
  FeatureMixin.onRemove.call(this, map)
314
313
  },
315
314
 
@@ -362,6 +361,13 @@ const PathMixin = {
362
361
  isOnScreen: function (bounds) {
363
362
  return bounds.overlaps(this.getBounds())
364
363
  },
364
+
365
+ _setLatLngs: function (latlngs) {
366
+ this.parentClass.prototype._setLatLngs.call(this, latlngs)
367
+ if (this.editor?.enabled()) {
368
+ this.editor.reset()
369
+ }
370
+ },
365
371
  }
366
372
 
367
373
  export const LeafletPolyline = Polyline.extend({
@@ -1,9 +1,9 @@
1
1
  import { DomEvent, DomUtil, stamp } from '../../vendors/leaflet/leaflet-src.esm.js'
2
- import { translate } from './i18n.js'
3
- import * as Utils from './utils.js'
4
2
  import { AutocompleteDatalist } from './autocomplete.js'
5
- import Orderable from './orderable.js'
6
3
  import { MutatingForm } from './form/builder.js'
4
+ import { translate } from './i18n.js'
5
+ import Orderable from './orderable.js'
6
+ import * as Utils from './utils.js'
7
7
 
8
8
  const EMPTY_VALUES = ['', undefined, null]
9
9
 
@@ -17,20 +17,10 @@ class Rule {
17
17
  this.parse()
18
18
  }
19
19
 
20
- get isDirty() {
21
- return this._isDirty
22
- }
23
-
24
- set isDirty(status) {
25
- this._isDirty = status
26
- if (status) this._umap.isDirty = status
27
- }
28
-
29
20
  constructor(umap, condition = '', options = {}) {
30
21
  // TODO make this public properties when browser coverage is ok
31
22
  // cf https://caniuse.com/?search=public%20class%20field
32
23
  this._condition = null
33
- this._isDirty = false
34
24
  this.OPERATORS = [
35
25
  ['>', this.gt],
36
26
  ['<', this.lt],
@@ -190,17 +180,25 @@ class Rule {
190
180
 
191
181
  _delete() {
192
182
  this._umap.rules.rules = this._umap.rules.rules.filter((rule) => rule !== this)
183
+ this._umap.rules.commit()
184
+ }
185
+
186
+ setter(key, value) {
187
+ const oldRules = Utils.CopyJSON(this._umap.properties.rules || {})
188
+ Utils.setObjectValue(this, key, value)
189
+ this._umap.rules.commit()
190
+ this._umap.sync.update('properties.rules', this._umap.properties.rules, oldRules)
193
191
  }
194
192
  }
195
193
 
196
194
  export default class Rules {
197
195
  constructor(umap) {
198
196
  this._umap = umap
199
- this.rules = []
200
197
  this.load()
201
198
  }
202
199
 
203
200
  load() {
201
+ this.rules = []
204
202
  if (!this._umap.properties.rules?.length) return
205
203
  for (const { condition, options } of this._umap.properties.rules) {
206
204
  if (!condition) continue
@@ -222,8 +220,8 @@ export default class Rules {
222
220
  else if (finalIndex > initialIndex) newIdx = referenceIdx
223
221
  else newIdx = referenceIdx + 1
224
222
  this.rules.splice(newIdx, 0, moved)
225
- moved.isDirty = true
226
223
  this._umap.render(['rules'])
224
+ this.commit()
227
225
  }
228
226
 
229
227
  edit(container) {
@@ -242,7 +240,6 @@ export default class Rules {
242
240
 
243
241
  addRule() {
244
242
  const rule = new Rule(this._umap)
245
- rule.isDirty = true
246
243
  this.rules.push(rule)
247
244
  rule.edit(map)
248
245
  }