umap-project 2.5.1__py3-none-any.whl → 2.6.0b0__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 (193) hide show
  1. umap/__init__.py +1 -1
  2. umap/admin.py +6 -1
  3. umap/context_processors.py +2 -1
  4. umap/decorators.py +13 -2
  5. umap/forms.py +26 -2
  6. umap/locale/br/LC_MESSAGES/django.mo +0 -0
  7. umap/locale/br/LC_MESSAGES/django.po +252 -146
  8. umap/locale/ca/LC_MESSAGES/django.mo +0 -0
  9. umap/locale/ca/LC_MESSAGES/django.po +274 -162
  10. umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  11. umap/locale/cs_CZ/LC_MESSAGES/django.po +261 -150
  12. umap/locale/de/LC_MESSAGES/django.mo +0 -0
  13. umap/locale/de/LC_MESSAGES/django.po +299 -187
  14. umap/locale/el/LC_MESSAGES/django.mo +0 -0
  15. umap/locale/el/LC_MESSAGES/django.po +215 -159
  16. umap/locale/en/LC_MESSAGES/django.po +211 -155
  17. umap/locale/es/LC_MESSAGES/django.mo +0 -0
  18. umap/locale/es/LC_MESSAGES/django.po +255 -144
  19. umap/locale/eu/LC_MESSAGES/django.mo +0 -0
  20. umap/locale/eu/LC_MESSAGES/django.po +254 -198
  21. umap/locale/fa_IR/LC_MESSAGES/django.mo +0 -0
  22. umap/locale/fa_IR/LC_MESSAGES/django.po +346 -234
  23. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  24. umap/locale/fr/LC_MESSAGES/django.po +216 -160
  25. umap/locale/hu/LC_MESSAGES/django.mo +0 -0
  26. umap/locale/hu/LC_MESSAGES/django.po +215 -159
  27. umap/locale/it/LC_MESSAGES/django.mo +0 -0
  28. umap/locale/it/LC_MESSAGES/django.po +252 -146
  29. umap/locale/ms/LC_MESSAGES/django.mo +0 -0
  30. umap/locale/ms/LC_MESSAGES/django.po +252 -146
  31. umap/locale/pl/LC_MESSAGES/django.mo +0 -0
  32. umap/locale/pl/LC_MESSAGES/django.po +254 -148
  33. umap/locale/pt/LC_MESSAGES/django.mo +0 -0
  34. umap/locale/pt/LC_MESSAGES/django.po +215 -159
  35. umap/locale/sv/LC_MESSAGES/django.mo +0 -0
  36. umap/locale/sv/LC_MESSAGES/django.po +254 -143
  37. umap/locale/th_TH/LC_MESSAGES/django.mo +0 -0
  38. umap/locale/th_TH/LC_MESSAGES/django.po +125 -70
  39. umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
  40. umap/locale/zh_TW/LC_MESSAGES/django.po +256 -145
  41. umap/migrations/0022_add_team.py +94 -0
  42. umap/models.py +45 -10
  43. umap/settings/__init__.py +2 -0
  44. umap/settings/base.py +3 -2
  45. umap/static/umap/base.css +32 -41
  46. umap/static/umap/content.css +19 -25
  47. umap/static/umap/css/icon.css +63 -37
  48. umap/static/umap/css/importers.css +1 -1
  49. umap/static/umap/css/slideshow.css +7 -5
  50. umap/static/umap/css/tableeditor.css +4 -3
  51. umap/static/umap/img/16-white.svg +1 -4
  52. umap/static/umap/img/16.svg +2 -6
  53. umap/static/umap/img/24-white.svg +4 -4
  54. umap/static/umap/img/24.svg +6 -6
  55. umap/static/umap/img/source/16-white.svg +2 -5
  56. umap/static/umap/img/source/16.svg +3 -7
  57. umap/static/umap/img/source/24-white.svg +7 -14
  58. umap/static/umap/img/source/24.svg +10 -17
  59. umap/static/umap/js/components/alerts/alert.css +20 -8
  60. umap/static/umap/js/modules/autocomplete.js +3 -3
  61. umap/static/umap/js/modules/browser.js +4 -3
  62. umap/static/umap/js/modules/caption.js +9 -11
  63. umap/static/umap/js/modules/data/features.js +994 -0
  64. umap/static/umap/js/modules/data/layer.js +1210 -0
  65. umap/static/umap/js/modules/formatter.js +12 -3
  66. umap/static/umap/js/modules/global.js +21 -5
  67. umap/static/umap/js/modules/permissions.js +280 -0
  68. umap/static/umap/js/{umap.icon.js → modules/rendering/icon.js} +77 -56
  69. umap/static/umap/js/modules/rendering/layers/base.js +105 -0
  70. umap/static/umap/js/modules/rendering/layers/classified.js +484 -0
  71. umap/static/umap/js/modules/rendering/layers/cluster.js +103 -0
  72. umap/static/umap/js/modules/rendering/layers/heat.js +182 -0
  73. umap/static/umap/js/modules/rendering/popup.js +99 -0
  74. umap/static/umap/js/modules/rendering/template.js +217 -0
  75. umap/static/umap/js/modules/rendering/ui.js +573 -0
  76. umap/static/umap/js/modules/schema.js +24 -0
  77. umap/static/umap/js/modules/share.js +66 -45
  78. umap/static/umap/js/modules/sync/updaters.js +9 -10
  79. umap/static/umap/js/modules/tableeditor.js +7 -7
  80. umap/static/umap/js/modules/ui/dialog.js +8 -4
  81. umap/static/umap/js/modules/utils.js +22 -13
  82. umap/static/umap/js/umap.controls.js +79 -146
  83. umap/static/umap/js/umap.core.js +9 -9
  84. umap/static/umap/js/umap.forms.js +32 -12
  85. umap/static/umap/js/umap.js +65 -63
  86. umap/static/umap/locale/br.js +35 -35
  87. umap/static/umap/locale/br.json +35 -35
  88. umap/static/umap/locale/ca.js +50 -50
  89. umap/static/umap/locale/ca.json +50 -50
  90. umap/static/umap/locale/de.js +136 -136
  91. umap/static/umap/locale/de.json +136 -136
  92. umap/static/umap/locale/el.js +47 -47
  93. umap/static/umap/locale/el.json +47 -47
  94. umap/static/umap/locale/en.js +7 -1
  95. umap/static/umap/locale/en.json +7 -1
  96. umap/static/umap/locale/fa_IR.js +44 -44
  97. umap/static/umap/locale/fa_IR.json +44 -44
  98. umap/static/umap/locale/fr.js +8 -2
  99. umap/static/umap/locale/fr.json +8 -2
  100. umap/static/umap/locale/pt.js +17 -17
  101. umap/static/umap/locale/pt.json +17 -17
  102. umap/static/umap/locale/pt_PT.js +207 -207
  103. umap/static/umap/locale/pt_PT.json +207 -207
  104. umap/static/umap/locale/th_TH.js +25 -25
  105. umap/static/umap/locale/th_TH.json +25 -25
  106. umap/static/umap/map.css +107 -104
  107. umap/static/umap/nav.css +19 -10
  108. umap/static/umap/unittests/utils.js +230 -107
  109. umap/static/umap/vendors/csv2geojson/csv2geojson.js +62 -40
  110. umap/static/umap/vendors/markercluster/MarkerCluster.Default.css +1 -1
  111. umap/storage.py +1 -0
  112. umap/templates/404.html +5 -1
  113. umap/templates/500.html +3 -1
  114. umap/templates/auth/user_detail.html +8 -2
  115. umap/templates/auth/user_form.html +19 -10
  116. umap/templates/auth/user_stars.html +8 -2
  117. umap/templates/base.html +1 -0
  118. umap/templates/registration/login.html +18 -3
  119. umap/templates/umap/about.html +1 -0
  120. umap/templates/umap/about_summary.html +22 -7
  121. umap/templates/umap/components/alerts/alert.html +42 -21
  122. umap/templates/umap/content.html +2 -0
  123. umap/templates/umap/content_footer.html +6 -2
  124. umap/templates/umap/css.html +1 -0
  125. umap/templates/umap/dashboard_menu.html +15 -0
  126. umap/templates/umap/home.html +14 -4
  127. umap/templates/umap/js.html +4 -9
  128. umap/templates/umap/login_popup_end.html +10 -4
  129. umap/templates/umap/map_detail.html +8 -2
  130. umap/templates/umap/map_fragment.html +3 -1
  131. umap/templates/umap/map_init.html +2 -1
  132. umap/templates/umap/map_list.html +4 -3
  133. umap/templates/umap/map_table.html +36 -12
  134. umap/templates/umap/messages.html +0 -1
  135. umap/templates/umap/navigation.html +2 -1
  136. umap/templates/umap/password_change.html +5 -1
  137. umap/templates/umap/password_change_done.html +8 -2
  138. umap/templates/umap/search.html +8 -2
  139. umap/templates/umap/search_bar.html +1 -0
  140. umap/templates/umap/team_confirm_delete.html +19 -0
  141. umap/templates/umap/team_detail.html +27 -0
  142. umap/templates/umap/team_form.html +60 -0
  143. umap/templates/umap/user_dashboard.html +7 -9
  144. umap/templates/umap/user_teams.html +51 -0
  145. umap/tests/base.py +8 -1
  146. umap/tests/conftest.py +6 -0
  147. umap/tests/fixtures/test_circles_layer.geojson +219 -0
  148. umap/tests/fixtures/test_upload_georss.xml +20 -0
  149. umap/tests/integration/conftest.py +18 -4
  150. umap/tests/integration/helpers.py +12 -0
  151. umap/tests/integration/test_anonymous_owned_map.py +23 -0
  152. umap/tests/integration/test_basics.py +29 -0
  153. umap/tests/integration/test_caption.py +20 -0
  154. umap/tests/integration/test_circles_layer.py +69 -0
  155. umap/tests/integration/test_draw_polygon.py +110 -13
  156. umap/tests/integration/test_draw_polyline.py +8 -18
  157. umap/tests/integration/test_edit_datalayer.py +1 -1
  158. umap/tests/integration/test_import.py +64 -5
  159. umap/tests/integration/test_owned_map.py +21 -13
  160. umap/tests/integration/test_team.py +47 -0
  161. umap/tests/integration/test_tilelayer.py +19 -2
  162. umap/tests/integration/test_view_marker.py +28 -1
  163. umap/tests/integration/test_websocket_sync.py +5 -5
  164. umap/tests/test_datalayer.py +32 -7
  165. umap/tests/test_datalayer_views.py +1 -1
  166. umap/tests/test_map.py +30 -4
  167. umap/tests/test_map_views.py +2 -2
  168. umap/tests/test_statics.py +40 -0
  169. umap/tests/test_team_views.py +131 -0
  170. umap/tests/test_views.py +15 -1
  171. umap/urls.py +23 -13
  172. umap/views.py +116 -10
  173. {umap_project-2.5.1.dist-info → umap_project-2.6.0b0.dist-info}/METADATA +9 -9
  174. {umap_project-2.5.1.dist-info → umap_project-2.6.0b0.dist-info}/RECORD +177 -170
  175. umap/static/umap/js/umap.datalayer.permissions.js +0 -70
  176. umap/static/umap/js/umap.features.js +0 -1290
  177. umap/static/umap/js/umap.layer.js +0 -1837
  178. umap/static/umap/js/umap.permissions.js +0 -208
  179. umap/static/umap/js/umap.popup.js +0 -341
  180. umap/static/umap/test/TableEditor.js +0 -104
  181. umap/static/umap/vendors/leaflet/leaflet-src.js +0 -14512
  182. umap/static/umap/vendors/leaflet/leaflet-src.js.map +0 -1
  183. umap/static/umap/vendors/leaflet/leaflet.js +0 -6
  184. umap/static/umap/vendors/leaflet/leaflet.js.map +0 -1
  185. umap/static/umap/vendors/markercluster/WhereAreTheJavascriptFiles.txt +0 -5
  186. umap/static/umap/vendors/markercluster/leaflet.markercluster-src.js +0 -2718
  187. umap/static/umap/vendors/markercluster/leaflet.markercluster-src.js.map +0 -1
  188. umap/static/umap/vendors/toolbar/leaflet.toolbar-src.css +0 -117
  189. umap/static/umap/vendors/toolbar/leaflet.toolbar-src.js +0 -365
  190. umap/tests/integration/test_statics.py +0 -47
  191. {umap_project-2.5.1.dist-info → umap_project-2.6.0b0.dist-info}/WHEEL +0 -0
  192. {umap_project-2.5.1.dist-info → umap_project-2.6.0b0.dist-info}/entry_points.txt +0 -0
  193. {umap_project-2.5.1.dist-info → umap_project-2.6.0b0.dist-info}/licenses/LICENSE +0 -0
