mirror of
https://github.com/umap-project/umap.git
synced 2025-05-06 06:21:49 +02:00
a11y: use role=alert for messages from Django and JS
Also define a custom module+css for alerts (chore).
This commit is contained in:
parent
76ed2200cf
commit
d6e4da3f40
15 changed files with 168 additions and 84 deletions
34
umap/static/umap/alerts.css
Normal file
34
umap/static/umap/alerts.css
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
[data-alert] {
|
||||||
|
box-sizing: border-box;
|
||||||
|
min-height: 46px;
|
||||||
|
line-height: 46px;
|
||||||
|
padding-left: 10px;
|
||||||
|
width: calc(100% - 500px);
|
||||||
|
position: absolute;
|
||||||
|
left: 250px; /* Keep save/cancel button accessible. */
|
||||||
|
right: 250px;
|
||||||
|
box-shadow: 0 1px 7px #999999;
|
||||||
|
background: none repeat scroll 0 0 rgba(20, 22, 23, 0.8);
|
||||||
|
font-weight: bold;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 0.8em;
|
||||||
|
z-index: 1012;
|
||||||
|
border-radius: 2px;
|
||||||
|
visibility: visible;
|
||||||
|
top: 23px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
[data-alert][data-level="error"] {
|
||||||
|
background-color: #c60f13;
|
||||||
|
}
|
||||||
|
[data-alert] [data-close] {
|
||||||
|
color: #fff;
|
||||||
|
padding-right: 10px;
|
||||||
|
width: 100px;
|
||||||
|
line-height: 1;
|
||||||
|
margin: .5rem;
|
||||||
|
background-color: #202425;
|
||||||
|
font-size: .7rem;
|
||||||
|
}
|
54
umap/static/umap/js/modules/alerts.js
Normal file
54
umap/static/umap/js/modules/alerts.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
export default class Alerts {
|
||||||
|
constructor() {
|
||||||
|
this.alertNode = document.querySelector('[role="alert"]')
|
||||||
|
const observer = new MutationObserver(this._callback.bind(this))
|
||||||
|
observer.observe(this.alertNode, { childList: true })
|
||||||
|
// On initial page load, we want to display messages from Django.
|
||||||
|
Array.from(this.alertNode.children).forEach(this._display.bind(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
_callback(mutationList, observer) {
|
||||||
|
for (const mutation of mutationList) {
|
||||||
|
this._display(
|
||||||
|
[...mutation.addedNodes].filter((item) => item.tagName === 'P').pop()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_display(alert) {
|
||||||
|
const duration = alert.dataset?.duration || 3000
|
||||||
|
const level = alert.dataset?.level || 'info'
|
||||||
|
const wrapper = document.createElement('div')
|
||||||
|
const alertHTML = alert.cloneNode(true).outerHTML
|
||||||
|
wrapper.innerHTML = `
|
||||||
|
<div data-level="${level}" data-alert data-toclose>
|
||||||
|
${alertHTML}
|
||||||
|
<button class="umap-close-link" type="button" data-close>
|
||||||
|
<i class="umap-close-icon"></i><span>${L._('Close')}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
const alertDiv = wrapper.firstElementChild
|
||||||
|
this.alertNode.after(alertDiv)
|
||||||
|
if (isFinite(duration)) {
|
||||||
|
setTimeout(() => {
|
||||||
|
alertDiv.remove()
|
||||||
|
}, duration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add(message, level = 'info', duration = 3000) {
|
||||||
|
this.alertNode.innerHTML = `
|
||||||
|
<p data-level="${level}" data-duration="${duration}">
|
||||||
|
${message}
|
||||||
|
</p>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODISCUSS: this might be something we want somewhere else.
|
||||||
|
document.addEventListener('click', (event) => {
|
||||||
|
if (event.target.closest('[data-close]')) {
|
||||||
|
event.target.closest('[data-toclose]').remove()
|
||||||
|
}
|
||||||
|
})
|
|
@ -1,5 +1,6 @@
|
||||||
import * as L from '../../vendors/leaflet/leaflet-src.esm.js'
|
import * as L from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
import URLs from './urls.js'
|
import URLs from './urls.js'
|
||||||
|
import Alerts from './alerts.js'
|
||||||
import Browser from './browser.js'
|
import Browser from './browser.js'
|
||||||
import { Request, ServerRequest, RequestError, HTTPError, NOKError } from './request.js'
|
import { Request, ServerRequest, RequestError, HTTPError, NOKError } from './request.js'
|
||||||
// Import modules and export them to the global scope.
|
// Import modules and export them to the global scope.
|
||||||
|
@ -7,4 +8,13 @@ import { Request, ServerRequest, RequestError, HTTPError, NOKError } from './req
|
||||||
|
|
||||||
// Copy the leaflet module, it's expected by leaflet plugins to be writeable.
|
// Copy the leaflet module, it's expected by leaflet plugins to be writeable.
|
||||||
window.L = { ...L }
|
window.L = { ...L }
|
||||||
window.U = { URLs, Request, ServerRequest, RequestError, HTTPError, NOKError, Browser }
|
window.U = {
|
||||||
|
Alerts,
|
||||||
|
URLs,
|
||||||
|
Request,
|
||||||
|
ServerRequest,
|
||||||
|
RequestError,
|
||||||
|
HTTPError,
|
||||||
|
NOKError,
|
||||||
|
Browser,
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Uses `L._`` from Leaflet.i18n which we cannot import as a module yet
|
// Uses `L._`` from Leaflet.i18n which we cannot import as a module yet
|
||||||
import { DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
|
import { DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
|
import Alert from './alerts.js'
|
||||||
|
|
||||||
export class RequestError extends Error {}
|
export class RequestError extends Error {}
|
||||||
|
|
||||||
|
@ -50,6 +51,7 @@ export class Request extends BaseRequest {
|
||||||
constructor(ui) {
|
constructor(ui) {
|
||||||
super()
|
super()
|
||||||
this.ui = ui
|
this.ui = ui
|
||||||
|
this.alerts = new Alert()
|
||||||
}
|
}
|
||||||
|
|
||||||
async _fetch(method, uri, headers, data) {
|
async _fetch(method, uri, headers, data) {
|
||||||
|
@ -81,7 +83,7 @@ export class Request extends BaseRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onError(error) {
|
_onError(error) {
|
||||||
this.ui.alert({ content: L._('Problem in the response'), level: 'error' })
|
this.alerts.add(L._('Problem in the response'), 'error')
|
||||||
}
|
}
|
||||||
|
|
||||||
_onNOK(error) {
|
_onNOK(error) {
|
||||||
|
@ -127,10 +129,10 @@ export class ServerRequest extends Request {
|
||||||
try {
|
try {
|
||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
if (data.info) {
|
if (data.info) {
|
||||||
this.ui.alert({ content: data.info, level: 'info' })
|
this.alerts.add(data.info)
|
||||||
this.ui.closePanel()
|
this.ui.closePanel()
|
||||||
} else if (data.error) {
|
} else if (data.error) {
|
||||||
this.ui.alert({ content: data.error, level: 'error' })
|
this.alerts.add(data.error, 'error')
|
||||||
return this._onError(new Error(data.error))
|
return this._onError(new Error(data.error))
|
||||||
}
|
}
|
||||||
return [data, response, null]
|
return [data, response, null]
|
||||||
|
@ -145,10 +147,7 @@ export class ServerRequest extends Request {
|
||||||
|
|
||||||
_onNOK(error) {
|
_onNOK(error) {
|
||||||
if (error.status === 403) {
|
if (error.status === 403) {
|
||||||
this.ui.alert({
|
this.alerts.add(message || L._('Action not allowed :('), 'error')
|
||||||
content: message || L._('Action not allowed :('),
|
|
||||||
level: 'error',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
return [{}, error.response, error]
|
return [{}, error.response, error]
|
||||||
}
|
}
|
||||||
|
|
|
@ -782,8 +782,7 @@ const ControlsMixin = {
|
||||||
if (datalayer.hasDataVisible()) found = true
|
if (datalayer.hasDataVisible()) found = true
|
||||||
})
|
})
|
||||||
// TODO: display a results counter in the panel instead.
|
// TODO: display a results counter in the panel instead.
|
||||||
if (!found)
|
if (!found) this.alerts.add(L._('No results for these facets'))
|
||||||
this.ui.alert({ content: L._('No results for these facets'), level: 'info' })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const fields = keys.map((current) => [
|
const fields = keys.map((current) => [
|
||||||
|
@ -1272,7 +1271,7 @@ U.Search = L.PhotonSearch.extend({
|
||||||
if (latlng.isValid()) {
|
if (latlng.isValid()) {
|
||||||
this.reverse.doReverse(latlng)
|
this.reverse.doReverse(latlng)
|
||||||
} else {
|
} else {
|
||||||
this.map.ui.alert({ content: 'Invalid latitude or longitude', mode: 'error' })
|
this.map.alerts.add(L._('Invalid latitude or longitude'), 'error')
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -686,10 +686,7 @@ U.Marker = L.Marker.extend({
|
||||||
const builder = new U.FormBuilder(this, coordinatesOptions, {
|
const builder = new U.FormBuilder(this, coordinatesOptions, {
|
||||||
callback: function () {
|
callback: function () {
|
||||||
if (!this._latlng.isValid()) {
|
if (!this._latlng.isValid()) {
|
||||||
this.map.ui.alert({
|
this.map.alerts.add(L._('Invalid latitude or longitude'), 'error')
|
||||||
content: L._('Invalid latitude or longitude'),
|
|
||||||
level: 'error',
|
|
||||||
})
|
|
||||||
builder.resetField('_latlng.lat')
|
builder.resetField('_latlng.lat')
|
||||||
builder.resetField('_latlng.lng')
|
builder.resetField('_latlng.lng')
|
||||||
}
|
}
|
||||||
|
@ -886,7 +883,7 @@ U.PathMixin = {
|
||||||
items.push({
|
items.push({
|
||||||
text: L._('Display measure'),
|
text: L._('Display measure'),
|
||||||
callback: function () {
|
callback: function () {
|
||||||
this.map.ui.alert({ content: this.getMeasure(), level: 'info' })
|
this.map.alerts.add(this.getMeasure())
|
||||||
},
|
},
|
||||||
context: this,
|
context: this,
|
||||||
})
|
})
|
||||||
|
|
|
@ -140,16 +140,15 @@ U.Importer = L.Class.extend({
|
||||||
this.map.processFileToImport(file, layer, type)
|
this.map.processFileToImport(file, layer, type)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!type)
|
if (!type) {
|
||||||
return this.map.ui.alert({
|
this.map.alerts.add(L._('Please choose a format'), 'error')
|
||||||
content: L._('Please choose a format'),
|
return
|
||||||
level: 'error',
|
}
|
||||||
})
|
|
||||||
if (this.rawInput.value && type === 'umap') {
|
if (this.rawInput.value && type === 'umap') {
|
||||||
try {
|
try {
|
||||||
this.map.importRaw(this.rawInput.value, type)
|
this.map.importRaw(this.rawInput.value, type)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.ui.alert({ content: L._('Invalid umap data'), level: 'error' })
|
this.alerts.add(L._('Invalid umap data'), 'error')
|
||||||
console.error(e)
|
console.error(e)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -144,6 +144,7 @@ U.Map = L.Map.extend({
|
||||||
// After calling parent initialize, as we are doing initCenter our-selves
|
// After calling parent initialize, as we are doing initCenter our-selves
|
||||||
if (geojson.geometry) this.options.center = this.latLng(geojson.geometry)
|
if (geojson.geometry) this.options.center = this.latLng(geojson.geometry)
|
||||||
this.urls = new U.URLs(this.options.urls)
|
this.urls = new U.URLs(this.options.urls)
|
||||||
|
this.alerts = new U.Alerts()
|
||||||
|
|
||||||
this.ui = new U.UI(this._container)
|
this.ui = new U.UI(this._container)
|
||||||
this.ui.on('dataloading', (e) => this.fire('dataloading', e))
|
this.ui.on('dataloading', (e) => this.fire('dataloading', e))
|
||||||
|
@ -393,7 +394,9 @@ U.Map = L.Map.extend({
|
||||||
icon: 'umap-fake-class',
|
icon: 'umap-fake-class',
|
||||||
iconLoading: 'umap-fake-class',
|
iconLoading: 'umap-fake-class',
|
||||||
flyTo: this.options.easing,
|
flyTo: this.options.easing,
|
||||||
onLocationError: (err) => this.ui.alert({ content: err.message }),
|
onLocationError: (err) => {
|
||||||
|
this.alerts.add(err.message, 'error')
|
||||||
|
},
|
||||||
})
|
})
|
||||||
this._controls.fullscreen = new L.Control.Fullscreen({
|
this._controls.fullscreen = new L.Control.Fullscreen({
|
||||||
title: { false: L._('View Fullscreen'), true: L._('Exit Fullscreen') },
|
title: { false: L._('View Fullscreen'), true: L._('Exit Fullscreen') },
|
||||||
|
@ -677,10 +680,10 @@ U.Map = L.Map.extend({
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
this.removeLayer(tilelayer)
|
this.removeLayer(tilelayer)
|
||||||
this.ui.alert({
|
this.alerts.add(
|
||||||
content: `${L._('Error in the tilelayer URL')}: ${tilelayer._url}`,
|
`${L._('Error in the tilelayer URL')}: ${tilelayer._url}`,
|
||||||
level: 'error',
|
'error'
|
||||||
})
|
)
|
||||||
// Users can put tilelayer URLs by hand, and if they add wrong {variable},
|
// Users can put tilelayer URLs by hand, and if they add wrong {variable},
|
||||||
// Leaflet throw an error, and then the map is no more editable
|
// Leaflet throw an error, and then the map is no more editable
|
||||||
}
|
}
|
||||||
|
@ -712,10 +715,7 @@ U.Map = L.Map.extend({
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.removeLayer(overlay)
|
this.removeLayer(overlay)
|
||||||
console.error(e)
|
console.error(e)
|
||||||
this.ui.alert({
|
this.alerts.add(`${L._('Error in the overlay URL')}: ${overlay._url}`, 'error')
|
||||||
content: `${L._('Error in the overlay URL')}: ${overlay._url}`,
|
|
||||||
level: 'error',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -842,10 +842,7 @@ U.Map = L.Map.extend({
|
||||||
if (this.options.umap_id) {
|
if (this.options.umap_id) {
|
||||||
// We do not want an extra message during the map creation
|
// We do not want an extra message during the map creation
|
||||||
// to avoid the double notification/alert.
|
// to avoid the double notification/alert.
|
||||||
this.ui.alert({
|
this.alerts.add(L._('The zoom and center have been modified.'))
|
||||||
content: L._('The zoom and center have been modified.'),
|
|
||||||
level: 'info',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -889,12 +886,12 @@ U.Map = L.Map.extend({
|
||||||
processFileToImport: function (file, layer, type) {
|
processFileToImport: function (file, layer, type) {
|
||||||
type = type || L.Util.detectFileType(file)
|
type = type || L.Util.detectFileType(file)
|
||||||
if (!type) {
|
if (!type) {
|
||||||
this.ui.alert({
|
this.alerts.add(
|
||||||
content: L._('Unable to detect format of file {filename}', {
|
L._('Unable to detect format of file {filename}', {
|
||||||
filename: file.name,
|
filename: file.name,
|
||||||
}),
|
}),
|
||||||
level: 'error',
|
'error'
|
||||||
})
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (type === 'umap') {
|
if (type === 'umap') {
|
||||||
|
@ -946,10 +943,10 @@ U.Map = L.Map.extend({
|
||||||
self.importRaw(rawData)
|
self.importRaw(rawData)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error importing data', e)
|
console.error('Error importing data', e)
|
||||||
self.ui.alert({
|
self.alerts.add(
|
||||||
content: L._('Invalid umap data in {filename}', { filename: file.name }),
|
L._('Invalid umap data in {filename}', { filename: file.name }),
|
||||||
level: 'error',
|
'error'
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1060,10 +1057,10 @@ U.Map = L.Map.extend({
|
||||||
const uri = this.urls.get('map_save', { map_id: this.options.umap_id })
|
const uri = this.urls.get('map_save', { map_id: this.options.umap_id })
|
||||||
const [data, response, error] = await this.server.post(uri, {}, formData)
|
const [data, response, error] = await this.server.post(uri, {}, formData)
|
||||||
if (!error) {
|
if (!error) {
|
||||||
let duration = 3000,
|
let alertDuration = 3000
|
||||||
alert = { content: L._('Map has been saved!'), level: 'info' }
|
let alertMessage = L._('Map has been saved!')
|
||||||
if (!this.options.umap_id) {
|
if (!this.options.umap_id) {
|
||||||
alert.content = L._('Congratulations, your map has been created!')
|
alertMessage = L._('Congratulations, your map has been created!')
|
||||||
this.options.umap_id = data.id
|
this.options.umap_id = data.id
|
||||||
this.permissions.setOptions(data.permissions)
|
this.permissions.setOptions(data.permissions)
|
||||||
this.permissions.commit()
|
this.permissions.commit()
|
||||||
|
@ -1072,8 +1069,8 @@ U.Map = L.Map.extend({
|
||||||
data.permissions.anonymous_edit_url &&
|
data.permissions.anonymous_edit_url &&
|
||||||
this.options.urls.map_send_edit_link
|
this.options.urls.map_send_edit_link
|
||||||
) {
|
) {
|
||||||
alert.duration = Infinity
|
alertDuration = Infinity
|
||||||
alert.content =
|
alertMessage =
|
||||||
L._(
|
L._(
|
||||||
'Your map has been created! As you are not logged in, here is your secret link to edit the map, please keep it safe:'
|
'Your map has been created! As you are not logged in, here is your secret link to edit the map, please keep it safe:'
|
||||||
) + `<br>${data.permissions.anonymous_edit_url}`
|
) + `<br>${data.permissions.anonymous_edit_url}`
|
||||||
|
@ -1108,8 +1105,9 @@ U.Map = L.Map.extend({
|
||||||
if (history && history.pushState)
|
if (history && history.pushState)
|
||||||
history.pushState({}, this.options.name, data.url)
|
history.pushState({}, this.options.name, data.url)
|
||||||
else window.location = data.url
|
else window.location = data.url
|
||||||
alert.content = data.info || alert.content
|
this.once('saved', () => {
|
||||||
this.once('saved', () => this.ui.alert(alert))
|
this.alerts.add(data.info || alertMessage, 'info', alertDuration)
|
||||||
|
})
|
||||||
this.ui.closePanel()
|
this.ui.closePanel()
|
||||||
this.permissions.save()
|
this.permissions.save()
|
||||||
}
|
}
|
||||||
|
@ -1142,11 +1140,10 @@ U.Map = L.Map.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
star: async function () {
|
star: async function () {
|
||||||
if (!this.options.umap_id)
|
if (!this.options.umap_id) {
|
||||||
return this.ui.alert({
|
this.alerts.add(L._('Please save the map first'), 'error')
|
||||||
content: L._('Please save the map first'),
|
return
|
||||||
level: 'error',
|
}
|
||||||
})
|
|
||||||
const url = this.urls.get('map_star', { map_id: this.options.umap_id })
|
const url = this.urls.get('map_star', { map_id: this.options.umap_id })
|
||||||
const [data, response, error] = await this.server.post(url)
|
const [data, response, error] = await this.server.post(url)
|
||||||
if (!error) {
|
if (!error) {
|
||||||
|
@ -1154,7 +1151,7 @@ U.Map = L.Map.extend({
|
||||||
let msg = data.starred
|
let msg = data.starred
|
||||||
? L._('Map has been starred')
|
? L._('Map has been starred')
|
||||||
: L._('Map has been unstarred')
|
: L._('Map has been unstarred')
|
||||||
this.ui.alert({ content: msg, level: 'info' })
|
this.alerts.add(msg)
|
||||||
this.renderControls()
|
this.renderControls()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -928,7 +928,7 @@ U.DataLayer = L.Evented.extend({
|
||||||
message: err[0].message,
|
message: err[0].message,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.map.ui.alert({ content: message, level: 'error', duration: 10000 })
|
this.map.alerts.add(message, 'error', 10000)
|
||||||
console.error(err)
|
console.error(err)
|
||||||
}
|
}
|
||||||
if (result && result.features.length) {
|
if (result && result.features.length) {
|
||||||
|
@ -955,7 +955,7 @@ U.DataLayer = L.Evented.extend({
|
||||||
const gj = JSON.parse(c)
|
const gj = JSON.parse(c)
|
||||||
callback(gj)
|
callback(gj)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.map.ui.alert({ content: `Invalid JSON file: ${err}` })
|
this.map.alerts.add(L._('Invalid JSON file: {error}', { error: err }), 'error')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1013,12 +1013,12 @@ U.DataLayer = L.Evented.extend({
|
||||||
return this.geojsonToFeatures(geometry.geometries)
|
return this.geojsonToFeatures(geometry.geometries)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this.map.ui.alert({
|
this.map.alerts.add(
|
||||||
content: L._('Skipping unknown geometry.type: {type}', {
|
L._('Skipping unknown geometry.type: {type}', {
|
||||||
type: geometry.type || 'undefined',
|
type: geometry.type || 'undefined',
|
||||||
}),
|
}),
|
||||||
level: 'error',
|
'error'
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
if (layer) {
|
if (layer) {
|
||||||
this.addLayer(layer)
|
this.addLayer(layer)
|
||||||
|
@ -1459,7 +1459,7 @@ U.DataLayer = L.Evented.extend({
|
||||||
if (!this.isVisible()) return
|
if (!this.isVisible()) return
|
||||||
const bounds = this.layer.getBounds()
|
const bounds = this.layer.getBounds()
|
||||||
if (bounds.isValid()) {
|
if (bounds.isValid()) {
|
||||||
const options = {maxZoom: this.getOption("zoomTo")}
|
const options = { maxZoom: this.getOption('zoomTo') }
|
||||||
this.map.fitBounds(bounds, options)
|
this.map.fitBounds(bounds, options)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -53,10 +53,7 @@ U.MapPermissions = L.Class.extend({
|
||||||
edit: function () {
|
edit: function () {
|
||||||
if (this.map.options.editMode !== 'advanced') return
|
if (this.map.options.editMode !== 'advanced') return
|
||||||
if (!this.map.options.umap_id)
|
if (!this.map.options.umap_id)
|
||||||
return this.map.ui.alert({
|
return this.map.alerts.add(L._('Please save the map first'))
|
||||||
content: L._('Please save the map first'),
|
|
||||||
level: 'info',
|
|
||||||
})
|
|
||||||
const container = L.DomUtil.create('div', 'permissions-panel'),
|
const container = L.DomUtil.create('div', 'permissions-panel'),
|
||||||
fields = [],
|
fields = [],
|
||||||
title = L.DomUtil.create('h3', '', container)
|
title = L.DomUtil.create('h3', '', container)
|
||||||
|
@ -135,10 +132,7 @@ U.MapPermissions = L.Class.extend({
|
||||||
const [data, response, error] = await this.map.server.post(this.getAttachUrl())
|
const [data, response, error] = await this.map.server.post(this.getAttachUrl())
|
||||||
if (!error) {
|
if (!error) {
|
||||||
this.options.owner = this.map.options.user
|
this.options.owner = this.map.options.user
|
||||||
this.map.ui.alert({
|
this.map.alerts.add(L._('Map has been attached to your account'))
|
||||||
content: L._('Map has been attached to your account'),
|
|
||||||
level: 'info',
|
|
||||||
})
|
|
||||||
this.map.ui.closePanel()
|
this.map.ui.closePanel()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -83,10 +83,10 @@ U.TableEditor = L.Class.extend({
|
||||||
|
|
||||||
validateName: function (name) {
|
validateName: function (name) {
|
||||||
if (name.indexOf('.') !== -1) {
|
if (name.indexOf('.') !== -1) {
|
||||||
this.datalayer.map.ui.alert({
|
this.datalayer.map.alerts.add(
|
||||||
content: L._('Invalide property name: {name}', { name: name }),
|
L._('Invalid property name: {name}', { name: name }),
|
||||||
level: 'error',
|
'error'
|
||||||
})
|
)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -64,6 +64,7 @@
|
||||||
|
|
||||||
<link rel="stylesheet" href="../../umap/font.css" />
|
<link rel="stylesheet" href="../../umap/font.css" />
|
||||||
<link rel="stylesheet" href="../../umap/base.css" />
|
<link rel="stylesheet" href="../../umap/base.css" />
|
||||||
|
<link rel="stylesheet" href="../../umap/alerts.css" />
|
||||||
<link rel="stylesheet" href="../../umap/content.css" />
|
<link rel="stylesheet" href="../../umap/content.css" />
|
||||||
<link rel="stylesheet" href="../../umap/nav.css" />
|
<link rel="stylesheet" href="../../umap/nav.css" />
|
||||||
<link rel="stylesheet" href="../../umap/map.css" />
|
<link rel="stylesheet" href="../../umap/map.css" />
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
href="{% static 'umap/vendors/iconlayers/iconLayers.css' %}" />
|
href="{% static 'umap/vendors/iconlayers/iconLayers.css' %}" />
|
||||||
<link rel="stylesheet" href="{% static 'umap/font.css' %}" />
|
<link rel="stylesheet" href="{% static 'umap/font.css' %}" />
|
||||||
<link rel="stylesheet" href="{% static 'umap/base.css' %}" />
|
<link rel="stylesheet" href="{% static 'umap/base.css' %}" />
|
||||||
|
<link rel="stylesheet" href="{% static 'umap/alerts.css' %}" />
|
||||||
<link rel="stylesheet" href="{% static 'umap/content.css' %}" />
|
<link rel="stylesheet" href="{% static 'umap/content.css' %}" />
|
||||||
<link rel="stylesheet" href="{% static 'umap/nav.css' %}" />
|
<link rel="stylesheet" href="{% static 'umap/nav.css' %}" />
|
||||||
<link rel="stylesheet" href="{% static 'umap/map.css' %}" />
|
<link rel="stylesheet" href="{% static 'umap/map.css' %}" />
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
{% load umap_tags %}
|
{% load umap_tags %}
|
||||||
|
|
||||||
|
<div role="alert">
|
||||||
|
{% for m in messages %}
|
||||||
|
{# We have just one, but we need to loop, as for messages API #}
|
||||||
|
<p data-level="{{ m.tags }}" data-duration="100000">{{ m }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
<div id="map"></div>
|
<div id="map"></div>
|
||||||
<!-- djlint:off -->
|
<!-- djlint:off -->
|
||||||
<script defer type="text/javascript">
|
<script defer type="text/javascript">
|
||||||
window.addEventListener('DOMContentLoaded', (event) => {
|
window.addEventListener('DOMContentLoaded', (event) => {
|
||||||
U.MAP = new U.Map("map", {{ map_settings|notag|safe }})
|
U.MAP = new U.Map("map", {{ map_settings|notag|safe }})
|
||||||
{% for m in messages %}
|
|
||||||
{# We have just one, but we need to loop, as for messages API #}
|
|
||||||
U.MAP.ui.alert({
|
|
||||||
content: "{{ m }}",
|
|
||||||
level: "{{ m.tags }}",
|
|
||||||
duration: 100000
|
|
||||||
})
|
|
||||||
{% endfor %}
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<!-- djlint:on -->
|
<!-- djlint:on -->
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div class="row">
|
<div class="row" role="alert">
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
<ul class="messages">
|
<ul class="messages">
|
||||||
{% for message in messages %}
|
{% for message in messages %}
|
||||||
|
|
Loading…
Reference in a new issue