{% translate "You can also receive that URL by email:" %}
+
+
+
+
+
+
+
+
+
+
+
+ {% blocktranslate %}
+ Woops! Someone else seems to have edited the data. You can save anyway, but this will erase the changes made by others.
+ {% endblocktranslate %}
+
+
+
+
+
+
+
+
+
+
diff --git a/umap/static/umap/js/components/alerts/alert.js b/umap/static/umap/js/components/alerts/alert.js
new file mode 100644
index 00000000..a80d3dfb
--- /dev/null
+++ b/umap/static/umap/js/components/alerts/alert.js
@@ -0,0 +1,169 @@
+class uMapAlert extends HTMLElement {
+ static info(message, duration = 5000) {
+ const event = new CustomEvent('umap:alert', {
+ bubbles: true,
+ cancelable: true,
+ detail: { message, duration },
+ })
+ document.dispatchEvent(event)
+ }
+
+ // biome-ignore lint/style/useNumberNamespace: Number.Infinity returns undefined by default
+ static error(message, duration = Infinity) {
+ const event = new CustomEvent('umap:alert', {
+ bubbles: true,
+ cancelable: true,
+ detail: { level: 'error', message, duration },
+ })
+ document.dispatchEvent(event)
+ }
+
+ constructor() {
+ super()
+ this.container = this.querySelector('[role="dialog"]')
+ this.element = this.container.querySelector('[role="alert"]')
+ }
+
+ _hide() {
+ this.setAttribute('hidden', 'hidden')
+ }
+
+ _show() {
+ this.removeAttribute('hidden')
+ }
+
+ _displayAlert(detail) {
+ const { level = 'info', duration = 5000, message = '' } = detail
+ this.container.dataset.level = level
+ this.container.dataset.duration = duration
+ this.element.textContent = message
+ this._show()
+ if (Number.isFinite(duration)) {
+ setTimeout(() => {
+ this._hide()
+ }, duration)
+ }
+ }
+
+ connectedCallback() {
+ this.addEventListener('click', (event) => {
+ if (event.target.closest('[data-close]')) {
+ this._hide()
+ }
+ })
+ document.addEventListener('umap:alert', (event) => {
+ this._displayAlert(event.detail)
+ })
+ }
+}
+
+class uMapAlertCreation extends uMapAlert {
+ static info(
+ message,
+ // biome-ignore lint/style/useNumberNamespace: Number.Infinity returns undefined by default
+ duration = Infinity,
+ editLink = undefined,
+ sendLink = undefined
+ ) {
+ const event = new CustomEvent('umap:alert-creation', {
+ bubbles: true,
+ cancelable: true,
+ detail: { message, duration, editLink, sendLink },
+ })
+ document.dispatchEvent(event)
+ }
+
+ constructor() {
+ super()
+ this.linkWrapper = this.container.querySelector('#link-wrapper')
+ this.formWrapper = this.container.querySelector('#form-wrapper')
+ }
+
+ _displayCreationAlert(detail) {
+ const {
+ level = 'info',
+ duration = 5000,
+ message = '',
+ editLink = undefined,
+ sendLink = undefined,
+ } = detail
+ uMapAlert.prototype._displayAlert.call(this, { level, duration, message })
+ this.linkWrapper.querySelector('input[type="url"]').value = editLink
+ const button = this.linkWrapper.querySelector('input[type="button"]')
+ button.addEventListener('click', (event) => {
+ event.preventDefault()
+ L.Util.copyToClipboard(editLink)
+ event.target.value = L._('✅ Copied!')
+ })
+ if (sendLink) {
+ this.formWrapper.removeAttribute('hidden')
+ const form = this.formWrapper.querySelector('form')
+ form.addEventListener('submit', async (event) => {
+ event.preventDefault()
+ const formData = new FormData(form)
+ const server = new U.ServerRequest()
+ this._hide()
+ await server.post(sendLink, {}, formData)
+ })
+ }
+ }
+
+ connectedCallback() {
+ this.addEventListener('click', (event) => {
+ if (event.target.closest('[data-close]')) {
+ this._hide()
+ }
+ })
+ document.addEventListener('umap:alert-creation', (event) => {
+ this._displayCreationAlert(event.detail)
+ })
+ }
+}
+
+class uMapAlertChoice extends uMapAlert {
+ static error(
+ message,
+ // biome-ignore lint/style/useNumberNamespace: Number.Infinity returns undefined by default
+ duration = Infinity
+ ) {
+ const event = new CustomEvent('umap:alert-choice', {
+ bubbles: true,
+ cancelable: true,
+ detail: { message, duration },
+ })
+ document.dispatchEvent(event)
+ }
+
+ constructor() {
+ super()
+ this.choiceWrapper = this.container.querySelector('#choice-wrapper')
+ }
+
+ _displayChoiceAlert(detail) {
+ const { level = 'error', duration = 5000, message = '' } = detail
+ uMapAlert.prototype._displayAlert.call(this, { level, duration, message })
+ const button = this.choiceWrapper.querySelector('input[type="submit"]')
+ button.addEventListener('click', (event) => {
+ event.preventDefault()
+ document.dispatchEvent(
+ new CustomEvent('umap:alert-choice-confirm', {
+ bubbles: true,
+ cancelable: true,
+ })
+ )
+ })
+ }
+
+ connectedCallback() {
+ this.addEventListener('click', (event) => {
+ if (event.target.closest('[data-close]')) {
+ this._hide()
+ }
+ })
+ document.addEventListener('umap:alert-choice', (event) => {
+ this._displayChoiceAlert(event.detail)
+ })
+ }
+}
+
+export { uMapAlert, uMapAlertCreation, uMapAlertChoice }
diff --git a/umap/static/umap/js/modules/autocomplete.js b/umap/static/umap/js/modules/autocomplete.js
index 3c2949a1..4fde8b84 100644
--- a/umap/static/umap/js/modules/autocomplete.js
+++ b/umap/static/umap/js/modules/autocomplete.js
@@ -1,7 +1,6 @@
import { DomUtil, DomEvent, setOptions } from '../../vendors/leaflet/leaflet-src.esm.js'
import { translate } from './i18n.js'
import { ServerRequest } from './request.js'
-import Alert from './ui/alert.js'
export class BaseAutocomplete {
constructor(el, options) {
@@ -220,8 +219,7 @@ export class BaseAutocomplete {
class BaseAjax extends BaseAutocomplete {
constructor(el, options) {
super(el, options)
- const alert = new Alert(document.querySelector('header'))
- this.server = new ServerRequest(alert)
+ this.server = new ServerRequest()
}
optionToResult(option) {
return {
diff --git a/umap/static/umap/js/modules/global.js b/umap/static/umap/js/modules/global.js
index d158a40b..31081ebf 100644
--- a/umap/static/umap/js/modules/global.js
+++ b/umap/static/umap/js/modules/global.js
@@ -3,7 +3,6 @@ import Browser from './browser.js'
import Facets from './facets.js'
import Caption from './caption.js'
import { Panel, EditPanel, FullPanel } from './ui/panel.js'
-import Alert from './ui/alert.js'
import Dialog from './ui/dialog.js'
import Tooltip from './ui/tooltip.js'
import * as Utils from './utils.js'
@@ -14,6 +13,11 @@ import Orderable from './orderable.js'
import Importer from './importer.js'
import Help from './help.js'
import { SyncEngine } from './sync/engine.js'
+import {
+ uMapAlert as Alert,
+ uMapAlertCreation as AlertCreation,
+ uMapAlertChoice as AlertChoice,
+} from '../components/alerts/alert.js'
// Import modules and export them to the global scope.
// For the not yet module-compatible JS out there.
@@ -21,6 +25,8 @@ import { SyncEngine } from './sync/engine.js'
// By alphabetic order
window.U = {
Alert,
+ AlertCreation,
+ AlertChoice,
AjaxAutocomplete,
AjaxAutocompleteMultiple,
Browser,
diff --git a/umap/static/umap/js/modules/importer.js b/umap/static/umap/js/modules/importer.js
index ea017552..06575025 100644
--- a/umap/static/umap/js/modules/importer.js
+++ b/umap/static/umap/js/modules/importer.js
@@ -163,16 +163,12 @@ export default class Importer {
this.map.processFileToImport(file, layer, type)
}
} else {
- if (!type)
- return this.map.alert.open({
- content: translate('Please choose a format'),
- level: 'error',
- })
+ if (!type) return U.Alert.error(L._('Please choose a format'))
if (this.rawInput.value && type === 'umap') {
try {
this.map.importRaw(this.rawInput.value, type)
} catch (e) {
- this.alert.open({ content: translate('Invalid umap data'), level: 'error' })
+ U.Alert.error(L._('Invalid umap data'))
console.error(e)
}
} else {
diff --git a/umap/static/umap/js/modules/request.js b/umap/static/umap/js/modules/request.js
index fe392871..af9b2cfc 100644
--- a/umap/static/umap/js/modules/request.js
+++ b/umap/static/umap/js/modules/request.js
@@ -1,5 +1,4 @@
-// Uses `L._`` from Leaflet.i18n which we cannot import as a module yet
-import { DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
+import { translate } from './i18n.js'
export class RequestError extends Error {}
@@ -47,11 +46,6 @@ class BaseRequest {
// In case of error, an alert is sent, but non 20X status are not handled
// The consumer must check the response status by hand
export class Request extends BaseRequest {
- constructor(alert) {
- super()
- this.alert = alert
- }
-
fire(name, params) {
document.body.dispatchEvent(new CustomEvent(name, params))
}
@@ -85,7 +79,7 @@ export class Request extends BaseRequest {
}
_onError(error) {
- this.alert.open({ content: L._('Problem in the response'), level: 'error' })
+ U.Alert.error(translate('Problem in the response'))
}
_onNOK(error) {
@@ -131,9 +125,9 @@ export class ServerRequest extends Request {
try {
const data = await response.json()
if (data.info) {
- this.alert.open({ content: data.info, level: 'info' })
+ U.Alert.info(data.info)
} else if (data.error) {
- this.alert.open({ content: data.error, level: 'error' })
+ U.Alert.error(data.error)
return this._onError(new Error(data.error))
}
return [data, response, null]
@@ -148,10 +142,7 @@ export class ServerRequest extends Request {
_onNOK(error) {
if (error.status === 403) {
- this.alert.open({
- content: error.message || L._('Action not allowed :('),
- level: 'error',
- })
+ U.Alert.error(error.message || translate('Action not allowed :('))
}
return [{}, error.response, error]
}
diff --git a/umap/static/umap/js/modules/ui/alert.js b/umap/static/umap/js/modules/ui/alert.js
deleted file mode 100644
index b02c2d82..00000000
--- a/umap/static/umap/js/modules/ui/alert.js
+++ /dev/null
@@ -1,82 +0,0 @@
-import { DomUtil, DomEvent } from '../../../vendors/leaflet/leaflet-src.esm.js'
-import { translate } from '../i18n.js'
-
-const ALERTS = []
-let ALERT_ID = null
-
-export default class Alert {
- constructor(parent) {
- this.parent = parent
- this.container = DomUtil.create('div', 'with-transition', this.parent)
- this.container.id = 'umap-alert-container'
- DomEvent.disableClickPropagation(this.container)
- DomEvent.on(this.container, 'contextmenu', DomEvent.stopPropagation) // Do not activate our custom context menu.
- DomEvent.on(this.container, 'wheel', DomEvent.stopPropagation)
- DomEvent.on(this.container, 'MozMousePixelScroll', DomEvent.stopPropagation)
- }
-
- open(params) {
- if (DomUtil.hasClass(this.parent, 'umap-alert')) ALERTS.push(params)
- else this._open(params)
- }
-
- _open(params) {
- if (!params) {
- if (ALERTS.length) params = ALERTS.pop()
- else return
- }
- let timeoutID
- const level_class = params.level && params.level == 'info' ? 'info' : 'error'
- this.container.innerHTML = ''
- DomUtil.addClass(this.parent, 'umap-alert')
- DomUtil.addClass(this.container, level_class)
- const close = () => {
- if (timeoutID && timeoutID !== ALERT_ID) {
- return
- } // Another alert has been forced
- this.container.innerHTML = ''
- DomUtil.removeClass(this.parent, 'umap-alert')
- DomUtil.removeClass(this.container, level_class)
- if (timeoutID) window.clearTimeout(timeoutID)
- this._open()
- }
- const closeButton = DomUtil.createButton(
- 'umap-close-link',
- this.container,
- '',
- close,
- this
- )
- DomUtil.create('i', 'umap-close-icon', closeButton)
- const label = DomUtil.create('span', '', closeButton)
- label.title = label.textContent = translate('Close')
- DomUtil.element({
- tagName: 'div',
- innerHTML: params.content,
- parent: this.container,
- })
- let action, el, input
- const form = DomUtil.create('div', 'umap-alert-actions', this.container)
- for (let action of params.actions || []) {
- if (action.input) {
- input = DomUtil.element({
- tagName: 'input',
- parent: form,
- className: 'umap-alert-input',
- placeholder: action.input,
- })
- }
- el = DomUtil.createButton(
- 'umap-action',
- form,
- action.label,
- action.callback,
- action.callbackContext
- )
- DomEvent.on(el, 'click', close, this)
- }
- if (params.duration !== Infinity) {
- ALERT_ID = timeoutID = window.setTimeout(close, params.duration || 3000)
- }
- }
-}
diff --git a/umap/static/umap/js/umap.controls.js b/umap/static/umap/js/umap.controls.js
index 4ae4ffbc..831aa26c 100644
--- a/umap/static/umap/js/umap.controls.js
+++ b/umap/static/umap/js/umap.controls.js
@@ -1086,7 +1086,7 @@ U.Search = L.PhotonSearch.extend({
if (latlng.isValid()) {
this.reverse.doReverse(latlng)
} else {
- this.map.alert.open({ content: 'Invalid latitude or longitude', mode: 'error' })
+ U.Alert.error(L._('Invalid latitude or longitude'))
}
return
}
diff --git a/umap/static/umap/js/umap.features.js b/umap/static/umap/js/umap.features.js
index a4cf8f1d..b669df4e 100644
--- a/umap/static/umap/js/umap.features.js
+++ b/umap/static/umap/js/umap.features.js
@@ -764,10 +764,7 @@ U.Marker = L.Marker.extend({
const builder = new U.FormBuilder(this, coordinatesOptions, {
callback: function () {
if (!this._latlng.isValid()) {
- this.map.alert.open({
- content: L._('Invalid latitude or longitude'),
- level: 'error',
- })
+ U.Alert.error(L._('Invalid latitude or longitude'))
builder.resetField('_latlng.lat')
builder.resetField('_latlng.lng')
}
@@ -966,7 +963,7 @@ U.PathMixin = {
items.push({
text: L._('Display measure'),
callback: function () {
- this.map.alert.open({ content: this.getMeasure(), level: 'info' })
+ U.Alert.info(this.getMeasure())
},
context: this,
})
diff --git a/umap/static/umap/js/umap.js b/umap/static/umap/js/umap.js
index ce455434..bbfee5d1 100644
--- a/umap/static/umap/js/umap.js
+++ b/umap/static/umap/js/umap.js
@@ -13,7 +13,7 @@ L.Map.mergeOptions({
// we cannot rely on this because of the y is overriden by Leaflet
// See https://github.com/Leaflet/Leaflet/pull/9201
// And let's remove this -y when this PR is merged and released.
- demoTileInfos: { 's': 'a', 'z': 9, 'x': 265, 'y': 181, '-y': 181, 'r': '' },
+ demoTileInfos: { s: 'a', z: 9, x: 265, y: 181, '-y': 181, r: '' },
licences: [],
licence: '',
enableMarkerDraw: true,
@@ -59,7 +59,6 @@ U.Map = L.Map.extend({
this.urls = new U.URLs(this.options.urls)
this.panel = new U.Panel(this)
- this.alert = new U.Alert(this._controlContainer)
this.tooltip = new U.Tooltip(this._controlContainer)
this.dialog = new U.Dialog(this._controlContainer)
if (this.hasEditMode()) {
@@ -68,8 +67,8 @@ U.Map = L.Map.extend({
}
L.DomEvent.on(document.body, 'dataloading', (e) => this.fire('dataloading', e))
L.DomEvent.on(document.body, 'dataload', (e) => this.fire('dataload', e))
- this.server = new U.ServerRequest(this.alert)
- this.request = new U.Request(this.alert)
+ this.server = new U.ServerRequest()
+ this.request = new U.Request()
this.initLoader()
this.name = this.options.name
@@ -391,7 +390,7 @@ U.Map = L.Map.extend({
icon: 'umap-fake-class',
iconLoading: 'umap-fake-class',
flyTo: this.options.easing,
- onLocationError: (err) => this.alert.open({ content: err.message }),
+ onLocationError: (err) => U.Alert.error(err.message),
})
this._controls.fullscreen = new L.Control.Fullscreen({
title: { false: L._('View Fullscreen'), true: L._('Exit Fullscreen') },
@@ -680,10 +679,7 @@ U.Map = L.Map.extend({
} catch (e) {
console.error(e)
this.removeLayer(tilelayer)
- this.alert.open({
- content: `${L._('Error in the tilelayer URL')}: ${tilelayer._url}`,
- level: 'error',
- })
+ U.Alert.error(`${L._('Error in the tilelayer URL')}: ${tilelayer._url}`)
// 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
}
@@ -715,10 +711,7 @@ U.Map = L.Map.extend({
} catch (e) {
this.removeLayer(overlay)
console.error(e)
- this.alert.open({
- content: `${L._('Error in the overlay URL')}: ${overlay._url}`,
- level: 'error',
- })
+ U.Alert.error(`${L._('Error in the overlay URL')}: ${overlay._url}`)
}
},
@@ -843,10 +836,7 @@ U.Map = L.Map.extend({
if (this.options.umap_id) {
// We do not want an extra message during the map creation
// to avoid the double notification/alert.
- this.alert.open({
- content: L._('The zoom and center have been modified.'),
- level: 'info',
- })
+ U.Alert.info(L._('The zoom and center have been modified.'))
}
},
@@ -886,12 +876,11 @@ U.Map = L.Map.extend({
processFileToImport: function (file, layer, type) {
type = type || U.Utils.detectFileType(file)
if (!type) {
- this.alert.open({
- content: L._('Unable to detect format of file {filename}', {
+ U.Alert.error(
+ L._('Unable to detect format of file {filename}', {
filename: file.name,
- }),
- level: 'error',
- })
+ })
+ )
return
}
if (type === 'umap') {
@@ -947,10 +936,7 @@ U.Map = L.Map.extend({
self.importRaw(rawData)
} catch (e) {
console.error('Error importing data', e)
- self.alert.open({
- content: L._('Invalid umap data in {filename}', { filename: file.name }),
- level: 'error',
- })
+ U.Alert.error(L._('Invalid umap data in {filename}', { filename: file.name }))
}
}
},
@@ -1058,57 +1044,54 @@ U.Map = L.Map.extend({
const [data, _, error] = await this.server.post(uri, {}, formData)
// FIXME: login_required response will not be an error, so it will not
// stop code while it should
- if (!error) {
- let duration = 3000,
- alert = { content: L._('Map has been saved!'), level: 'info' }
- if (!this.options.umap_id) {
- alert.content = L._('Congratulations, your map has been created!')
- this.options.umap_id = data.id
- this.permissions.setOptions(data.permissions)
- this.permissions.commit()
- if (data.permissions && data.permissions.anonymous_edit_url) {
- alert.duration = Infinity
- alert.content =
- 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:'
- ) + ` ${data.permissions.anonymous_edit_url}`
+ if (error) {
+ return
+ }
- alert.actions = [
- {
- label: L._('Copy link'),
- callback: () => {
- L.Util.copyToClipboard(data.permissions.anonymous_edit_url)
- this.alert.open({
- content: L._('Secret edit link copied to clipboard!'),
- level: 'info',
- })
- },
- callbackContext: this,
- },
- ]
- if (this.options.urls.map_send_edit_link) {
- alert.actions.push({
- label: L._('Send me the link'),
- input: L._('Email'),
- callback: this.sendEditLink,
- callbackContext: this,
- })
- }
- }
- } else if (!this.permissions.isDirty) {
+ if (!this.options.umap_id) {
+ this.options.umap_id = data.id
+ this.permissions.setOptions(data.permissions)
+ this.permissions.commit()
+ if (data?.permissions?.anonymous_edit_url) {
+ const send_edit_link_url =
+ this.options.urls.map_send_edit_link &&
+ this.urls.get('map_send_edit_link', {
+ map_id: this.options.umap_id,
+ })
+ this.once('saved', () => {
+ U.AlertCreation.info(
+ 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:'
+ ),
+ Number.Infinity,
+ data.permissions.anonymous_edit_url,
+ send_edit_link_url
+ )
+ })
+ } else {
+ this.once('saved', () => {
+ U.Alert.info(L._('Congratulations, your map has been created!'))
+ })
+ }
+ } else {
+ if (!this.permissions.isDirty) {
// Do not override local changes to permissions,
// but update in case some other editors changed them in the meantime.
this.permissions.setOptions(data.permissions)
this.permissions.commit()
}
- // Update URL in case the name has changed.
- if (history && history.pushState)
- history.pushState({}, this.options.name, data.url)
- else window.location = data.url
- alert.content = data.info || alert.content
- this.once('saved', () => this.alert.open(alert))
- this.permissions.save()
+ this.once('saved', () => {
+ U.Alert.info(data.info || L._('Map has been saved!'))
+ })
}
+ // Update URL in case the name has changed.
+ if (history?.pushState) {
+ history.pushState({}, this.options.name, data.url)
+ } else {
+ window.location = data.url
+ }
+ this.permissions.save()
},
save: function () {
@@ -1126,33 +1109,20 @@ U.Map = L.Map.extend({
}
},
- sendEditLink: async function () {
- const input = this.alert.container.querySelector('input')
- const email = input.value
-
- const formData = new FormData()
- formData.append('email', email)
-
- const url = this.urls.get('map_send_edit_link', { map_id: this.options.umap_id })
- await this.server.post(url, {}, formData)
- },
-
star: async function () {
- if (!this.options.umap_id)
- return this.alert.open({
- content: L._('Please save the map first'),
- level: 'error',
- })
+ if (!this.options.umap_id) {
+ return U.Alert.error(L._('Please save the map first'))
+ }
const url = this.urls.get('map_star', { map_id: this.options.umap_id })
const [data, response, error] = await this.server.post(url)
- if (!error) {
- this.options.starred = data.starred
- let msg = data.starred
- ? L._('Map has been starred')
- : L._('Map has been unstarred')
- this.alert.open({ content: msg, level: 'info' })
- this.renderControls()
+ if (error) {
+ return
}
+ this.options.starred = data.starred
+ U.Alert.info(
+ data.starred ? L._('Map has been starred') : L._('Map has been unstarred')
+ )
+ this.renderControls()
},
geometry: function () {
diff --git a/umap/static/umap/js/umap.layer.js b/umap/static/umap/js/umap.layer.js
index 064287a7..141a448d 100644
--- a/umap/static/umap/js/umap.layer.js
+++ b/umap/static/umap/js/umap.layer.js
@@ -958,7 +958,7 @@ U.DataLayer = L.Evented.extend({
const doc = new DOMParser().parseFromString(x, 'text/xml')
const errorNode = doc.querySelector('parsererror')
if (errorNode) {
- this.map.alert.open({ content: L._('Cannot parse data'), level: 'error' })
+ U.Alert.error(L._('Cannot parse data'))
}
return doc
}
@@ -993,7 +993,7 @@ U.DataLayer = L.Evented.extend({
message: err[0].message,
})
}
- this.map.alert.open({ content: message, level: 'error', duration: 10000 })
+ U.Alert.error(message, 10000)
console.error(err)
}
if (result && result.features.length) {
@@ -1020,7 +1020,7 @@ U.DataLayer = L.Evented.extend({
const gj = JSON.parse(c)
callback(gj)
} catch (err) {
- this.map.alert.open({ content: `Invalid JSON file: ${err}` })
+ U.Alert.error(`Invalid JSON file: ${err}`)
return
}
}
@@ -1121,12 +1121,11 @@ U.DataLayer = L.Evented.extend({
return this.geojsonToFeatures(geometry.geometries)
default:
- this.map.alert.open({
- content: L._('Skipping unknown geometry.type: {type}', {
+ U.Alert.error(
+ L._('Skipping unknown geometry.type: {type}', {
type: geometry.type || 'undefined',
- }),
- level: 'error',
- })
+ })
+ )
}
},
@@ -1706,27 +1705,14 @@ U.DataLayer = L.Evented.extend({
const [data, response, error] = await this.map.server.post(url, headers, formData)
if (error) {
if (response && response.status === 412) {
- const msg = L._(
- 'Woops! Someone else seems to have edited the data. You can save anyway, but this will erase the changes made by others.'
+ U.AlertChoice.error(
+ L._(
+ 'Woops! Someone else seems to have edited the data. ' +
+ 'You can save anyway, but this will erase the changes made by others.'
+ )
)
- const actions = [
- {
- label: L._('Save anyway'),
- callback: async () => {
- // Save again,
- // but do not pass the reference version this time
- await this._trySave(url, {}, formData)
- },
- },
- {
- label: L._('Cancel'),
- },
- ]
- this.map.alert.open({
- content: msg,
- level: 'error',
- duration: 100000,
- actions: actions,
+ document.addEventListener('umap:alert-choice-confirm', async (event) => {
+ await this._trySave(url, {}, formData)
})
}
} else {
diff --git a/umap/static/umap/js/umap.permissions.js b/umap/static/umap/js/umap.permissions.js
index 32b3a977..4fb19295 100644
--- a/umap/static/umap/js/umap.permissions.js
+++ b/umap/static/umap/js/umap.permissions.js
@@ -52,11 +52,9 @@ U.MapPermissions = L.Class.extend({
edit: function () {
if (this.map.options.editMode !== 'advanced') return
- if (!this.map.options.umap_id)
- return this.map.alert.open({
- content: L._('Please save the map first'),
- level: 'info',
- })
+ if (!this.map.options.umap_id) {
+ return U.Alert.info(L._('Please save the map first'))
+ }
const container = L.DomUtil.create('div', 'permissions-panel')
const fields = []
L.DomUtil.createTitle(container, L._('Update permissions'), 'icon-key')
@@ -140,10 +138,7 @@ U.MapPermissions = L.Class.extend({
const [data, response, error] = await this.map.server.post(this.getAttachUrl())
if (!error) {
this.options.owner = this.map.options.user
- this.map.alert.open({
- content: L._('Map has been attached to your account'),
- level: 'info',
- })
+ U.Alert.info(L._('Map has been attached to your account'))
this.map.editPanel.close()
}
},
diff --git a/umap/static/umap/js/umap.tableeditor.js b/umap/static/umap/js/umap.tableeditor.js
index 36515a60..389ae61b 100644
--- a/umap/static/umap/js/umap.tableeditor.js
+++ b/umap/static/umap/js/umap.tableeditor.js
@@ -83,10 +83,7 @@ U.TableEditor = L.Class.extend({
validateName: function (name) {
if (name.indexOf('.') !== -1) {
- this.datalayer.map.alert.open({
- content: L._('Invalide property name: {name}', { name: name }),
- level: 'error',
- })
+ U.Alert.error(L._('Invalide property name: {name}', { name: name }))
return false
}
return true
diff --git a/umap/templates/umap/content.html b/umap/templates/umap/content.html
index 01e3ed43..49f035a1 100644
--- a/umap/templates/umap/content.html
+++ b/umap/templates/umap/content.html
@@ -38,8 +38,7 @@
{{ block.super }}
diff --git a/umap/templates/umap/messages.html b/umap/templates/umap/messages.html
index c2d19217..6eefee47 100644
--- a/umap/templates/umap/messages.html
+++ b/umap/templates/umap/messages.html
@@ -1,11 +1,9 @@
-
-
- {% if messages %}
-
- {% for message in messages %}
-
{{ message }}
- {% endfor %}
-
- {% endif %}
-
-
+{% load i18n %}
+
+{% include "umap/js/components/alerts/alert.html" %}
+
+{% for message in messages %}
+
+{% endfor %}
diff --git a/umap/views.py b/umap/views.py
index 9a3e2dd2..d0019851 100644
--- a/umap/views.py
+++ b/umap/views.py
@@ -906,6 +906,7 @@ class MapDelete(DeleteView):
return HttpResponseForbidden(_("Only its owner can delete the map."))
self.object.delete()
home_url = reverse("home")
+ messages.info(self.request, _("Map successfully deleted."))
if is_ajax(self.request):
return simple_json_response(redirect=home_url)
else: