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.
- umap/__init__.py +1 -1
- umap/admin.py +6 -1
- umap/context_processors.py +2 -1
- umap/decorators.py +13 -2
- umap/forms.py +26 -2
- umap/locale/br/LC_MESSAGES/django.mo +0 -0
- umap/locale/br/LC_MESSAGES/django.po +252 -146
- umap/locale/ca/LC_MESSAGES/django.mo +0 -0
- umap/locale/ca/LC_MESSAGES/django.po +274 -162
- umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
- umap/locale/cs_CZ/LC_MESSAGES/django.po +261 -150
- umap/locale/de/LC_MESSAGES/django.mo +0 -0
- umap/locale/de/LC_MESSAGES/django.po +299 -187
- umap/locale/el/LC_MESSAGES/django.mo +0 -0
- umap/locale/el/LC_MESSAGES/django.po +215 -159
- umap/locale/en/LC_MESSAGES/django.po +211 -155
- umap/locale/es/LC_MESSAGES/django.mo +0 -0
- umap/locale/es/LC_MESSAGES/django.po +255 -144
- umap/locale/eu/LC_MESSAGES/django.mo +0 -0
- umap/locale/eu/LC_MESSAGES/django.po +254 -198
- umap/locale/fa_IR/LC_MESSAGES/django.mo +0 -0
- umap/locale/fa_IR/LC_MESSAGES/django.po +346 -234
- umap/locale/fr/LC_MESSAGES/django.mo +0 -0
- umap/locale/fr/LC_MESSAGES/django.po +216 -160
- umap/locale/hu/LC_MESSAGES/django.mo +0 -0
- umap/locale/hu/LC_MESSAGES/django.po +215 -159
- umap/locale/it/LC_MESSAGES/django.mo +0 -0
- umap/locale/it/LC_MESSAGES/django.po +252 -146
- umap/locale/ms/LC_MESSAGES/django.mo +0 -0
- umap/locale/ms/LC_MESSAGES/django.po +252 -146
- umap/locale/pl/LC_MESSAGES/django.mo +0 -0
- umap/locale/pl/LC_MESSAGES/django.po +254 -148
- umap/locale/pt/LC_MESSAGES/django.mo +0 -0
- umap/locale/pt/LC_MESSAGES/django.po +215 -159
- umap/locale/sv/LC_MESSAGES/django.mo +0 -0
- umap/locale/sv/LC_MESSAGES/django.po +254 -143
- umap/locale/th_TH/LC_MESSAGES/django.mo +0 -0
- umap/locale/th_TH/LC_MESSAGES/django.po +125 -70
- umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
- umap/locale/zh_TW/LC_MESSAGES/django.po +256 -145
- umap/migrations/0022_add_team.py +94 -0
- umap/models.py +45 -10
- umap/settings/__init__.py +2 -0
- umap/settings/base.py +3 -2
- umap/static/umap/base.css +32 -41
- umap/static/umap/content.css +19 -25
- umap/static/umap/css/icon.css +63 -37
- umap/static/umap/css/importers.css +1 -1
- umap/static/umap/css/slideshow.css +7 -5
- umap/static/umap/css/tableeditor.css +4 -3
- umap/static/umap/img/16-white.svg +1 -4
- umap/static/umap/img/16.svg +2 -6
- umap/static/umap/img/24-white.svg +4 -4
- umap/static/umap/img/24.svg +6 -6
- umap/static/umap/img/source/16-white.svg +2 -5
- umap/static/umap/img/source/16.svg +3 -7
- umap/static/umap/img/source/24-white.svg +7 -14
- umap/static/umap/img/source/24.svg +10 -17
- umap/static/umap/js/components/alerts/alert.css +20 -8
- umap/static/umap/js/modules/autocomplete.js +3 -3
- umap/static/umap/js/modules/browser.js +4 -3
- umap/static/umap/js/modules/caption.js +9 -11
- umap/static/umap/js/modules/data/features.js +994 -0
- umap/static/umap/js/modules/data/layer.js +1210 -0
- umap/static/umap/js/modules/formatter.js +12 -3
- umap/static/umap/js/modules/global.js +21 -5
- umap/static/umap/js/modules/permissions.js +280 -0
- umap/static/umap/js/{umap.icon.js → modules/rendering/icon.js} +77 -56
- umap/static/umap/js/modules/rendering/layers/base.js +105 -0
- umap/static/umap/js/modules/rendering/layers/classified.js +484 -0
- umap/static/umap/js/modules/rendering/layers/cluster.js +103 -0
- umap/static/umap/js/modules/rendering/layers/heat.js +182 -0
- umap/static/umap/js/modules/rendering/popup.js +99 -0
- umap/static/umap/js/modules/rendering/template.js +217 -0
- umap/static/umap/js/modules/rendering/ui.js +573 -0
- umap/static/umap/js/modules/schema.js +24 -0
- umap/static/umap/js/modules/share.js +66 -45
- umap/static/umap/js/modules/sync/updaters.js +9 -10
- umap/static/umap/js/modules/tableeditor.js +7 -7
- umap/static/umap/js/modules/ui/dialog.js +8 -4
- umap/static/umap/js/modules/utils.js +22 -13
- umap/static/umap/js/umap.controls.js +79 -146
- umap/static/umap/js/umap.core.js +9 -9
- umap/static/umap/js/umap.forms.js +32 -12
- umap/static/umap/js/umap.js +65 -63
- umap/static/umap/locale/br.js +35 -35
- umap/static/umap/locale/br.json +35 -35
- umap/static/umap/locale/ca.js +50 -50
- umap/static/umap/locale/ca.json +50 -50
- umap/static/umap/locale/de.js +136 -136
- umap/static/umap/locale/de.json +136 -136
- umap/static/umap/locale/el.js +47 -47
- umap/static/umap/locale/el.json +47 -47
- umap/static/umap/locale/en.js +7 -1
- umap/static/umap/locale/en.json +7 -1
- umap/static/umap/locale/fa_IR.js +44 -44
- umap/static/umap/locale/fa_IR.json +44 -44
- umap/static/umap/locale/fr.js +8 -2
- umap/static/umap/locale/fr.json +8 -2
- umap/static/umap/locale/pt.js +17 -17
- umap/static/umap/locale/pt.json +17 -17
- umap/static/umap/locale/pt_PT.js +207 -207
- umap/static/umap/locale/pt_PT.json +207 -207
- umap/static/umap/locale/th_TH.js +25 -25
- umap/static/umap/locale/th_TH.json +25 -25
- umap/static/umap/map.css +107 -104
- umap/static/umap/nav.css +19 -10
- umap/static/umap/unittests/utils.js +230 -107
- umap/static/umap/vendors/csv2geojson/csv2geojson.js +62 -40
- umap/static/umap/vendors/markercluster/MarkerCluster.Default.css +1 -1
- umap/storage.py +1 -0
- umap/templates/404.html +5 -1
- umap/templates/500.html +3 -1
- umap/templates/auth/user_detail.html +8 -2
- umap/templates/auth/user_form.html +19 -10
- umap/templates/auth/user_stars.html +8 -2
- umap/templates/base.html +1 -0
- umap/templates/registration/login.html +18 -3
- umap/templates/umap/about.html +1 -0
- umap/templates/umap/about_summary.html +22 -7
- umap/templates/umap/components/alerts/alert.html +42 -21
- umap/templates/umap/content.html +2 -0
- umap/templates/umap/content_footer.html +6 -2
- umap/templates/umap/css.html +1 -0
- umap/templates/umap/dashboard_menu.html +15 -0
- umap/templates/umap/home.html +14 -4
- umap/templates/umap/js.html +4 -9
- umap/templates/umap/login_popup_end.html +10 -4
- umap/templates/umap/map_detail.html +8 -2
- umap/templates/umap/map_fragment.html +3 -1
- umap/templates/umap/map_init.html +2 -1
- umap/templates/umap/map_list.html +4 -3
- umap/templates/umap/map_table.html +36 -12
- umap/templates/umap/messages.html +0 -1
- umap/templates/umap/navigation.html +2 -1
- umap/templates/umap/password_change.html +5 -1
- umap/templates/umap/password_change_done.html +8 -2
- umap/templates/umap/search.html +8 -2
- umap/templates/umap/search_bar.html +1 -0
- umap/templates/umap/team_confirm_delete.html +19 -0
- umap/templates/umap/team_detail.html +27 -0
- umap/templates/umap/team_form.html +60 -0
- umap/templates/umap/user_dashboard.html +7 -9
- umap/templates/umap/user_teams.html +51 -0
- umap/tests/base.py +8 -1
- umap/tests/conftest.py +6 -0
- umap/tests/fixtures/test_circles_layer.geojson +219 -0
- umap/tests/fixtures/test_upload_georss.xml +20 -0
- umap/tests/integration/conftest.py +18 -4
- umap/tests/integration/helpers.py +12 -0
- umap/tests/integration/test_anonymous_owned_map.py +23 -0
- umap/tests/integration/test_basics.py +29 -0
- umap/tests/integration/test_caption.py +20 -0
- umap/tests/integration/test_circles_layer.py +69 -0
- umap/tests/integration/test_draw_polygon.py +110 -13
- umap/tests/integration/test_draw_polyline.py +8 -18
- umap/tests/integration/test_edit_datalayer.py +1 -1
- umap/tests/integration/test_import.py +64 -5
- umap/tests/integration/test_owned_map.py +21 -13
- umap/tests/integration/test_team.py +47 -0
- umap/tests/integration/test_tilelayer.py +19 -2
- umap/tests/integration/test_view_marker.py +28 -1
- umap/tests/integration/test_websocket_sync.py +5 -5
- umap/tests/test_datalayer.py +32 -7
- umap/tests/test_datalayer_views.py +1 -1
- umap/tests/test_map.py +30 -4
- umap/tests/test_map_views.py +2 -2
- umap/tests/test_statics.py +40 -0
- umap/tests/test_team_views.py +131 -0
- umap/tests/test_views.py +15 -1
- umap/urls.py +23 -13
- umap/views.py +116 -10
- {umap_project-2.5.1.dist-info → umap_project-2.6.0b0.dist-info}/METADATA +9 -9
- {umap_project-2.5.1.dist-info → umap_project-2.6.0b0.dist-info}/RECORD +177 -170
- umap/static/umap/js/umap.datalayer.permissions.js +0 -70
- umap/static/umap/js/umap.features.js +0 -1290
- umap/static/umap/js/umap.layer.js +0 -1837
- umap/static/umap/js/umap.permissions.js +0 -208
- umap/static/umap/js/umap.popup.js +0 -341
- umap/static/umap/test/TableEditor.js +0 -104
- umap/static/umap/vendors/leaflet/leaflet-src.js +0 -14512
- umap/static/umap/vendors/leaflet/leaflet-src.js.map +0 -1
- umap/static/umap/vendors/leaflet/leaflet.js +0 -6
- umap/static/umap/vendors/leaflet/leaflet.js.map +0 -1
- umap/static/umap/vendors/markercluster/WhereAreTheJavascriptFiles.txt +0 -5
- umap/static/umap/vendors/markercluster/leaflet.markercluster-src.js +0 -2718
- umap/static/umap/vendors/markercluster/leaflet.markercluster-src.js.map +0 -1
- umap/static/umap/vendors/toolbar/leaflet.toolbar-src.css +0 -117
- umap/static/umap/vendors/toolbar/leaflet.toolbar-src.js +0 -365
- umap/tests/integration/test_statics.py +0 -47
- {umap_project-2.5.1.dist-info → umap_project-2.6.0b0.dist-info}/WHEEL +0 -0
- {umap_project-2.5.1.dist-info → umap_project-2.6.0b0.dist-info}/entry_points.txt +0 -0
- {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.
|
|
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
|
-
|
|
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(
|
|
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 {
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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:
|
|
29
|
+
iconUrl: SCHEMA.iconUrl.default,
|
|
10
30
|
feature: null,
|
|
11
31
|
}
|
|
12
32
|
options = L.Util.extend({}, default_options, options)
|
|
13
|
-
|
|
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 (
|
|
22
|
-
if (url ===
|
|
23
|
-
if (
|
|
24
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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 (
|
|
83
|
+
initialize: function (options) {
|
|
67
84
|
options = L.Util.extend({}, this.default_options, options)
|
|
68
|
-
|
|
85
|
+
BaseIcon.prototype.initialize.call(this, options)
|
|
69
86
|
},
|
|
70
87
|
|
|
71
88
|
_setIconStyles: function (img, name) {
|
|
72
|
-
|
|
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
|
-
|
|
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 =
|
|
90
|
-
this.elements.container =
|
|
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.
|
|
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 =
|
|
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
|
-
|
|
106
|
-
initialize: function (
|
|
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
|
-
|
|
131
|
+
BaseIcon.prototype.initialize.call(this, options)
|
|
114
132
|
},
|
|
115
133
|
|
|
116
134
|
_setIconStyles: function (img, name) {
|
|
117
|
-
|
|
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 =
|
|
142
|
+
this.elements.main = DomUtil.create('div')
|
|
125
143
|
this.elements.main.innerHTML = ' '
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
151
|
-
this.elements.container =
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
189
|
-
const div =
|
|
190
|
-
const span =
|
|
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 ||
|
|
223
|
+
return color || DomUtil.TextColorFromBackgroundColor(el, backgroundColor)
|
|
204
224
|
},
|
|
205
225
|
})
|
|
206
226
|
|
|
207
|
-
|
|
208
|
-
|
|
227
|
+
export function isImg(src) {
|
|
228
|
+
return Utils.isPath(src) || Utils.isRemoteUrl(src) || Utils.isDataImage(src)
|
|
229
|
+
}
|
|
209
230
|
|
|
210
|
-
|
|
231
|
+
export function makeElement(src, parent) {
|
|
211
232
|
let icon
|
|
212
|
-
if (
|
|
213
|
-
icon =
|
|
233
|
+
if (isImg(src)) {
|
|
234
|
+
icon = DomUtil.create('img')
|
|
214
235
|
icon.src = src
|
|
215
236
|
} else {
|
|
216
|
-
icon =
|
|
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
|
-
|
|
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 (
|
|
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
|
+
}
|