@@ -22,7 +22,7 @@ export const EXPORT_FORMATS = {
22
22
  const table = []
23
23
  map.eachFeature((feature) => {
24
24
  const row = feature.toGeoJSON().properties
25
- const center = feature.getCenter()
25
+ const center = feature.center
26
26
  delete row._umap_options
27
27
  row.Latitude = center.lat
28
28
  row.Longitude = center.lng
@@ -38,7 +38,16 @@ export const EXPORT_FORMATS = {
38
38
  export class Formatter {
39
39
  async fromGPX(str) {
40
40
  const togeojson = await import('../../vendors/togeojson/togeojson.es.js')
41
- return togeojson.gpx(this.toDom(str))
41
+ const data = togeojson.gpx(this.toDom(str))
42
+ for (const feature of data.features || []) {
43
+ feature.properties.description = feature.properties.desc
44
+ for (const key in feature.properties) {
45
+ if (key.startsWith('_') || typeof feature.properties[key] === 'object') {
46
+ delete feature.properties[key]
47
+ }
48
+ }
49
+ }
50
+ return data
42
51
  }
43
52
 
44
53
  async fromKML(str) {
@@ -106,7 +115,7 @@ export class Formatter {
106
115
  }
107
116
 
108
117
  async fromGeoRSS(str) {
109
- return GeoRSSToGeoJSON(this.toDom(c))
118
+ return GeoRSSToGeoJSON(this.toDom(str))
110
119
  }
111
120
 
112
121
  toDom(x) {
@@ -1,9 +1,12 @@
1
1
  import {
2
2
  uMapAlert as Alert,
3
- uMapAlertConflict as AlertConflict,
4
3
  uMapAlertCreation as AlertCreation,
5
4
  } from '../components/alerts/alert.js'
6
- import { AjaxAutocomplete, AjaxAutocompleteMultiple, AutocompleteDatalist } from './autocomplete.js'
5
+ import {
6
+ AjaxAutocomplete,
7
+ AjaxAutocompleteMultiple,
8
+ AutocompleteDatalist,
9
+ } from './autocomplete.js'
7
10
  import Browser from './browser.js'
8
11
  import Caption from './caption.js'
9
12
  import Facets from './facets.js'
@@ -19,10 +22,14 @@ import Slideshow from './slideshow.js'
19
22
  import { SyncEngine } from './sync/engine.js'
20
23
  import Dialog from './ui/dialog.js'
21
24
  import { EditPanel, FullPanel, Panel } from './ui/panel.js'
22
- import TableEditor from './tableeditor.js'
23
25
  import Tooltip from './ui/tooltip.js'
24
26
  import URLs from './urls.js'
25
27
  import * as Utils from './utils.js'
28
+ import * as Icon from './rendering/icon.js'
29
+ import { DataLayer, LAYER_TYPES } from './data/layer.js'
30
+ import { DataLayerPermissions, MapPermissions } from './permissions.js'
31
+ import { Point, LineString, Polygon } from './data/features.js'
32
+ import { LeafletMarker, LeafletPolyline, LeafletPolygon } from './rendering/ui.js'
26
33
 
27
34
  // Import modules and export them to the global scope.
28
35
  // For the not yet module-compatible JS out there.
@@ -31,12 +38,13 @@ import * as Utils from './utils.js'
31
38
  window.U = {
32
39
  Alert,
33
40
  AlertCreation,
34
- AlertConflict,
35
41
  AjaxAutocomplete,
36
42
  AjaxAutocompleteMultiple,
37
43
  AutocompleteDatalist,
38
44
  Browser,
39
45
  Caption,
46
+ DataLayer,
47
+ DataLayerPermissions,
40
48
  Dialog,
41
49
  EditPanel,
42
50
  Facets,
@@ -44,10 +52,19 @@ window.U = {
44
52
  FullPanel,
45
53
  Help,
46
54
  HTTPError,
55
+ Icon,
47
56
  Importer,
57
+ LAYER_TYPES,
58
+ LeafletMarker,
59
+ LeafletPolygon,
60
+ LeafletPolyline,
61
+ LineString,
62
+ MapPermissions,
48
63
  NOKError,
49
64
  Orderable,
50
65
  Panel,
66
+ Point,
67
+ Polygon,
51
68
  Request,
52
69
  RequestError,
53
70
  Rules,
@@ -56,7 +73,6 @@ window.U = {
56
73
  Share,
57
74
  Slideshow,
58
75
  SyncEngine,
59
- TableEditor,
60
76
  Tooltip,
61
77
  URLs,
62
78
  Utils,
@@ -0,0 +1,280 @@
1
+ import { DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
2
+ import { translate } from './i18n.js'
3
+ import { uMapAlert as Alert } from '../components/alerts/alert.js'
4
+ import * as Utils from './utils.js'
5
+
6
+ // Dedicated object so we can deal with a separate dirty status, and thus
7
+ // call the endpoint only when needed, saving one call at each save.
8
+ export class MapPermissions {
9
+ constructor(map) {
10
+ this.setOptions(map.options.permissions)
11
+ this.map = map
12
+ this._isDirty = false
13
+ }
14
+
15
+ set isDirty(status) {
16
+ this._isDirty = status
17
+ if (status) this.map.isDirty = status
18
+ }
19
+
20
+ get isDirty() {
21
+ return this._isDirty
22
+ }
23
+
24
+ setOptions(options) {
25
+ this.options = Object.assign(
26
+ {
27
+ owner: null,
28
+ team: null,
29
+ editors: [],
30
+ share_status: null,
31
+ edit_status: null,
32
+ },
33
+ options
34
+ )
35
+ }
36
+
37
+ isOwner() {
38
+ return Boolean(this.map.options.user?.is_owner)
39
+ }
40
+
41
+ isAnonymousMap() {
42
+ return !this.map.options.permissions.owner
43
+ }
44
+
45
+ getMap() {
46
+ return this.map
47
+ }
48
+
49
+ edit() {
50
+ if (this.map.options.editMode !== 'advanced') return
51
+ if (!this.map.options.umap_id) {
52
+ return Alert.info(translate('Please save the map first'))
53
+ }
54
+ const container = DomUtil.create('div', 'permissions-panel')
55
+ const fields = []
56
+ DomUtil.createTitle(container, translate('Update permissions'), 'icon-key')
57
+ if (this.isAnonymousMap()) {
58
+ if (this.options.anonymous_edit_url) {
59
+ const helpText = `${translate('Secret edit link:')}<br>${
60
+ this.options.anonymous_edit_url
61
+ }`
62
+ DomUtil.element({
63
+ tagName: 'p',
64
+ className: 'help-text',
65
+ innerHTML: helpText,
66
+ parent: container,
67
+ })
68
+ fields.push([
69
+ 'options.edit_status',
70
+ {
71
+ handler: 'IntSelect',
72
+ label: translate('Who can edit'),
73
+ selectOptions: this.map.options.edit_statuses,
74
+ helpText: helpText,
75
+ },
76
+ ])
77
+ }
78
+ } else {
79
+ if (this.isOwner()) {
80
+ fields.push([
81
+ 'options.edit_status',
82
+ {
83
+ handler: 'IntSelect',
84
+ label: translate('Who can edit'),
85
+ selectOptions: this.map.options.edit_statuses,
86
+ },
87
+ ])
88
+ fields.push([
89
+ 'options.share_status',
90
+ {
91
+ handler: 'IntSelect',
92
+ label: translate('Who can view'),
93
+ selectOptions: this.map.options.share_statuses,
94
+ },
95
+ ])
96
+ fields.push([
97
+ 'options.owner',
98
+ { handler: 'ManageOwner', label: translate("Map's owner") },
99
+ ])
100
+ if (this.map.options.user?.teams?.length) {
101
+ fields.push([
102
+ 'options.team',
103
+ {
104
+ handler: 'ManageTeam',
105
+ label: translate('Attach map to a team'),
106
+ teams: this.map.options.user.teams,
107
+ },
108
+ ])
109
+ }
110
+ }
111
+ fields.push([
112
+ 'options.editors',
113
+ { handler: 'ManageEditors', label: translate("Map's editors") },
114
+ ])
115
+ }
116
+
117
+ const builder = new U.FormBuilder(this, fields)
118
+ const form = builder.build()
119
+ container.appendChild(form)
120
+ if (this.isAnonymousMap() && this.map.options.user) {
121
+ // We have a user, and this user has come through here, so they can edit the map, so let's allow to own the map.
122
+ // Note: real check is made on the back office anyway.
123
+ const advancedActions = DomUtil.createFieldset(
124
+ container,
125
+ translate('Advanced actions')
126
+ )
127
+ const advancedButtons = DomUtil.create('div', 'button-bar', advancedActions)
128
+ DomUtil.createButton(
129
+ 'button',
130
+ advancedButtons,
131
+ translate('Attach the map to my account'),
132
+ this.attach,
133
+ this
134
+ )
135
+ }
136
+ DomUtil.add('h4', '', container, translate('Datalayers'))
137
+ this.map.eachDataLayer((datalayer) => {
138
+ datalayer.permissions.edit(container)
139
+ })
140
+ this.map.editPanel.open({ content: container, className: 'dark' })
141
+ }
142
+
143
+ async attach() {
144
+ const [data, response, error] = await this.map.server.post(this.getAttachUrl())
145
+ if (!error) {
146
+ this.options.owner = this.map.options.user
147
+ Alert.success(translate('Map has been attached to your account'))
148
+ this.map.editPanel.close()
149
+ }
150
+ }
151
+
152
+ async save() {
153
+ if (!this.isDirty) return this.map.continueSaving()
154
+ const formData = new FormData()
155
+ if (!this.isAnonymousMap() && this.options.editors) {
156
+ const editors = this.options.editors.map((u) => u.id)
157
+ for (let i = 0; i < this.options.editors.length; i++)
158
+ formData.append('editors', this.options.editors[i].id)
159
+ }
160
+ if (this.isOwner() || this.isAnonymousMap())
161
+ formData.append('edit_status', this.options.edit_status)
162
+ if (this.isOwner()) {
163
+ formData.append('owner', this.options.owner?.id)
164
+ formData.append('team', this.options.team?.id || '')
165
+ formData.append('share_status', this.options.share_status)
166
+ }
167
+ const [data, response, error] = await this.map.server.post(
168
+ this.getUrl(),
169
+ {},
170
+ formData
171
+ )
172
+ if (!error) {
173
+ this.commit()
174
+ this.isDirty = false
175
+ this.map.continueSaving()
176
+ this.map.fire('postsync')
177
+ }
178
+ }
179
+
180
+ getUrl() {
181
+ return Utils.template(this.map.options.urls.map_update_permissions, {
182
+ map_id: this.map.options.umap_id,
183
+ })
184
+ }
185
+
186
+ getAttachUrl() {
187
+ return Utils.template(this.map.options.urls.map_attach_owner, {
188
+ map_id: this.map.options.umap_id,
189
+ })
190
+ }
191
+
192
+ commit() {
193
+ this.map.options.permissions = Object.assign(
194
+ this.map.options.permissions,
195
+ this.options
196
+ )
197
+ }
198
+
199
+ getShareStatusDisplay() {
200
+ return Object.fromEntries(this.map.options.share_statuses)[
201
+ this.options.share_status
202
+ ]
203
+ }
204
+ }
205
+
206
+ export class DataLayerPermissions {
207
+ constructor(datalayer) {
208
+ this.options = Object.assign(
209
+ {
210
+ edit_status: null,
211
+ },
212
+ datalayer.options.permissions
213
+ )
214
+
215
+ this.datalayer = datalayer
216
+ this._isDirty = false
217
+ }
218
+
219
+ set isDirty(status) {
220
+ this._isDirty = status
221
+ if (status) this.datalayer.isDirty = status
222
+ }
223
+
224
+ get isDirty() {
225
+ return this._isDirty
226
+ }
227
+
228
+ getMap() {
229
+ return this.datalayer.map
230
+ }
231
+
232
+ edit(container) {
233
+ const fields = [
234
+ [
235
+ 'options.edit_status',
236
+ {
237
+ handler: 'IntSelect',
238
+ label: translate('Who can edit "{layer}"', {
239
+ layer: this.datalayer.getName(),
240
+ }),
241
+ selectOptions: this.datalayer.map.options.datalayer_edit_statuses,
242
+ },
243
+ ],
244
+ ]
245
+ const builder = new U.FormBuilder(this, fields, {
246
+ className: 'umap-form datalayer-permissions',
247
+ })
248
+ const form = builder.build()
249
+ container.appendChild(form)
250
+ }
251
+
252
+ getUrl() {
253
+ return Utils.template(this.datalayer.map.options.urls.datalayer_permissions, {
254
+ map_id: this.datalayer.map.options.umap_id,
255
+ pk: this.datalayer.umap_id,
256
+ })
257
+ }
258
+ async save() {
259
+ if (!this.isDirty) return this.datalayer.map.continueSaving()
260
+ const formData = new FormData()
261
+ formData.append('edit_status', this.options.edit_status)
262
+ const [data, response, error] = await this.datalayer.map.server.post(
263
+ this.getUrl(),
264
+ {},
265
+ formData
266
+ )
267
+ if (!error) {
268
+ this.commit()
269
+ this.isDirty = false
270
+ this.datalayer.map.continueSaving()
271
+ }
272
+ }
273
+
274
+ commit() {
275
+ this.datalayer.options.permissions = Object.assign(
276
+ this.datalayer.options.permissions,
277
+ this.options
278
+ )
279
+ }
280
+ }
@@ -1,16 +1,36 @@
1
- U.Icon = L.DivIcon.extend({
2
- statics: {
3
- RECENT: [],
4
- },
5
- initialize: function (map, options) {
6
- this.map = map
1
+ import {
2
+ DomEvent,
3
+ DomUtil,
4
+ DivIcon,
5
+ Icon,
6
+ } from '../../../vendors/leaflet/leaflet-src.esm.js'
7
+ import * as Utils from '../utils.js'
8
+ import { SCHEMA } from '../schema.js'
9
+
10
+ export function getClass(name) {
11
+ switch (name) {
12
+ case 'Circle':
13
+ return Circle
14
+ case 'Ball':
15
+ return Ball
16
+ case 'Drop':
17
+ return Drop
18
+ default:
19
+ return DefaultIcon
20
+ }
21
+ }
22
+
23
+ export const RECENT = []
24
+
25
+ const BaseIcon = L.DivIcon.extend({
26
+ initialize: function (options) {
7
27
  const default_options = {
8
28
  iconSize: null, // Made in css
9
- iconUrl: this.map.getDefaultOption('iconUrl'),
29
+ iconUrl: SCHEMA.iconUrl.default,
10
30
  feature: null,
11
31
  }
12
32
  options = L.Util.extend({}, default_options, options)
13
- L.Icon.prototype.initialize.call(this, options)
33
+ Icon.prototype.initialize.call(this, options)
14
34
  this.feature = this.options.feature
15
35
  if (this.feature?.isReadOnly()) {
16
36
  this.options.className += ' readonly'
@@ -18,10 +38,10 @@ U.Icon = L.DivIcon.extend({
18
38
  },
19
39
 
20
40
  _setRecent: (url) => {
21
- if (U.Utils.hasVar(url)) return
22
- if (url === U.SCHEMA.iconUrl.default) return
23
- if (U.Icon.RECENT.indexOf(url) === -1) {
24
- U.Icon.RECENT.push(url)
41
+ if (Utils.hasVar(url)) return
42
+ if (url === SCHEMA.iconUrl.default) return
43
+ if (RECENT.indexOf(url) === -1) {
44
+ RECENT.push(url)
25
45
  }
26
46
  },
27
47
 
@@ -33,29 +53,26 @@ U.Icon = L.DivIcon.extend({
33
53
  } else {
34
54
  url = this.options[`${name}Url`]
35
55
  }
36
- return this.formatUrl(url, this.feature)
56
+ return formatUrl(url, this.feature)
37
57
  },
38
58
 
39
59
  _getColor: function () {
40
60
  let color
41
61
  if (this.feature) color = this.feature.getDynamicOption('color')
42
62
  else if (this.options.color) color = this.options.color
43
- else color = this.map.getDefaultOption('color')
63
+ else color = SCHEMA.color.default
44
64
  return color
45
65
  },
46
66
 
47
67
  _getOpacity: function () {
48
68
  if (this.feature) return this.feature.getOption('iconOpacity')
49
- return this.map.getDefaultOption('iconOpacity')
69
+ return SCHEMA.iconOpacity.default
50
70
  },
51
71
 
52
- formatUrl: (url, feature) =>
53
- U.Utils.greedyTemplate(url || '', feature ? feature.extendedProperties() : {}),
54
-
55
72
  onAdd: () => {},
56
73
  })
57
74
 
58
- U.Icon.Default = U.Icon.extend({
75
+ const DefaultIcon = BaseIcon.extend({
59
76
  default_options: {
60
77
  iconAnchor: new L.Point(16, 40),
61
78
  popupAnchor: new L.Point(0, -40),
@@ -63,13 +80,13 @@ U.Icon.Default = U.Icon.extend({
63
80
  className: 'umap-div-icon',
64
81
  },
65
82
 
66
- initialize: function (map, options) {
83
+ initialize: function (options) {
67
84
  options = L.Util.extend({}, this.default_options, options)
68
- U.Icon.prototype.initialize.call(this, map, options)
85
+ BaseIcon.prototype.initialize.call(this, options)
69
86
  },
70
87
 
71
88
  _setIconStyles: function (img, name) {
72
- U.Icon.prototype._setIconStyles.call(this, img, name)
89
+ BaseIcon.prototype._setIconStyles.call(this, img, name)
73
90
  const color = this._getColor()
74
91
  const opacity = this._getOpacity()
75
92
  this.elements.container.style.backgroundColor = color
@@ -81,54 +98,56 @@ U.Icon.Default = U.Icon.extend({
81
98
  onAdd: function () {
82
99
  const src = this._getIconUrl('icon')
83
100
  const bgcolor = this._getColor()
84
- U.Icon.setIconContrast(this.elements.icon, this.elements.container, src, bgcolor)
101
+ setContrast(this.elements.icon, this.elements.container, src, bgcolor)
85
102
  },
86
103
 
87
104
  createIcon: function () {
88
105
  this.elements = {}
89
- this.elements.main = L.DomUtil.create('div')
90
- this.elements.container = L.DomUtil.create(
106
+ this.elements.main = DomUtil.create('div')
107
+ this.elements.container = DomUtil.create(
91
108
  'div',
92
109
  'icon_container',
93
110
  this.elements.main
94
111
  )
95
- this.elements.arrow = L.DomUtil.create('div', 'icon_arrow', this.elements.main)
112
+ this.elements.main.dataset.feature = this.feature?.id
113
+ this.elements.arrow = DomUtil.create('div', 'icon_arrow', this.elements.main)
96
114
  const src = this._getIconUrl('icon')
97
115
  if (src) {
98
- this.elements.icon = U.Icon.makeIconElement(src, this.elements.container)
116
+ this.elements.icon = makeElement(src, this.elements.container)
99
117
  }
100
118
  this._setIconStyles(this.elements.main, 'icon')
101
119
  return this.elements.main
102
120
  },
103
121
  })
104
122
 
105
- U.Icon.Circle = U.Icon.extend({
106
- initialize: function (map, options) {
123
+ const Circle = BaseIcon.extend({
124
+ initialize: function (options) {
107
125
  const default_options = {
108
126
  popupAnchor: new L.Point(0, -6),
109
127
  tooltipAnchor: new L.Point(6, 0),
110
128
  className: 'umap-circle-icon',
111
129
  }
112
130
  options = L.Util.extend({}, default_options, options)
113
- U.Icon.prototype.initialize.call(this, map, options)
131
+ BaseIcon.prototype.initialize.call(this, options)
114
132
  },
115
133
 
116
134
  _setIconStyles: function (img, name) {
117
- U.Icon.prototype._setIconStyles.call(this, img, name)
135
+ BaseIcon.prototype._setIconStyles.call(this, img, name)
118
136
  this.elements.main.style.backgroundColor = this._getColor()
119
137
  this.elements.main.style.opacity = this._getOpacity()
120
138
  },
121
139
 
122
140
  createIcon: function () {
123
141
  this.elements = {}
124
- this.elements.main = L.DomUtil.create('div')
142
+ this.elements.main = DomUtil.create('div')
125
143
  this.elements.main.innerHTML = '&nbsp;'
126
144
  this._setIconStyles(this.elements.main, 'icon')
145
+ this.elements.main.dataset.feature = this.feature?.id
127
146
  return this.elements.main
128
147
  },
129
148
  })
130
149
 
131
- U.Icon.Drop = U.Icon.Default.extend({
150
+ const Drop = DefaultIcon.extend({
132
151
  default_options: {
133
152
  iconAnchor: new L.Point(16, 42),
134
153
  popupAnchor: new L.Point(0, -42),
@@ -137,7 +156,7 @@ U.Icon.Drop = U.Icon.Default.extend({
137
156
  },
138
157
  })
139
158
 
140
- U.Icon.Ball = U.Icon.Default.extend({
159
+ const Ball = DefaultIcon.extend({
141
160
  default_options: {
142
161
  iconAnchor: new L.Point(8, 30),
143
162
  popupAnchor: new L.Point(0, -28),
@@ -147,19 +166,20 @@ U.Icon.Ball = U.Icon.Default.extend({
147
166
 
148
167
  createIcon: function () {
149
168
  this.elements = {}
150
- this.elements.main = L.DomUtil.create('div')
151
- this.elements.container = L.DomUtil.create(
169
+ this.elements.main = DomUtil.create('div')
170
+ this.elements.container = DomUtil.create(
152
171
  'div',
153
172
  'icon_container',
154
173
  this.elements.main
155
174
  )
156
- this.elements.arrow = L.DomUtil.create('div', 'icon_arrow', this.elements.main)
175
+ this.elements.main.dataset.feature = this.feature?.id
176
+ this.elements.arrow = DomUtil.create('div', 'icon_arrow', this.elements.main)
157
177
  this._setIconStyles(this.elements.main, 'icon')
158
178
  return this.elements.main
159
179
  },
160
180
 
161
181
  _setIconStyles: function (img, name) {
162
- U.Icon.prototype._setIconStyles.call(this, img, name)
182
+ BaseIcon.prototype._setIconStyles.call(this, img, name)
163
183
  const color = this._getColor('color')
164
184
  let background
165
185
  if (L.Browser.ielt9) {
@@ -174,7 +194,7 @@ U.Icon.Ball = U.Icon.Default.extend({
174
194
  },
175
195
  })
176
196
 
177
- U.Icon.Cluster = L.DivIcon.extend({
197
+ export const Cluster = DivIcon.extend({
178
198
  options: {
179
199
  iconSize: [40, 40],
180
200
  },
@@ -185,9 +205,9 @@ U.Icon.Cluster = L.DivIcon.extend({
185
205
  },
186
206
 
187
207
  createIcon: function () {
188
- const container = L.DomUtil.create('div', 'leaflet-marker-icon marker-cluster')
189
- const div = L.DomUtil.create('div', '', container)
190
- const span = L.DomUtil.create('span', '', div)
208
+ const container = DomUtil.create('div', 'leaflet-marker-icon marker-cluster')
209
+ const div = DomUtil.create('div', '', container)
210
+ const span = DomUtil.create('span', '', div)
191
211
  const backgroundColor = this.datalayer.getColor()
192
212
  span.textContent = this.cluster.getChildCount()
193
213
  div.style.backgroundColor = backgroundColor
@@ -200,27 +220,28 @@ U.Icon.Cluster = L.DivIcon.extend({
200
220
  if (this.datalayer.options.cluster?.textColor) {
201
221
  color = this.datalayer.options.cluster.textColor
202
222
  }
203
- return color || L.DomUtil.TextColorFromBackgroundColor(el, backgroundColor)
223
+ return color || DomUtil.TextColorFromBackgroundColor(el, backgroundColor)
204
224
  },
205
225
  })
206
226
 
207
- U.Icon.isImg = (src) =>
208
- U.Utils.isPath(src) || U.Utils.isRemoteUrl(src) || U.Utils.isDataImage(src)
227
+ export function isImg(src) {
228
+ return Utils.isPath(src) || Utils.isRemoteUrl(src) || Utils.isDataImage(src)
229
+ }
209
230
 
210
- U.Icon.makeIconElement = (src, parent) => {
231
+ export function makeElement(src, parent) {
211
232
  let icon
212
- if (U.Icon.isImg(src)) {
213
- icon = L.DomUtil.create('img')
233
+ if (isImg(src)) {
234
+ icon = DomUtil.create('img')
214
235
  icon.src = src
215
236
  } else {
216
- icon = L.DomUtil.create('span')
237
+ icon = DomUtil.create('span')
217
238
  icon.textContent = src
218
239
  }
219
240
  parent.appendChild(icon)
220
241
  return icon
221
242
  }
222
243
 
223
- U.Icon.setIconContrast = (icon, parent, src, bgcolor) => {
244
+ export function setContrast(icon, parent, src, bgcolor) {
224
245
  /*
225
246
  * icon: the element we'll adapt the style, it can be an image or text
226
247
  * parent: the element we'll consider to decide whether to adapt the style,
@@ -231,14 +252,10 @@ U.Icon.setIconContrast = (icon, parent, src, bgcolor) => {
231
252
  */
232
253
  if (!icon) return
233
254
 
234
- if (L.DomUtil.contrastedColor(parent, bgcolor)) {
255
+ if (DomUtil.contrastedColor(parent, bgcolor)) {
235
256
  // Decide whether to switch svg to white or not, but do it
236
257
  // only for internal SVG, as invert could do weird things
237
- if (
238
- U.Utils.isPath(src) &&
239
- src.endsWith('.svg') &&
240
- src !== U.SCHEMA.iconUrl.default
241
- ) {
258
+ if (Utils.isPath(src) && src.endsWith('.svg') && src !== SCHEMA.iconUrl.default) {
242
259
  // Must be called after icon container is added to the DOM
243
260
  // An image
244
261
  icon.style.filter = 'invert(1)'
@@ -248,3 +265,7 @@ U.Icon.setIconContrast = (icon, parent, src, bgcolor) => {
248
265
  }
249
266
  }
250
267
  }
268
+
269
+ export function formatUrl(url, feature) {
270
+ return Utils.greedyTemplate(url || '', feature ? feature.extendedProperties() : {})
271
+ }