umap-project 3.3.6__py3-none-any.whl → 3.4.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/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
- umap/locale/cs_CZ/LC_MESSAGES/django.po +43 -33
- umap/locale/da/LC_MESSAGES/django.mo +0 -0
- umap/locale/da/LC_MESSAGES/django.po +43 -33
- umap/locale/de/LC_MESSAGES/django.mo +0 -0
- umap/locale/de/LC_MESSAGES/django.po +35 -29
- umap/locale/el/LC_MESSAGES/django.mo +0 -0
- umap/locale/el/LC_MESSAGES/django.po +35 -29
- umap/locale/en/LC_MESSAGES/django.po +34 -28
- umap/locale/es/LC_MESSAGES/django.mo +0 -0
- umap/locale/es/LC_MESSAGES/django.po +43 -33
- umap/locale/et/LC_MESSAGES/django.mo +0 -0
- umap/locale/et/LC_MESSAGES/django.po +58 -54
- umap/locale/eu/LC_MESSAGES/django.mo +0 -0
- umap/locale/eu/LC_MESSAGES/django.po +43 -33
- umap/locale/fa_IR/LC_MESSAGES/django.mo +0 -0
- umap/locale/fa_IR/LC_MESSAGES/django.po +43 -33
- umap/locale/fr/LC_MESSAGES/django.mo +0 -0
- umap/locale/fr/LC_MESSAGES/django.po +36 -30
- umap/locale/gl/LC_MESSAGES/django.mo +0 -0
- umap/locale/gl/LC_MESSAGES/django.po +43 -33
- umap/locale/hu/LC_MESSAGES/django.mo +0 -0
- umap/locale/hu/LC_MESSAGES/django.po +35 -29
- umap/locale/is/LC_MESSAGES/django.mo +0 -0
- umap/locale/is/LC_MESSAGES/django.po +43 -33
- umap/locale/it/LC_MESSAGES/django.mo +0 -0
- umap/locale/it/LC_MESSAGES/django.po +43 -33
- umap/locale/nl/LC_MESSAGES/django.mo +0 -0
- umap/locale/nl/LC_MESSAGES/django.po +35 -29
- umap/locale/pl/LC_MESSAGES/django.mo +0 -0
- umap/locale/pl/LC_MESSAGES/django.po +43 -33
- umap/locale/pt/LC_MESSAGES/django.mo +0 -0
- umap/locale/pt/LC_MESSAGES/django.po +43 -33
- umap/locale/th_TH/LC_MESSAGES/django.mo +0 -0
- umap/locale/th_TH/LC_MESSAGES/django.po +310 -109
- umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
- umap/locale/zh_TW/LC_MESSAGES/django.po +80 -70
- umap/management/commands/switch_user.py +2 -2
- umap/static/umap/base.css +89 -32
- umap/static/umap/content.css +129 -33
- umap/static/umap/css/bar.css +82 -20
- umap/static/umap/css/browser.css +163 -0
- umap/static/umap/css/contextmenu.css +15 -0
- umap/static/umap/css/dialog.css +36 -16
- umap/static/umap/css/form.css +122 -32
- umap/static/umap/css/icon.css +46 -3
- umap/static/umap/css/panel.css +7 -3
- umap/static/umap/css/popup.css +34 -8
- umap/static/umap/css/tooltip.css +8 -4
- umap/static/umap/img/16-white.svg +26 -8
- umap/static/umap/img/16.svg +1 -1
- umap/static/umap/img/source/16-white.svg +36 -18
- umap/static/umap/img/source/16.svg +1 -1
- umap/static/umap/js/components/alerts/alert.css +69 -31
- umap/static/umap/js/components/alerts/alert.js +20 -2
- umap/static/umap/js/modules/browser.js +63 -55
- umap/static/umap/js/modules/caption.js +10 -7
- umap/static/umap/js/modules/data/features.js +82 -59
- umap/static/umap/js/modules/data/layer.js +56 -157
- umap/static/umap/js/modules/domutils.js +109 -0
- umap/static/umap/js/modules/filters.js +807 -0
- umap/static/umap/js/modules/form/builder.js +8 -5
- umap/static/umap/js/modules/form/fields.js +110 -220
- umap/static/umap/js/modules/formatter.js +24 -1
- umap/static/umap/js/modules/help.js +3 -2
- umap/static/umap/js/modules/importers/opendata.js +5 -0
- umap/static/umap/js/modules/importers/openrouteservice.js +6 -1
- umap/static/umap/js/modules/managers.js +265 -1
- umap/static/umap/js/modules/permissions.js +35 -31
- umap/static/umap/js/modules/rendering/controls.js +7 -7
- umap/static/umap/js/modules/rendering/icon.js +3 -8
- umap/static/umap/js/modules/rendering/layers/classified.js +17 -10
- umap/static/umap/js/modules/rendering/layers/cluster.js +2 -2
- umap/static/umap/js/modules/rendering/template.js +44 -8
- umap/static/umap/js/modules/rendering/ui.js +29 -23
- umap/static/umap/js/modules/rules.js +4 -3
- umap/static/umap/js/modules/schema.js +3 -6
- umap/static/umap/js/modules/share.js +4 -3
- umap/static/umap/js/modules/tableeditor.js +50 -38
- umap/static/umap/js/modules/templates.js +2 -3
- umap/static/umap/js/modules/ui/bar.js +42 -18
- umap/static/umap/js/modules/ui/dialog.js +33 -31
- umap/static/umap/js/modules/ui/panel.js +21 -7
- umap/static/umap/js/modules/ui/tooltip.js +6 -5
- umap/static/umap/js/modules/umap.js +148 -51
- umap/static/umap/js/modules/utils.js +23 -1
- umap/static/umap/js/umap.core.js +1 -110
- umap/static/umap/locale/am_ET.js +40 -14
- umap/static/umap/locale/am_ET.json +40 -14
- umap/static/umap/locale/ar.js +40 -14
- umap/static/umap/locale/ar.json +40 -14
- umap/static/umap/locale/ast.js +40 -14
- umap/static/umap/locale/ast.json +40 -14
- umap/static/umap/locale/bg.js +40 -14
- umap/static/umap/locale/bg.json +40 -14
- umap/static/umap/locale/br.js +47 -21
- umap/static/umap/locale/br.json +47 -21
- umap/static/umap/locale/ca.js +40 -14
- umap/static/umap/locale/ca.json +40 -14
- umap/static/umap/locale/cs_CZ.js +40 -14
- umap/static/umap/locale/cs_CZ.json +40 -14
- umap/static/umap/locale/da.js +40 -14
- umap/static/umap/locale/da.json +40 -14
- umap/static/umap/locale/de.js +39 -13
- umap/static/umap/locale/de.json +39 -13
- umap/static/umap/locale/el.js +40 -14
- umap/static/umap/locale/el.json +40 -14
- umap/static/umap/locale/en.js +39 -13
- umap/static/umap/locale/en.json +39 -13
- umap/static/umap/locale/en_US.json +40 -14
- umap/static/umap/locale/es.js +40 -14
- umap/static/umap/locale/es.json +40 -14
- umap/static/umap/locale/et.js +79 -53
- umap/static/umap/locale/et.json +79 -53
- umap/static/umap/locale/eu.js +72 -46
- umap/static/umap/locale/eu.json +72 -46
- umap/static/umap/locale/fa_IR.js +40 -14
- umap/static/umap/locale/fa_IR.json +40 -14
- umap/static/umap/locale/fi.js +40 -14
- umap/static/umap/locale/fi.json +40 -14
- umap/static/umap/locale/fr.js +39 -13
- umap/static/umap/locale/fr.json +39 -13
- umap/static/umap/locale/gl.js +40 -14
- umap/static/umap/locale/gl.json +40 -14
- umap/static/umap/locale/he.js +40 -14
- umap/static/umap/locale/he.json +40 -14
- umap/static/umap/locale/hr.js +40 -14
- umap/static/umap/locale/hr.json +40 -14
- umap/static/umap/locale/hu.js +40 -14
- umap/static/umap/locale/hu.json +40 -14
- umap/static/umap/locale/id.js +40 -14
- umap/static/umap/locale/id.json +40 -14
- umap/static/umap/locale/is.js +40 -14
- umap/static/umap/locale/is.json +40 -14
- umap/static/umap/locale/it.js +40 -14
- umap/static/umap/locale/it.json +40 -14
- umap/static/umap/locale/ja.js +40 -14
- umap/static/umap/locale/ja.json +40 -14
- umap/static/umap/locale/ko.js +40 -14
- umap/static/umap/locale/ko.json +40 -14
- umap/static/umap/locale/lt.js +40 -14
- umap/static/umap/locale/lt.json +40 -14
- umap/static/umap/locale/ms.js +40 -14
- umap/static/umap/locale/ms.json +40 -14
- umap/static/umap/locale/nl.js +40 -14
- umap/static/umap/locale/nl.json +40 -14
- umap/static/umap/locale/no.js +40 -14
- umap/static/umap/locale/no.json +40 -14
- umap/static/umap/locale/pl.js +40 -14
- umap/static/umap/locale/pl.json +40 -14
- umap/static/umap/locale/pl_PL.json +40 -14
- umap/static/umap/locale/pt.js +40 -14
- umap/static/umap/locale/pt.json +40 -14
- umap/static/umap/locale/pt_BR.js +40 -14
- umap/static/umap/locale/pt_BR.json +40 -14
- umap/static/umap/locale/pt_PT.js +40 -14
- umap/static/umap/locale/pt_PT.json +40 -14
- umap/static/umap/locale/ro.js +40 -14
- umap/static/umap/locale/ro.json +40 -14
- umap/static/umap/locale/ru.js +40 -14
- umap/static/umap/locale/ru.json +40 -14
- umap/static/umap/locale/sk_SK.js +40 -14
- umap/static/umap/locale/sk_SK.json +40 -14
- umap/static/umap/locale/sl.js +40 -14
- umap/static/umap/locale/sl.json +40 -14
- umap/static/umap/locale/sr.js +40 -14
- umap/static/umap/locale/sr.json +40 -14
- umap/static/umap/locale/sv.js +40 -14
- umap/static/umap/locale/sv.json +40 -14
- umap/static/umap/locale/th_TH.js +40 -14
- umap/static/umap/locale/th_TH.json +40 -14
- umap/static/umap/locale/tr.js +40 -14
- umap/static/umap/locale/tr.json +40 -14
- umap/static/umap/locale/uk_UA.js +40 -14
- umap/static/umap/locale/uk_UA.json +40 -14
- umap/static/umap/locale/vi.js +40 -14
- umap/static/umap/locale/vi.json +40 -14
- umap/static/umap/locale/vi_VN.json +40 -14
- umap/static/umap/locale/zh.js +40 -14
- umap/static/umap/locale/zh.json +40 -14
- umap/static/umap/locale/zh_CN.json +40 -14
- umap/static/umap/locale/zh_TW.Big5.json +40 -14
- umap/static/umap/locale/zh_TW.js +39 -13
- umap/static/umap/locale/zh_TW.json +39 -13
- umap/static/umap/map.css +60 -223
- umap/static/umap/unittests/utils.js +18 -0
- umap/static/umap/vars.css +23 -5
- umap/templates/umap/components/alerts/alert.html +32 -29
- umap/templates/umap/css.html +2 -1
- umap/templates/umap/login_popup_end.html +18 -9
- umap/templates/umap/user_map_table.html +7 -2
- umap/tests/integration/conftest.py +2 -6
- umap/tests/integration/test_anonymous_owned_map.py +89 -36
- umap/tests/integration/test_basics.py +25 -1
- umap/tests/integration/test_browser.py +37 -0
- umap/tests/integration/test_draw_polygon.py +2 -0
- umap/tests/integration/test_edit_marker.py +1 -1
- umap/tests/integration/test_export_map.py +19 -0
- umap/tests/integration/test_fields.py +522 -0
- umap/tests/integration/test_filters.py +617 -0
- umap/tests/integration/test_import.py +15 -42
- umap/tests/integration/test_remote_data.py +60 -4
- umap/tests/integration/test_share.py +4 -4
- umap/tests/integration/test_tableeditor.py +31 -7
- umap/tests/integration/test_websocket_sync.py +3 -1
- umap/tests/test_dashboard.py +10 -0
- umap/urls.py +1 -0
- umap/views.py +5 -0
- {umap_project-3.3.6.dist-info → umap_project-3.4.0b0.dist-info}/METADATA +12 -12
- {umap_project-3.3.6.dist-info → umap_project-3.4.0b0.dist-info}/RECORD +214 -211
- umap/static/umap/js/modules/facets.js +0 -164
- umap/tests/integration/test_facets_browser.py +0 -279
- {umap_project-3.3.6.dist-info → umap_project-3.4.0b0.dist-info}/WHEEL +0 -0
- {umap_project-3.3.6.dist-info → umap_project-3.4.0b0.dist-info}/entry_points.txt +0 -0
- {umap_project-3.3.6.dist-info → umap_project-3.4.0b0.dist-info}/licenses/LICENSE +0 -0
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
uMapAlert as Alert,
|
|
10
10
|
uMapAlertConflict as AlertConflict,
|
|
11
11
|
} from '../../components/alerts/alert.js'
|
|
12
|
-
import { MutatingForm } from '../form/builder.js'
|
|
12
|
+
import { MutatingForm, Form } from '../form/builder.js'
|
|
13
13
|
import { translate } from '../i18n.js'
|
|
14
14
|
import { DataLayerPermissions } from '../permissions.js'
|
|
15
15
|
import { Default as DefaultLayer } from '../rendering/layers/base.js'
|
|
@@ -21,8 +21,8 @@ import TableEditor from '../tableeditor.js'
|
|
|
21
21
|
import * as Utils from '../utils.js'
|
|
22
22
|
import { LineString, Point, Polygon } from './features.js'
|
|
23
23
|
import Rules from '../rules.js'
|
|
24
|
-
import
|
|
25
|
-
import {
|
|
24
|
+
import { FeatureManager, FieldManager } from '../managers.js'
|
|
25
|
+
import { Filters } from '../filters.js'
|
|
26
26
|
|
|
27
27
|
export const LAYER_TYPES = [
|
|
28
28
|
DefaultLayer,
|
|
@@ -89,12 +89,14 @@ export class DataLayer {
|
|
|
89
89
|
if (!this.createdOnServer) {
|
|
90
90
|
if (this.showAtLoad()) this.show()
|
|
91
91
|
}
|
|
92
|
-
if (!this._needsFetch && !this._umap.fields.
|
|
92
|
+
if (!this._needsFetch && !this._umap.fields.size) {
|
|
93
93
|
this.properties.fields = [
|
|
94
94
|
{ key: U.DEFAULT_LABEL_KEY, type: 'String' },
|
|
95
95
|
{ key: 'description', type: 'Text' },
|
|
96
96
|
]
|
|
97
97
|
}
|
|
98
|
+
this.fields = new FieldManager(this, this._umap.dialog)
|
|
99
|
+
this.filters = new Filters(this, this._umap)
|
|
98
100
|
|
|
99
101
|
// Only layers that are displayed on load must be hidden/shown
|
|
100
102
|
// Automatically, others will be shown manually, and thus will
|
|
@@ -129,7 +131,7 @@ export class DataLayer {
|
|
|
129
131
|
}
|
|
130
132
|
|
|
131
133
|
get cssId() {
|
|
132
|
-
return `datalayer-${
|
|
134
|
+
return `datalayer-${this.id}`
|
|
133
135
|
}
|
|
134
136
|
|
|
135
137
|
get rank() {
|
|
@@ -146,17 +148,10 @@ export class DataLayer {
|
|
|
146
148
|
this.properties.rank = value
|
|
147
149
|
}
|
|
148
150
|
|
|
149
|
-
get fields() {
|
|
150
|
-
if (!this.properties.fields) this.properties.fields = []
|
|
151
|
-
return this.properties.fields
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
set fields(fields) {
|
|
155
|
-
this.properties.fields = fields
|
|
156
|
-
}
|
|
157
|
-
|
|
158
151
|
get fieldKeys() {
|
|
159
|
-
|
|
152
|
+
// Needed to get a similar API from layer and uMap, but
|
|
153
|
+
// uMap whould return concat of all datalayers fields
|
|
154
|
+
return Array.from(this.fields.keys())
|
|
160
155
|
}
|
|
161
156
|
|
|
162
157
|
get sortKey() {
|
|
@@ -174,6 +169,18 @@ export class DataLayer {
|
|
|
174
169
|
// Propagate will remove the fields it has already
|
|
175
170
|
// processed
|
|
176
171
|
fields = this.propagate(fields)
|
|
172
|
+
if (fields.includes('properties.fields')) {
|
|
173
|
+
this.fields?.pull()
|
|
174
|
+
if (this._umap.browser.isOpen()) {
|
|
175
|
+
this._umap.browser.buildFilters()
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (fields.includes('properties.filters')) {
|
|
179
|
+
this.filters.load()
|
|
180
|
+
if (this._umap.browser.isOpen()) {
|
|
181
|
+
this._umap.browser.buildFilters()
|
|
182
|
+
}
|
|
183
|
+
}
|
|
177
184
|
|
|
178
185
|
const impacts = Utils.getImpactsFromSchema(fields)
|
|
179
186
|
|
|
@@ -448,7 +455,8 @@ export class DataLayer {
|
|
|
448
455
|
this.inferFields(feature)
|
|
449
456
|
try {
|
|
450
457
|
this.showFeature(feature)
|
|
451
|
-
} catch {
|
|
458
|
+
} catch (error) {
|
|
459
|
+
console.error(error)
|
|
452
460
|
if (this._umap.editEnabled) {
|
|
453
461
|
Alert.error(translate('Skipping invalid geometry'))
|
|
454
462
|
}
|
|
@@ -482,88 +490,43 @@ export class DataLayer {
|
|
|
482
490
|
}
|
|
483
491
|
|
|
484
492
|
inferFields(feature) {
|
|
485
|
-
if (!this.properties.fields) this.properties.fields = []
|
|
486
|
-
const keys = this.fieldKeys
|
|
487
493
|
for (const key in feature.properties) {
|
|
488
494
|
if (typeof feature.properties[key] !== 'object') {
|
|
489
495
|
if (key.indexOf('_') === 0) continue
|
|
490
|
-
if (
|
|
491
|
-
this.
|
|
496
|
+
if (this.fields.has(key)) continue
|
|
497
|
+
if (this._umap.fields.has(key)) continue
|
|
498
|
+
let type = 'String'
|
|
499
|
+
if (key === 'description') type = 'Text'
|
|
500
|
+
this.fields.add({ key, type })
|
|
492
501
|
}
|
|
493
502
|
}
|
|
503
|
+
this.fields.push()
|
|
494
504
|
}
|
|
495
505
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
.confirm(
|
|
499
|
-
translate('Are you sure you want to delete this field on all the features?')
|
|
500
|
-
)
|
|
501
|
-
.then(() => {
|
|
502
|
-
this.deleteProperty(property)
|
|
503
|
-
})
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
async askForRenameProperty(property) {
|
|
507
|
-
return this._umap.dialog
|
|
508
|
-
.prompt(translate('Please enter the new name of this field'))
|
|
509
|
-
.then(({ prompt }) => {
|
|
510
|
-
if (!prompt || !this.validateName(prompt)) return
|
|
511
|
-
this.renameProperty(property, prompt)
|
|
512
|
-
})
|
|
506
|
+
renameField(oldName, newName) {
|
|
507
|
+
this.renameFeaturesField(oldName, newName)
|
|
513
508
|
}
|
|
514
509
|
|
|
515
|
-
|
|
516
|
-
this.sync.startBatch()
|
|
517
|
-
const oldFields = Utils.CopyJSON(this.fields)
|
|
518
|
-
for (const field of this.fields) {
|
|
519
|
-
if (field.key === oldName) {
|
|
520
|
-
field.key = newName
|
|
521
|
-
break
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
this.sync.update('properties.fields', this.fields, oldFields)
|
|
510
|
+
renameFeaturesField(oldName, newName) {
|
|
525
511
|
this.features.forEach((feature) => {
|
|
526
|
-
feature.
|
|
512
|
+
feature.renameField(oldName, newName)
|
|
527
513
|
})
|
|
528
|
-
this.sync.commitBatch()
|
|
529
514
|
}
|
|
530
515
|
|
|
531
|
-
|
|
532
|
-
this.
|
|
533
|
-
const oldFields = Utils.CopyJSON(this.fields)
|
|
534
|
-
this.fields = this.fields.filter((field) => field.key !== property)
|
|
535
|
-
this.sync.update('properties.fields', this.fields, oldFields)
|
|
536
|
-
this.features.forEach((feature) => {
|
|
537
|
-
feature.deleteProperty(property)
|
|
538
|
-
})
|
|
539
|
-
this.sync.commitBatch()
|
|
516
|
+
deleteField(name) {
|
|
517
|
+
this.deleteFeaturesField(name)
|
|
540
518
|
}
|
|
541
519
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
})
|
|
547
|
-
this._umap.dialog
|
|
548
|
-
.prompt(translate('Please enter the name of the property'))
|
|
549
|
-
.then(({ prompt }) => {
|
|
550
|
-
if (!prompt || !this.validateName(prompt)) return
|
|
551
|
-
this.properties.fields.push({ key: prompt, type: 'String' })
|
|
552
|
-
resolve()
|
|
520
|
+
deleteFeaturesField(name) {
|
|
521
|
+
if (!this._umap.fields.has(name) && !this.fields.has(name)) {
|
|
522
|
+
this.features.forEach((feature) => {
|
|
523
|
+
feature.deleteField(name)
|
|
553
524
|
})
|
|
554
|
-
|
|
525
|
+
}
|
|
555
526
|
}
|
|
556
527
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
Alert.error(translate('Name “{name}” should not contain a dot.', { name }))
|
|
560
|
-
return false
|
|
561
|
-
}
|
|
562
|
-
if (this.fieldKeys.includes(name)) {
|
|
563
|
-
Alert.error(translate('This name already exists: “{name}”', { name }))
|
|
564
|
-
return false
|
|
565
|
-
}
|
|
566
|
-
return true
|
|
528
|
+
eachFeature(callback) {
|
|
529
|
+
this.features.forEach((feature) => callback(feature))
|
|
567
530
|
}
|
|
568
531
|
|
|
569
532
|
sortedValues(property) {
|
|
@@ -834,7 +797,7 @@ export class DataLayer {
|
|
|
834
797
|
const builder = new MutatingForm(this, layerFields)
|
|
835
798
|
const template = `
|
|
836
799
|
<details id="layer-properties">
|
|
837
|
-
<summary>${this.layer.getName()}: ${translate('settings')}</summary>
|
|
800
|
+
<summary><h4>${this.layer.getName()}: ${translate('settings')}</h4></summary>
|
|
838
801
|
<fieldset data-ref=fieldset></fieldset>
|
|
839
802
|
</details>
|
|
840
803
|
`
|
|
@@ -928,64 +891,6 @@ export class DataLayer {
|
|
|
928
891
|
fieldset.appendChild(builder.build())
|
|
929
892
|
}
|
|
930
893
|
|
|
931
|
-
_editFields(container) {
|
|
932
|
-
const template = `
|
|
933
|
-
<details id="fields">
|
|
934
|
-
<summary>${translate('Manage Fields')}</summary>
|
|
935
|
-
<fieldset>
|
|
936
|
-
<ul data-ref=ul></ul>
|
|
937
|
-
<button type="button" data-ref=add><i class="icon icon-16 icon-add"></i>${translate('Add a new field')}</button>
|
|
938
|
-
</fieldset>
|
|
939
|
-
</details>
|
|
940
|
-
`
|
|
941
|
-
const [fieldset, { ul, add }] = Utils.loadTemplateWithRefs(template)
|
|
942
|
-
add.addEventListener('click', () => {
|
|
943
|
-
this.addProperty().then(() => {
|
|
944
|
-
this.edit().then((panel) => {
|
|
945
|
-
panel.scrollTo('details#fields')
|
|
946
|
-
})
|
|
947
|
-
})
|
|
948
|
-
})
|
|
949
|
-
container.appendChild(fieldset)
|
|
950
|
-
for (const field of this.fields) {
|
|
951
|
-
const [row, { rename, del }] = Utils.loadTemplateWithRefs(
|
|
952
|
-
`<li class="orderable" data-key="${field.key}">
|
|
953
|
-
<button class="icon icon-16 icon-edit" title="${translate('Rename this field')}" data-ref=rename></button>
|
|
954
|
-
<button class="icon icon-16 icon-delete" title="${translate('Delete this field')}" data-ref=del></button>
|
|
955
|
-
<i class="icon icon-16 icon-drag" title="${translate('Drag to reorder')}"></i>
|
|
956
|
-
${field.key}
|
|
957
|
-
</li>`
|
|
958
|
-
)
|
|
959
|
-
ul.appendChild(row)
|
|
960
|
-
rename.addEventListener('click', () => {
|
|
961
|
-
this.askForRenameProperty(field.key).then(() => {
|
|
962
|
-
this.edit().then((panel) => {
|
|
963
|
-
panel.scrollTo('details#fields')
|
|
964
|
-
})
|
|
965
|
-
})
|
|
966
|
-
})
|
|
967
|
-
del.addEventListener('click', () => {
|
|
968
|
-
this.confirmDeleteProperty(field.key).then(() => {
|
|
969
|
-
this.edit().then((panel) => {
|
|
970
|
-
panel.scrollTo('details#fields')
|
|
971
|
-
})
|
|
972
|
-
})
|
|
973
|
-
})
|
|
974
|
-
}
|
|
975
|
-
const onReorder = (src, dst, initialIndex, finalIndex) => {
|
|
976
|
-
const orderedKeys = Array.from(ul.querySelectorAll('li')).map(
|
|
977
|
-
(el) => el.dataset.key
|
|
978
|
-
)
|
|
979
|
-
const oldFields = Utils.CopyJSON(this.properties.fields)
|
|
980
|
-
this.properties.fields.sort(
|
|
981
|
-
(fieldA, fieldB) =>
|
|
982
|
-
orderedKeys.indexOf(fieldA.key) > orderedKeys.indexOf(fieldB.key)
|
|
983
|
-
)
|
|
984
|
-
this.sync.update('properties.fields', this.properties.fields, oldFields)
|
|
985
|
-
}
|
|
986
|
-
const orderable = new Orderable(ul, onReorder)
|
|
987
|
-
}
|
|
988
|
-
|
|
989
894
|
_editRemoteDataProperties(container) {
|
|
990
895
|
// XXX I'm not sure **why** this is needed (as it's set during `this.initialize`)
|
|
991
896
|
// but apparently it's needed.
|
|
@@ -1096,9 +1001,7 @@ export class DataLayer {
|
|
|
1096
1001
|
this._editInteractionProperties(container)
|
|
1097
1002
|
this._editTextPathProperties(container)
|
|
1098
1003
|
this._editRemoteDataProperties(container)
|
|
1099
|
-
|
|
1100
|
-
this._editFields(container)
|
|
1101
|
-
}
|
|
1004
|
+
this.fields.edit(container)
|
|
1102
1005
|
this.rules.edit(container)
|
|
1103
1006
|
|
|
1104
1007
|
if (this._umap.properties.urls.datalayer_versions) {
|
|
@@ -1294,7 +1197,8 @@ export class DataLayer {
|
|
|
1294
1197
|
}
|
|
1295
1198
|
|
|
1296
1199
|
umapGeoJSON() {
|
|
1297
|
-
const
|
|
1200
|
+
const features = this.isRemoteLayer() ? [] : this.features.all()
|
|
1201
|
+
const geojson = this._umap.formatter.toFeatureCollection(features)
|
|
1298
1202
|
geojson._umap_options = this.properties
|
|
1299
1203
|
return geojson
|
|
1300
1204
|
}
|
|
@@ -1331,12 +1235,12 @@ export class DataLayer {
|
|
|
1331
1235
|
async save() {
|
|
1332
1236
|
if (this.isDeleted) return await this.saveDelete()
|
|
1333
1237
|
if (!this.isRemoteLayer() && !this.isLoaded()) return
|
|
1334
|
-
const geojson = this.umapGeoJSON()
|
|
1335
1238
|
const formData = new FormData()
|
|
1336
1239
|
formData.append('name', this.properties.name)
|
|
1337
1240
|
formData.append('display_on_load', !!this.properties.displayOnLoad)
|
|
1338
1241
|
formData.append('rank', this.rank)
|
|
1339
1242
|
formData.append('settings', this.prepareProperties())
|
|
1243
|
+
const geojson = this.umapGeoJSON()
|
|
1340
1244
|
// Filename support is shaky, don't do it for now.
|
|
1341
1245
|
const blob = new Blob([JSON.stringify(geojson)], { type: 'application/json' })
|
|
1342
1246
|
formData.append('geojson', blob)
|
|
@@ -1438,13 +1342,12 @@ export class DataLayer {
|
|
|
1438
1342
|
)) {
|
|
1439
1343
|
container.innerHTML = ''
|
|
1440
1344
|
if (this.layer.renderLegend) return this.layer.renderLegend(container)
|
|
1441
|
-
const keys = new Set(this.fieldKeys)
|
|
1442
1345
|
const rules = new Map()
|
|
1443
1346
|
for (const rule of this.rules) {
|
|
1444
1347
|
rules.set(rule.condition, rule)
|
|
1445
1348
|
}
|
|
1446
1349
|
for (const rule of this._umap.rules) {
|
|
1447
|
-
if (!rules.has(rule.condition) &&
|
|
1350
|
+
if (!rules.has(rule.condition) && this.fields.has(rule.key)) {
|
|
1448
1351
|
rules.set(rule.condition, rule)
|
|
1449
1352
|
}
|
|
1450
1353
|
}
|
|
@@ -1468,6 +1371,11 @@ export class DataLayer {
|
|
|
1468
1371
|
'icon-eye',
|
|
1469
1372
|
translate('Show/hide layer')
|
|
1470
1373
|
)
|
|
1374
|
+
const table = DomUtil.createButtonIcon(
|
|
1375
|
+
container,
|
|
1376
|
+
'icon-table show-on-edit',
|
|
1377
|
+
translate('Edit properties in a table')
|
|
1378
|
+
)
|
|
1471
1379
|
const zoomTo = DomUtil.createButtonIcon(
|
|
1472
1380
|
container,
|
|
1473
1381
|
'icon-zoom',
|
|
@@ -1478,11 +1386,6 @@ export class DataLayer {
|
|
|
1478
1386
|
'icon-edit show-on-edit',
|
|
1479
1387
|
translate('Edit')
|
|
1480
1388
|
)
|
|
1481
|
-
const table = DomUtil.createButtonIcon(
|
|
1482
|
-
container,
|
|
1483
|
-
'icon-table show-on-edit',
|
|
1484
|
-
translate('Edit properties in a table')
|
|
1485
|
-
)
|
|
1486
1389
|
const remove = DomUtil.createButtonIcon(
|
|
1487
1390
|
container,
|
|
1488
1391
|
'icon-delete show-on-edit',
|
|
@@ -1500,16 +1403,12 @@ export class DataLayer {
|
|
|
1500
1403
|
}
|
|
1501
1404
|
DomEvent.on(toggle, 'click', () => this.toggle())
|
|
1502
1405
|
DomEvent.on(zoomTo, 'click', this.zoomTo, this)
|
|
1503
|
-
container.classList.add(this.
|
|
1406
|
+
container.classList.add(this.cssId)
|
|
1504
1407
|
container.classList.toggle('off', !this.isVisible())
|
|
1505
1408
|
}
|
|
1506
1409
|
|
|
1507
1410
|
getHidableElements() {
|
|
1508
|
-
return document.querySelectorAll(`.${this.
|
|
1509
|
-
}
|
|
1510
|
-
|
|
1511
|
-
getHidableClass() {
|
|
1512
|
-
return `show_with_datalayer_${stamp(this)}`
|
|
1411
|
+
return document.querySelectorAll(`.${this.cssId}`)
|
|
1513
1412
|
}
|
|
1514
1413
|
|
|
1515
1414
|
propagateDelete() {
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// Utils that needs the DOM
|
|
2
|
+
import * as Utils from './utils.js'
|
|
3
|
+
import { translate } from './i18n.js'
|
|
4
|
+
import Tooltip from './ui/tooltip.js'
|
|
5
|
+
|
|
6
|
+
export const copyToClipboard = (textToCopy) => {
|
|
7
|
+
const tooltip = new Tooltip()
|
|
8
|
+
// https://stackoverflow.com/a/65996386
|
|
9
|
+
// Navigator clipboard api needs a secure context (https)
|
|
10
|
+
if (navigator.clipboard && window.isSecureContext) {
|
|
11
|
+
navigator.clipboard.writeText(textToCopy)
|
|
12
|
+
} else {
|
|
13
|
+
// Use the 'out of viewport hidden text area' trick
|
|
14
|
+
const textArea = document.createElement('textarea')
|
|
15
|
+
textArea.value = textToCopy
|
|
16
|
+
|
|
17
|
+
// Move textarea out of the viewport so it's not visible
|
|
18
|
+
textArea.style.position = 'absolute'
|
|
19
|
+
textArea.style.left = '-999999px'
|
|
20
|
+
|
|
21
|
+
document.body.prepend(textArea)
|
|
22
|
+
textArea.select()
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
document.execCommand('copy')
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error(error)
|
|
28
|
+
} finally {
|
|
29
|
+
textArea.remove()
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
tooltip.open({ content: translate('✅ Copied!'), duration: 5000 })
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const copiableInput = (parent, label, value) => {
|
|
36
|
+
const [container, { input, button }] = Utils.loadTemplateWithRefs(`
|
|
37
|
+
<div class="copiable-input">
|
|
38
|
+
<label>${label}<input type="text" readOnly value="${value}" data-ref=input /></label>
|
|
39
|
+
<button type="button" class="icon icon-24 icon-copy" title="${translate('copy')}" data-ref=button></button>
|
|
40
|
+
</div>
|
|
41
|
+
`)
|
|
42
|
+
button.addEventListener('click', () => copyToClipboard(input.value))
|
|
43
|
+
parent.appendChild(container)
|
|
44
|
+
return input
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// From https://gist.github.com/Accudio/b9cb16e0e3df858cef0d31e38f1fe46f
|
|
48
|
+
// convert colour in range 0-255 to the modifier used within luminance calculation
|
|
49
|
+
const colourMod = (colour) => {
|
|
50
|
+
const sRGB = colour / 255
|
|
51
|
+
let mod = ((sRGB + 0.055) / 1.055) ** 2.4
|
|
52
|
+
if (sRGB < 0.03928) mod = sRGB / 12.92
|
|
53
|
+
return mod
|
|
54
|
+
}
|
|
55
|
+
const RGBRegex = /rgb *\( *([0-9]{1,3}) *, *([0-9]{1,3}) *, *([0-9]{1,3}) *\)/
|
|
56
|
+
|
|
57
|
+
export const textColorFromBackgroundColor = (el, bgcolor) => {
|
|
58
|
+
return contrastedColor(el, bgcolor) ? '#ffffff' : '#000000'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const contrastWCAG21 = (rgb) => {
|
|
62
|
+
const [r, g, b] = rgb
|
|
63
|
+
// luminance of inputted colour
|
|
64
|
+
const lum = 0.2126 * colourMod(r) + 0.7152 * colourMod(g) + 0.0722 * colourMod(b)
|
|
65
|
+
// white has a luminance of 1
|
|
66
|
+
const whiteLum = 1
|
|
67
|
+
const contrast = (whiteLum + 0.05) / (lum + 0.05)
|
|
68
|
+
return contrast > 3 ? 1 : 0
|
|
69
|
+
}
|
|
70
|
+
const colorNameToHex = (str) => {
|
|
71
|
+
const ctx = document.createElement('canvas').getContext('2d')
|
|
72
|
+
ctx.fillStyle = str
|
|
73
|
+
return ctx.fillStyle
|
|
74
|
+
}
|
|
75
|
+
export const hexToRGB = (hex) => {
|
|
76
|
+
return hex
|
|
77
|
+
.replace(
|
|
78
|
+
/^#?([a-f\d])([a-f\d])([a-f\d])$/i,
|
|
79
|
+
(m, r, g, b) => `#${r}${r}${g}${g}${b}${b}`
|
|
80
|
+
)
|
|
81
|
+
.substring(1)
|
|
82
|
+
.match(/.{2}/g)
|
|
83
|
+
.map((x) => Number.parseInt(x, 16))
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const CACHE_CONSTRAST = {}
|
|
87
|
+
export const contrastedColor = (el, bgcolor) => {
|
|
88
|
+
// Return 0 for black and 1 for white
|
|
89
|
+
// bgcolor is a human color, it can be a any keyword (purple…)
|
|
90
|
+
if (typeof CACHE_CONSTRAST[bgcolor] !== 'undefined') return CACHE_CONSTRAST[bgcolor]
|
|
91
|
+
let rgb = window.getComputedStyle(el).getPropertyValue('background-color')
|
|
92
|
+
rgb = RGBRegex.exec(rgb)
|
|
93
|
+
if (rgb && rgb.length === 4) {
|
|
94
|
+
rgb = [
|
|
95
|
+
Number.parseInt(rgb[1], 10),
|
|
96
|
+
Number.parseInt(rgb[2], 10),
|
|
97
|
+
Number.parseInt(rgb[3], 10),
|
|
98
|
+
]
|
|
99
|
+
} else {
|
|
100
|
+
// The element may not yet be added to the DOM, so let's try
|
|
101
|
+
// another way
|
|
102
|
+
const hex = colorNameToHex(bgcolor)
|
|
103
|
+
rgb = hexToRGB(hex)
|
|
104
|
+
}
|
|
105
|
+
if (!rgb) return 1
|
|
106
|
+
const out = contrastWCAG21(rgb)
|
|
107
|
+
if (bgcolor) CACHE_CONSTRAST[bgcolor] = out
|
|
108
|
+
return out
|
|
109
|
+
}
|