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
@@ -0,0 +1,182 @@
1
+ // Uses global L.HeatLayer, not exposed as ESM
2
+ import {
3
+ Marker,
4
+ LatLng,
5
+ latLngBounds,
6
+ Bounds,
7
+ point,
8
+ } from '../../../../vendors/leaflet/leaflet-src.esm.js'
9
+ import { LayerMixin } from './base.js'
10
+ import * as Utils from '../../utils.js'
11
+ import { translate } from '../../i18n.js'
12
+
13
+ export const Heat = L.HeatLayer.extend({
14
+ statics: {
15
+ NAME: translate('Heatmap'),
16
+ TYPE: 'Heat',
17
+ },
18
+ includes: [LayerMixin],
19
+ browsable: false,
20
+
21
+ initialize: function (datalayer) {
22
+ this.datalayer = datalayer
23
+ L.HeatLayer.prototype.initialize.call(this, [], this.datalayer.options.heat)
24
+ LayerMixin.onInit.call(this, this.datalayer.map)
25
+ if (!Utils.isObject(this.datalayer.options.heat)) {
26
+ this.datalayer.options.heat = {}
27
+ }
28
+ },
29
+
30
+ addLayer: function (layer) {
31
+ if (layer instanceof Marker) {
32
+ let latlng = layer.getLatLng()
33
+ let alt
34
+ if (this.datalayer.options.heat?.intensityProperty) {
35
+ alt = Number.parseFloat(
36
+ layer.feature.properties[this.datalayer.options.heat.intensityProperty || 0]
37
+ )
38
+ latlng = new LatLng(latlng.lat, latlng.lng, alt)
39
+ }
40
+ this.addLatLng(latlng)
41
+ }
42
+ },
43
+
44
+ onAdd: function (map) {
45
+ LayerMixin.onAdd.call(this, map)
46
+ return L.HeatLayer.prototype.onAdd.call(this, map)
47
+ },
48
+
49
+ onRemove: function (map) {
50
+ LayerMixin.onRemove.call(this, map)
51
+ return L.HeatLayer.prototype.onRemove.call(this, map)
52
+ },
53
+
54
+ clearLayers: function () {
55
+ this.setLatLngs([])
56
+ },
57
+
58
+ getFeatures: () => ({}),
59
+
60
+ getBounds: function () {
61
+ return latLngBounds(this._latlngs)
62
+ },
63
+
64
+ getEditableOptions: () => [
65
+ [
66
+ 'options.heat.radius',
67
+ {
68
+ handler: 'Range',
69
+ min: 10,
70
+ max: 100,
71
+ step: 5,
72
+ label: translate('Heatmap radius'),
73
+ helpText: translate('Override heatmap radius (default 25)'),
74
+ },
75
+ ],
76
+ [
77
+ 'options.heat.intensityProperty',
78
+ {
79
+ handler: 'BlurInput',
80
+ placeholder: translate('Heatmap intensity property'),
81
+ helpText: translate('Optional intensity property for heatmap'),
82
+ },
83
+ ],
84
+ ],
85
+
86
+ onEdit: function (field, builder) {
87
+ if (field === 'options.heat.intensityProperty') {
88
+ this.datalayer.resetLayer(true) // We need to repopulate the latlngs
89
+ return
90
+ }
91
+ if (field === 'options.heat.radius') {
92
+ this.options.radius = this.datalayer.options.heat.radius
93
+ }
94
+ this._updateOptions()
95
+ },
96
+
97
+ redraw: function () {
98
+ // setlalngs call _redraw through setAnimFrame, thus async, so this
99
+ // can ends with race condition if we remove the layer very faslty after.
100
+ // TODO: PR in upstream Leaflet.heat
101
+ if (!this._map) return
102
+ L.HeatLayer.prototype.redraw.call(this)
103
+ },
104
+
105
+ _redraw: function () {
106
+ // Import patch from https://github.com/Leaflet/Leaflet.heat/pull/78
107
+ // Remove me when this get merged and released.
108
+ if (!this._map) {
109
+ return
110
+ }
111
+ const data = []
112
+ const r = this._heat._r
113
+ const size = this._map.getSize()
114
+ const bounds = new Bounds(point([-r, -r]), size.add([r, r]))
115
+ const cellSize = r / 2
116
+ const grid = []
117
+ const panePos = this._map._getMapPanePos()
118
+ const offsetX = panePos.x % cellSize
119
+ const offsetY = panePos.y % cellSize
120
+ let i
121
+ let len
122
+ let p
123
+ let cell
124
+ let x
125
+ let y
126
+ let j
127
+ let len2
128
+
129
+ this._max = 1
130
+
131
+ for (i = 0, len = this._latlngs.length; i < len; i++) {
132
+ p = this._map.latLngToContainerPoint(this._latlngs[i])
133
+ x = Math.floor((p.x - offsetX) / cellSize) + 2
134
+ y = Math.floor((p.y - offsetY) / cellSize) + 2
135
+
136
+ const alt =
137
+ this._latlngs[i].alt !== undefined
138
+ ? this._latlngs[i].alt
139
+ : this._latlngs[i][2] !== undefined
140
+ ? +this._latlngs[i][2]
141
+ : 1
142
+
143
+ grid[y] = grid[y] || []
144
+ cell = grid[y][x]
145
+
146
+ if (!cell) {
147
+ cell = grid[y][x] = [p.x, p.y, alt]
148
+ cell.p = p
149
+ } else {
150
+ cell[0] = (cell[0] * cell[2] + p.x * alt) / (cell[2] + alt) // x
151
+ cell[1] = (cell[1] * cell[2] + p.y * alt) / (cell[2] + alt) // y
152
+ cell[2] += alt // cumulated intensity value
153
+ }
154
+
155
+ // Set the max for the current zoom level
156
+ if (cell[2] > this._max) {
157
+ this._max = cell[2]
158
+ }
159
+ }
160
+
161
+ this._heat.max(this._max)
162
+
163
+ for (i = 0, len = grid.length; i < len; i++) {
164
+ if (grid[i]) {
165
+ for (j = 0, len2 = grid[i].length; j < len2; j++) {
166
+ cell = grid[i][j]
167
+ if (cell && bounds.contains(cell.p)) {
168
+ data.push([
169
+ Math.round(cell[0]),
170
+ Math.round(cell[1]),
171
+ Math.min(cell[2], this._max),
172
+ ])
173
+ }
174
+ }
175
+ }
176
+ }
177
+
178
+ this._heat.data(data).draw(this.options.minOpacity)
179
+
180
+ this._frame = null
181
+ },
182
+ })
@@ -0,0 +1,99 @@
1
+ import {
2
+ DomEvent,
3
+ DomUtil,
4
+ Path,
5
+ Popup as BasePopup,
6
+ } from '../../../vendors/leaflet/leaflet-src.esm.js'
7
+ import loadTemplate from './template.js'
8
+ import Browser from '../browser.js'
9
+
10
+ export default function loadPopup(name) {
11
+ switch (name) {
12
+ case 'Large':
13
+ return PopupLarge
14
+ case 'Panel':
15
+ return Panel
16
+ default:
17
+ return Popup
18
+ }
19
+ }
20
+
21
+ const Popup = BasePopup.extend({
22
+ initialize: function (feature) {
23
+ this.feature = feature
24
+ this.container = DomUtil.create('div', 'umap-popup')
25
+ this.format()
26
+ BasePopup.prototype.initialize.call(this, {}, feature)
27
+ this.setContent(this.container)
28
+ },
29
+
30
+ format: function () {
31
+ const name = this.feature.getOption('popupTemplate')
32
+ this.content = loadTemplate(name, this.feature, this.container)
33
+ const elements = this.container.querySelectorAll('img,iframe')
34
+ for (const element of elements) {
35
+ this.onElementLoaded(element)
36
+ }
37
+ if (!elements.length && this.container.textContent.replace('\n', '') === '') {
38
+ this.container.innerHTML = ''
39
+ DomUtil.add('h3', '', this.container, this.feature.getDisplayName())
40
+ }
41
+ },
42
+
43
+ onElementLoaded: function (el) {
44
+ DomEvent.on(el, 'load', () => {
45
+ this._updateLayout()
46
+ this._updatePosition()
47
+ this._adjustPan()
48
+ })
49
+ },
50
+ })
51
+
52
+ const PopupLarge = Popup.extend({
53
+ options: {
54
+ maxWidth: 500,
55
+ className: 'umap-popup-large',
56
+ },
57
+ })
58
+
59
+ const Panel = Popup.extend({
60
+ options: {
61
+ zoomAnimation: false,
62
+ },
63
+
64
+ onAdd: function (map) {
65
+ map.panel.setDefaultMode('expanded')
66
+ map.panel.open({
67
+ content: this._content,
68
+ actions: [Browser.backButton(map)],
69
+ })
70
+
71
+ // fire events as in base class Popup.js:onAdd
72
+ map.fire('popupopen', { popup: this })
73
+ if (this._source) {
74
+ this._source.fire('popupopen', { popup: this }, true)
75
+ if (!(this._source instanceof Path)) {
76
+ this._source.on('preclick', DomEvent.stopPropagation)
77
+ }
78
+ }
79
+ },
80
+
81
+ onRemove: function (map) {
82
+ map.panel.close()
83
+
84
+ // fire events as in base class Popup.js:onRemove
85
+ map.fire('popupclose', { popup: this })
86
+ if (this._source) {
87
+ this._source.fire('popupclose', { popup: this }, true)
88
+ if (!(this._source instanceof Path)) {
89
+ this._source.off('preclick', DomEvent.stopPropagation)
90
+ }
91
+ }
92
+ },
93
+
94
+ update: () => {},
95
+ _updateLayout: () => {},
96
+ _updatePosition: () => {},
97
+ _adjustPan: () => {},
98
+ _animateZoom: () => {},
99
+ })
@@ -0,0 +1,217 @@
1
+ import { DomUtil, DomEvent } from '../../../vendors/leaflet/leaflet-src.esm.js'
2
+ import { translate, getLocale } from '../i18n.js'
3
+ import * as Utils from '../utils.js'
4
+ import * as Icon from './icon.js'
5
+
6
+ export default function loadTemplate(name, feature, container) {
7
+ let klass = PopupTemplate
8
+ switch (name) {
9
+ case 'GeoRSSLink':
10
+ klass = GeoRSSLink
11
+ break
12
+ case 'GeoRSSImage':
13
+ klass = GeoRSSImage
14
+ break
15
+ case 'Table':
16
+ klass = Table
17
+ break
18
+ case 'OSM':
19
+ klass = OSM
20
+ break
21
+ }
22
+ const content = new klass()
23
+ return content.render(feature, container)
24
+ }
25
+
26
+ class PopupTemplate {
27
+ renderTitle(feature) {}
28
+
29
+ renderBody(feature) {
30
+ const template = feature.getOption('popupContentTemplate')
31
+ const target = feature.getOption('outlinkTarget')
32
+ const properties = feature.extendedProperties()
33
+ // Resolve properties inside description
34
+ properties.description = Utils.greedyTemplate(
35
+ feature.properties.description || '',
36
+ properties
37
+ )
38
+ let content = Utils.greedyTemplate(template, properties)
39
+ content = Utils.toHTML(content, { target: target })
40
+ return Utils.loadTemplate(`<div class="umap-popup-container text">${content}</div>`)
41
+ }
42
+
43
+ renderFooter(feature) {
44
+ if (feature.hasPopupFooter()) {
45
+ const template = `
46
+ <ul class="umap-popup-footer dark">
47
+ <li rel="prev"><button class="icon icon-16 icon-back" data-ref="previous"></button></li>
48
+ <li class="zoom" title="${translate('Zoom to this feature')}"><button class="icon icon-16 icon-zoom" data-ref="zoom"></button></li>
49
+ <li rel="next"><button class="icon icon-16 icon-forward" data-ref="next"></button></li>
50
+ </ul>`
51
+ const [footer, { previous, zoom, next }] = Utils.loadTemplateWithRefs(template)
52
+ const nextFeature = feature.getNext()
53
+ const previousFeature = feature.getPrevious()
54
+ // Fixme: remove me when this is merged and released
55
+ // https://github.com/Leaflet/Leaflet/pull/9052
56
+ DomEvent.disableClickPropagation(footer)
57
+ if (nextFeature) {
58
+ next.title = translate('Go to «{feature}»', {
59
+ feature: nextFeature.properties.name || translate('next'),
60
+ })
61
+ DomEvent.on(next, 'click', () => {
62
+ nextFeature.zoomTo({ callback: nextFeature.view })
63
+ })
64
+ }
65
+ if (previousFeature) {
66
+ previous.title = translate('Go to «{feature}»', {
67
+ feature: previousFeature.properties.name || translate('previous'),
68
+ })
69
+ DomEvent.on(previous, 'click', () => {
70
+ previousFeature.zoomTo({ callback: previousFeature.view })
71
+ })
72
+ }
73
+ DomEvent.on(zoom, 'click', () => feature.zoomTo())
74
+ return footer
75
+ }
76
+ }
77
+
78
+ render(feature, container) {
79
+ const title = this.renderTitle(feature)
80
+ if (title) container.appendChild(title)
81
+ const body = this.renderBody(feature)
82
+ if (body) DomUtil.add('div', 'umap-popup-content', container, body)
83
+ const footer = this.renderFooter(feature)
84
+ if (footer) container.appendChild(footer)
85
+ }
86
+ }
87
+ export const TitleMixin = (Base) =>
88
+ class extends Base {
89
+ renderTitle(feature) {
90
+ const title = feature.getDisplayName()
91
+ if (title) {
92
+ return Utils.loadTemplate(`<h3 class="popup-title">${title}</h3>`)
93
+ }
94
+ }
95
+ }
96
+
97
+ class Table extends TitleMixin(PopupTemplate) {
98
+ getValue(feature, key) {
99
+ // TODO, manage links (url, mailto, wikipedia...)
100
+ const value = Utils.escapeHTML(feature.properties[key]).trim()
101
+ if (value.indexOf('http') === 0) {
102
+ return `<a href="${value}" target="_blank">${value}</a>`
103
+ }
104
+ return value
105
+ }
106
+
107
+ makeRow(feature, key) {
108
+ return Utils.loadTemplate(
109
+ `<tr><th>${key}</th><td>${this.getValue(feature, key)}</td></tr>`
110
+ )
111
+ }
112
+
113
+ renderBody(feature) {
114
+ const table = document.createElement('table')
115
+
116
+ for (const key in feature.properties) {
117
+ if (typeof feature.properties[key] === 'object' || key === 'name') continue
118
+ table.appendChild(this.makeRow(feature, key))
119
+ }
120
+ return table
121
+ }
122
+ }
123
+
124
+ class GeoRSSImage extends TitleMixin(PopupTemplate) {
125
+ renderBody(feature) {
126
+ const body = DomUtil.create('a')
127
+ body.href = feature.properties.link
128
+ body.target = '_blank'
129
+ if (feature.properties.img) {
130
+ const img = DomUtil.create('img', '', body)
131
+ img.src = feature.properties.img
132
+ // Sadly, we are unable to override this from JS the clean way
133
+ // See https://github.com/Leaflet/Leaflet/commit/61d746818b99d362108545c151a27f09d60960ee#commitcomment-6061847
134
+ img.style.maxWidth = '500px'
135
+ img.style.maxHeight = '500px'
136
+ }
137
+ return body
138
+ }
139
+ }
140
+
141
+ class GeoRSSLink extends PopupTemplate {
142
+ renderBody(feature) {
143
+ if (feature.properties.link) {
144
+ return Utils.loadTemplate(
145
+ `<a href="${feature.properties.link}" target="_blank"><h3>${feature.getDisplayName()}</h3></a>`
146
+ )
147
+ }
148
+ }
149
+ }
150
+
151
+ class OSM extends TitleMixin(PopupTemplate) {
152
+ getName(feature) {
153
+ const props = feature.properties
154
+ const locale = getLocale()
155
+ if (locale && props[`name:${locale}`]) return props[`name:${locale}`]
156
+ return props.name
157
+ }
158
+
159
+ renderBody(feature) {
160
+ const props = feature.properties
161
+ const body = document.createElement('div')
162
+ const title = DomUtil.add('h3', 'popup-title', container)
163
+ const color = feature.getPreviewColor()
164
+ title.style.backgroundColor = color
165
+ const iconUrl = feature.getDynamicOption('iconUrl')
166
+ const icon = Icon.makeElement(iconUrl, title)
167
+ DomUtil.addClass(icon, 'icon')
168
+ Icon.setContrast(icon, title, iconUrl, color)
169
+ if (DomUtil.contrastedColor(title, color)) title.style.color = 'white'
170
+ DomUtil.add('span', '', title, this.getName(feature))
171
+ const street = props['addr:street']
172
+ if (street) {
173
+ const row = DomUtil.add('address', 'address', body)
174
+ const number = props['addr:housenumber']
175
+ if (number) {
176
+ // Poor way to deal with international forms of writting addresses
177
+ DomUtil.add('span', '', row, `${translate('No.')}: ${number}`)
178
+ DomUtil.add('span', '', row, `${translate('Street')}: ${street}`)
179
+ } else {
180
+ DomUtil.add('span', '', row, street)
181
+ }
182
+ }
183
+ if (props.website) {
184
+ body.appendChild(
185
+ Utils.loadTemplate(`<div><a href="${props.website}">${props.website}</a></div>`)
186
+ )
187
+ }
188
+ const phone = props.phone || props['contact:phone']
189
+ if (phone) {
190
+ body.appendChild(
191
+ Utils.loadTemplate(`<div><a href="tel:${phone}">${phone}</a></div>`)
192
+ )
193
+ }
194
+ if (props.mobile) {
195
+ body.appendChild(
196
+ Utils.loadTemplate(
197
+ `<div><a href="tel:${props.mobile}">${props.mobile}</a></div>`
198
+ )
199
+ )
200
+ }
201
+ const email = props.email || props['contact:email']
202
+ if (email) {
203
+ body.appendChild(
204
+ Utils.loadTemplate(`<div><a href="mailto:${email}">${email}</a></div>`)
205
+ )
206
+ }
207
+ const id = props['@id'] || props.id
208
+ if (id) {
209
+ body.appendChild(
210
+ Utils.loadTemplate(
211
+ `<div class="osm-link"><a href="https://www.openstreetmap.org/${id}">${translate('See on OpenStreetMap')}</a></div>`
212
+ )
213
+ )
214
+ }
215
+ return body
216
+ }
217
+ }