wip: move xhr management to a module and refactor
It sort of work for common cases, but edge cases needs work, specifically the login flow.
This commit is contained in:
parent
1d80645eda
commit
084bc3d518
8 changed files with 300 additions and 223 deletions
|
@ -1,8 +1,9 @@
|
||||||
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 { Request, ServerRequest } from './request.js'
|
||||||
// Import modules and export them to the global scope.
|
// Import modules and export them to the global scope.
|
||||||
// For the not yet module-compatible JS out there.
|
// For the not yet module-compatible JS out there.
|
||||||
|
|
||||||
// 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.umap = { URLs }
|
window.umap = { URLs, Request, ServerRequest }
|
||||||
|
|
146
umap/static/umap/js/modules/request.js
Normal file
146
umap/static/umap/js/modules/request.js
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
// Uses `L._`` from Leaflet.i18n which we cannot import as a module yet
|
||||||
|
import { Evented, DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
|
|
||||||
|
const BaseRequest = Evented.extend({
|
||||||
|
_fetch: async function (method, uri, headers, data) {
|
||||||
|
const id = Math.random()
|
||||||
|
this.fire('dataloading', { id: id })
|
||||||
|
let response
|
||||||
|
|
||||||
|
try {
|
||||||
|
response = await fetch(uri, {
|
||||||
|
method: method,
|
||||||
|
mode: 'cors',
|
||||||
|
headers: headers,
|
||||||
|
body: data,
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
this._onError(error)
|
||||||
|
this.fire('dataload', { id: id })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!response.ok) {
|
||||||
|
this.onNok(response.status, await response.text())
|
||||||
|
}
|
||||||
|
// TODO
|
||||||
|
// - error handling
|
||||||
|
// - UI connection / events
|
||||||
|
// - preflight mode in CORS ?
|
||||||
|
|
||||||
|
this.fire('dataload', { id: id })
|
||||||
|
return response
|
||||||
|
},
|
||||||
|
|
||||||
|
get: async function (uri, headers) {
|
||||||
|
return await this._fetch('GET', uri, headers)
|
||||||
|
},
|
||||||
|
|
||||||
|
post: async function (uri, headers, data) {
|
||||||
|
return await this._fetch('POST', uri, headers, data)
|
||||||
|
},
|
||||||
|
|
||||||
|
_onError: function (error) {
|
||||||
|
console.error(error)
|
||||||
|
this.onError(error)
|
||||||
|
},
|
||||||
|
onError: function (error) {},
|
||||||
|
onNok: function (status) {},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const Request = BaseRequest.extend({
|
||||||
|
initialize: function (ui) {
|
||||||
|
this.ui = ui
|
||||||
|
},
|
||||||
|
onError: function (error) {
|
||||||
|
console.error(error)
|
||||||
|
this.ui.alert({ content: L._('Problem in the response'), level: 'error' })
|
||||||
|
},
|
||||||
|
onNok: function (status, message) {
|
||||||
|
this.onError(message)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Adds uMap specifics to requests handling
|
||||||
|
// like logging, CSRF, etc.
|
||||||
|
export const ServerRequest = Request.extend({
|
||||||
|
post: async function (uri, headers, data) {
|
||||||
|
const token = document.cookie.replace(
|
||||||
|
/(?:(?:^|.*;\s*)csrftoken\s*\=\s*([^;]*).*$)|^.*$/,
|
||||||
|
'$1'
|
||||||
|
)
|
||||||
|
if (token) {
|
||||||
|
headers = headers || {}
|
||||||
|
headers['X-CSRFToken'] = token
|
||||||
|
}
|
||||||
|
const response = await Request.prototype.post.call(this, uri, headers, data)
|
||||||
|
return this._handle_json_response(response)
|
||||||
|
},
|
||||||
|
|
||||||
|
get: async function (uri, headers) {
|
||||||
|
const response = await Request.prototype.get.call(this, uri, headers)
|
||||||
|
return this._handle_json_response(response)
|
||||||
|
},
|
||||||
|
|
||||||
|
_handle_json_response: async function (response) {
|
||||||
|
try {
|
||||||
|
const data = await response.json()
|
||||||
|
this._handle_server_instructions(data)
|
||||||
|
return [data, response]
|
||||||
|
} catch (error) {
|
||||||
|
this._onError(error)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_handle_server_instructions: function (data) {
|
||||||
|
// In some case, the response contains instructions
|
||||||
|
if (data.redirect) {
|
||||||
|
const newPath = data.redirect
|
||||||
|
if (window.location.pathname == newPath) {
|
||||||
|
window.location.reload() // Keep the hash, so the current view
|
||||||
|
} else {
|
||||||
|
window.location = newPath
|
||||||
|
}
|
||||||
|
} else if (data.info) {
|
||||||
|
this.ui.alert({ content: data.info, level: 'info' })
|
||||||
|
this.ui.closePanel()
|
||||||
|
} else if (data.error) {
|
||||||
|
this.ui.alert({ content: data.error, level: 'error' })
|
||||||
|
} else if (data.html) {
|
||||||
|
const ui_options = { data }
|
||||||
|
let listen_options
|
||||||
|
this.ui.openPanel(ui_options)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onNok: function (status, message) {
|
||||||
|
if (status === 403) {
|
||||||
|
this.ui.alert({
|
||||||
|
content: message || L._('Action not allowed :('),
|
||||||
|
level: 'error',
|
||||||
|
})
|
||||||
|
} else if (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.'
|
||||||
|
)
|
||||||
|
const actions = [
|
||||||
|
{
|
||||||
|
label: L._('Save anyway'),
|
||||||
|
callback: function () {
|
||||||
|
// TODO
|
||||||
|
delete settings.headers['If-Match']
|
||||||
|
this._fetch(settings)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: L._('Cancel'),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
this.ui.alert({
|
||||||
|
content: msg,
|
||||||
|
level: 'error',
|
||||||
|
duration: 100000,
|
||||||
|
actions: actions,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
|
@ -13,7 +13,7 @@ L.U.AutoComplete = L.Class.extend({
|
||||||
initialize: function (el, options) {
|
initialize: function (el, options) {
|
||||||
this.el = el
|
this.el = el
|
||||||
const ui = new L.U.UI(document.querySelector('header'))
|
const ui = new L.U.UI(document.querySelector('header'))
|
||||||
this.xhr = new L.U.Xhr(ui)
|
this.server = new window.umap.ServerRequest(ui)
|
||||||
L.setOptions(this, options)
|
L.setOptions(this, options)
|
||||||
let CURRENT = null
|
let CURRENT = null
|
||||||
try {
|
try {
|
||||||
|
@ -158,21 +158,19 @@ L.U.AutoComplete = L.Class.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
search: function () {
|
search: async function () {
|
||||||
const val = this.input.value
|
let val = this.input.value
|
||||||
if (val.length < this.options.minChar) {
|
if (val.length < this.options.minChar) {
|
||||||
this.clear()
|
this.clear()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (`${val}` === `${this.CACHE}`) return
|
if (`${val}` === `${this.CACHE}`) return
|
||||||
else this.CACHE = val
|
else this.CACHE = val
|
||||||
this._do_search(
|
val = val.toLowerCase()
|
||||||
val,
|
const [{ data }, response] = await this.server.get(
|
||||||
function (data) {
|
`/agnocomplete/AutocompleteUser/?q=${encodeURIComponent(val)}`
|
||||||
this.handleResults(data.data)
|
|
||||||
},
|
|
||||||
this
|
|
||||||
)
|
)
|
||||||
|
this.handleResults(data)
|
||||||
},
|
},
|
||||||
|
|
||||||
createResult: function (item) {
|
createResult: function (item) {
|
||||||
|
@ -272,14 +270,6 @@ L.U.AutoComplete.Ajax = L.U.AutoComplete.extend({
|
||||||
label: option.innerHTML,
|
label: option.innerHTML,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_do_search: function (val, callback, context) {
|
|
||||||
val = val.toLowerCase()
|
|
||||||
this.xhr.get(`/agnocomplete/AutocompleteUser/?q=${encodeURIComponent(val)}`, {
|
|
||||||
callback: callback,
|
|
||||||
context: context || this,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
L.U.AutoComplete.Ajax.SelectMultiple = L.U.AutoComplete.Ajax.extend({
|
L.U.AutoComplete.Ajax.SelectMultiple = L.U.AutoComplete.Ajax.extend({
|
||||||
|
|
|
@ -51,19 +51,14 @@ L.U.DataLayerPermissions = L.Class.extend({
|
||||||
pk: this.datalayer.umap_id,
|
pk: this.datalayer.umap_id,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
save: function () {
|
save: async function () {
|
||||||
if (!this.isDirty) return this.datalayer.map.continueSaving()
|
if (!this.isDirty) return this.datalayer.map.continueSaving()
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
formData.append('edit_status', this.options.edit_status)
|
formData.append('edit_status', this.options.edit_status)
|
||||||
this.datalayer.map.post(this.getUrl(), {
|
await this.datalayer.map.server.post(this.getUrl(), {}, formData)
|
||||||
data: formData,
|
this.commit()
|
||||||
context: this,
|
this.isDirty = false
|
||||||
callback: function (data) {
|
this.datalayer.map.continueSaving()
|
||||||
this.commit()
|
|
||||||
this.isDirty = false
|
|
||||||
this.datalayer.map.continueSaving()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
commit: function () {
|
commit: function () {
|
||||||
|
|
|
@ -685,7 +685,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
||||||
return !this.value() || this.value() === this.obj.getMap().options.default_iconUrl
|
return !this.value() || this.value() === this.obj.getMap().options.default_iconUrl
|
||||||
},
|
},
|
||||||
|
|
||||||
showSymbolsTab: function () {
|
showSymbolsTab: async function () {
|
||||||
this.openTab('symbols')
|
this.openTab('symbols')
|
||||||
this.searchInput = L.DomUtil.create('input', '', this.body)
|
this.searchInput = L.DomUtil.create('input', '', this.body)
|
||||||
this.searchInput.type = 'search'
|
this.searchInput.type = 'search'
|
||||||
|
@ -695,13 +695,11 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
||||||
if (this.pictogram_list) {
|
if (this.pictogram_list) {
|
||||||
this.buildSymbolsList()
|
this.buildSymbolsList()
|
||||||
} else {
|
} else {
|
||||||
this.builder.map.get(this.builder.map.options.urls.pictogram_list_json, {
|
const [{ pictogram_list }, response] = await this.builder.map.server.get(
|
||||||
callback: (data) => {
|
this.builder.map.options.urls.pictogram_list_json
|
||||||
this.pictogram_list = data.pictogram_list
|
)
|
||||||
this.buildSymbolsList()
|
this.pictogram_list = pictogram_list
|
||||||
},
|
this.buildSymbolsList()
|
||||||
context: this,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -98,9 +98,12 @@ L.U.Map.include({
|
||||||
this.urls = new window.umap.URLs(this.options.urls)
|
this.urls = new window.umap.URLs(this.options.urls)
|
||||||
|
|
||||||
this.ui = new L.U.UI(this._container)
|
this.ui = new L.U.UI(this._container)
|
||||||
this.xhr = new L.U.Xhr(this.ui)
|
this.server = new window.umap.ServerRequest(this.ui)
|
||||||
this.xhr.on('dataloading', (e) => this.fire('dataloading', e))
|
this.server.on('dataloading', (e) => this.fire('dataloading', e))
|
||||||
this.xhr.on('dataload', (e) => this.fire('dataload', e))
|
this.server.on('dataload', (e) => this.fire('dataload', e))
|
||||||
|
this.request = new window.umap.Request(this.ui)
|
||||||
|
this.request.on('dataloading', (e) => this.fire('dataloading', e))
|
||||||
|
this.request.on('dataload', (e) => this.fire('dataload', e))
|
||||||
|
|
||||||
this.initLoader()
|
this.initLoader()
|
||||||
this.name = this.options.name
|
this.name = this.options.name
|
||||||
|
@ -1083,7 +1086,7 @@ L.U.Map.include({
|
||||||
return properties
|
return properties
|
||||||
},
|
},
|
||||||
|
|
||||||
saveSelf: function () {
|
saveSelf: async function () {
|
||||||
const geojson = {
|
const geojson = {
|
||||||
type: 'Feature',
|
type: 'Feature',
|
||||||
geometry: this.geometry(),
|
geometry: this.geometry(),
|
||||||
|
@ -1093,64 +1096,60 @@ L.U.Map.include({
|
||||||
formData.append('name', this.options.name)
|
formData.append('name', this.options.name)
|
||||||
formData.append('center', JSON.stringify(this.geometry()))
|
formData.append('center', JSON.stringify(this.geometry()))
|
||||||
formData.append('settings', JSON.stringify(geojson))
|
formData.append('settings', JSON.stringify(geojson))
|
||||||
this.post(this.urls.get('map_save', { map_id: this.options.umap_id }), {
|
const uri = this.urls.get('map_save', { map_id: this.options.umap_id })
|
||||||
data: formData,
|
const [data, response] = await this.server.post(uri, {}, formData)
|
||||||
context: this,
|
let duration = 3000,
|
||||||
callback: function (data) {
|
alert = { content: L._('Map has been saved!'), level: 'info' }
|
||||||
let duration = 3000,
|
if (!this.options.umap_id) {
|
||||||
alert = { content: L._('Map has been saved!'), level: 'info' }
|
alert.content = L._('Congratulations, your map has been created!')
|
||||||
if (!this.options.umap_id) {
|
this.options.umap_id = data.id
|
||||||
alert.content = L._('Congratulations, your map has been created!')
|
this.permissions.setOptions(data.permissions)
|
||||||
this.options.umap_id = data.id
|
this.permissions.commit()
|
||||||
this.permissions.setOptions(data.permissions)
|
if (
|
||||||
this.permissions.commit()
|
data.permissions &&
|
||||||
if (
|
data.permissions.anonymous_edit_url &&
|
||||||
data.permissions &&
|
this.options.urls.map_send_edit_link
|
||||||
data.permissions.anonymous_edit_url &&
|
) {
|
||||||
this.options.urls.map_send_edit_link
|
alert.duration = Infinity
|
||||||
) {
|
alert.content =
|
||||||
alert.duration = Infinity
|
L._(
|
||||||
alert.content =
|
'Your map has been created! As you are not logged in, here is your secret link to edit the map, please keep it safe:'
|
||||||
L._(
|
) + `<br>${data.permissions.anonymous_edit_url}`
|
||||||
'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}`
|
|
||||||
|
|
||||||
alert.actions = [
|
alert.actions = [
|
||||||
{
|
{
|
||||||
label: L._('Send me the link'),
|
label: L._('Send me the link'),
|
||||||
input: L._('Email'),
|
input: L._('Email'),
|
||||||
callback: this.sendEditLink,
|
callback: this.sendEditLink,
|
||||||
callbackContext: this,
|
callbackContext: this,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: L._('Copy link'),
|
label: L._('Copy link'),
|
||||||
callback: () => {
|
callback: () => {
|
||||||
L.Util.copyToClipboard(data.permissions.anonymous_edit_url)
|
L.Util.copyToClipboard(data.permissions.anonymous_edit_url)
|
||||||
this.ui.alert({
|
this.ui.alert({
|
||||||
content: L._('Secret edit link copied to clipboard!'),
|
content: L._('Secret edit link copied to clipboard!'),
|
||||||
level: 'info',
|
level: 'info',
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
callbackContext: this,
|
callbackContext: this,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
} else if (!this.permissions.isDirty) {
|
} else if (!this.permissions.isDirty) {
|
||||||
// Do not override local changes to permissions,
|
// Do not override local changes to permissions,
|
||||||
// but update in case some other editors changed them in the meantime.
|
// but update in case some other editors changed them in the meantime.
|
||||||
this.permissions.setOptions(data.permissions)
|
this.permissions.setOptions(data.permissions)
|
||||||
this.permissions.commit()
|
this.permissions.commit()
|
||||||
}
|
}
|
||||||
// Update URL in case the name has changed.
|
// Update URL in case the name has changed.
|
||||||
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
|
alert.content = data.info || alert.content
|
||||||
this.once('saved', () => this.ui.alert(alert))
|
this.once('saved', () => this.ui.alert(alert))
|
||||||
this.ui.closePanel()
|
this.ui.closePanel()
|
||||||
this.permissions.save()
|
this.permissions.save()
|
||||||
},
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
save: function () {
|
save: function () {
|
||||||
|
@ -1820,23 +1819,6 @@ L.U.Map.include({
|
||||||
this.loader.onAdd(this)
|
this.loader.onAdd(this)
|
||||||
},
|
},
|
||||||
|
|
||||||
post: function (url, options) {
|
|
||||||
options = options || {}
|
|
||||||
options.listener = this
|
|
||||||
this.xhr.post(url, options)
|
|
||||||
},
|
|
||||||
|
|
||||||
get: function (url, options) {
|
|
||||||
options = options || {}
|
|
||||||
options.listener = this
|
|
||||||
this.xhr.get(url, options)
|
|
||||||
},
|
|
||||||
|
|
||||||
ajax: function (options) {
|
|
||||||
options.listener = this
|
|
||||||
this.xhr._ajax(options)
|
|
||||||
},
|
|
||||||
|
|
||||||
initContextMenu: function () {
|
initContextMenu: function () {
|
||||||
this.contextmenu = new L.U.ContextMenu(this)
|
this.contextmenu = new L.U.ContextMenu(this)
|
||||||
this.contextmenu.enable()
|
this.contextmenu.enable()
|
||||||
|
|
|
@ -670,30 +670,26 @@ L.U.DataLayer = L.Evented.extend({
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchData: function () {
|
fetchData: async function () {
|
||||||
if (!this.umap_id) return
|
if (!this.umap_id) return
|
||||||
if (this._loading) return
|
if (this._loading) return
|
||||||
this._loading = true
|
this._loading = true
|
||||||
this.map.get(this._dataUrl(), {
|
const [geojson, response] = await this.map.server.get(this._dataUrl())
|
||||||
callback: function (geojson, response) {
|
this._last_modified = response.headers['Last-Modified']
|
||||||
this._last_modified = response.getResponseHeader('Last-Modified')
|
// FIXME: for now this property is set dynamically from backend
|
||||||
// FIXME: for now this property is set dynamically from backend
|
// And thus it's not in the geojson file in the server
|
||||||
// And thus it's not in the geojson file in the server
|
// So do not let all options to be reset
|
||||||
// So do not let all options to be reset
|
// Fix is a proper migration so all datalayers settings are
|
||||||
// Fix is a proper migration so all datalayers settings are
|
// in DB, and we remove it from geojson flat files.
|
||||||
// in DB, and we remove it from geojson flat files.
|
if (geojson._umap_options) {
|
||||||
if (geojson._umap_options) {
|
geojson._umap_options.editMode = this.options.editMode
|
||||||
geojson._umap_options.editMode = this.options.editMode
|
}
|
||||||
}
|
// In case of maps pre 1.0 still around
|
||||||
// In case of maps pre 1.0 still around
|
if (geojson._storage) geojson._storage.editMode = this.options.editMode
|
||||||
if (geojson._storage) geojson._storage.editMode = this.options.editMode
|
this.fromUmapGeoJSON(geojson)
|
||||||
this.fromUmapGeoJSON(geojson)
|
this.backupOptions()
|
||||||
this.backupOptions()
|
this.fire('loaded')
|
||||||
this.fire('loaded')
|
this._loading = false
|
||||||
this._loading = false
|
|
||||||
},
|
|
||||||
context: this,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
fromGeoJSON: function (geojson) {
|
fromGeoJSON: function (geojson) {
|
||||||
|
@ -1062,13 +1058,10 @@ L.U.DataLayer = L.Evented.extend({
|
||||||
reader.onload = (e) => this.importRaw(e.target.result, type)
|
reader.onload = (e) => this.importRaw(e.target.result, type)
|
||||||
},
|
},
|
||||||
|
|
||||||
importFromUrl: function (url, type) {
|
importFromUrl: async function (uri, type) {
|
||||||
url = this.map.localizeUrl(url)
|
uri = this.map.localizeUrl(uri)
|
||||||
this.map.xhr._ajax({
|
const response = await this.map.request.get(uri)
|
||||||
verb: 'GET',
|
this.importRaw(await response.text(), type)
|
||||||
uri: url,
|
|
||||||
callback: (data) => this.importRaw(data, type),
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getColor: function () {
|
getColor: function () {
|
||||||
|
@ -1385,8 +1378,8 @@ L.U.DataLayer = L.Evented.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
buildVersionsFieldset: function (container) {
|
buildVersionsFieldset: async function (container) {
|
||||||
const appendVersion = function (data) {
|
const appendVersion = (data) => {
|
||||||
const date = new Date(parseInt(data.at, 10))
|
const date = new Date(parseInt(data.at, 10))
|
||||||
const content = `${date.toLocaleString(L.lang)} (${parseInt(data.size) / 1000}Kb)`
|
const content = `${date.toLocaleString(L.lang)} (${parseInt(data.size) / 1000}Kb)`
|
||||||
const el = L.DomUtil.create('div', 'umap-datalayer-version', versionsContainer)
|
const el = L.DomUtil.create('div', 'umap-datalayer-version', versionsContainer)
|
||||||
|
@ -1402,34 +1395,24 @@ L.U.DataLayer = L.Evented.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
const versionsContainer = L.DomUtil.createFieldset(container, L._('Versions'), {
|
const versionsContainer = L.DomUtil.createFieldset(container, L._('Versions'), {
|
||||||
callback: function () {
|
callback: async function () {
|
||||||
this.map.xhr.get(this.getVersionsUrl(), {
|
const [{versions}, response] = await this.map.server.get(this.getVersionsUrl())
|
||||||
callback: function (data) {
|
versions.forEach(appendVersion)
|
||||||
for (let i = 0; i < data.versions.length; i++) {
|
|
||||||
appendVersion.call(this, data.versions[i])
|
|
||||||
}
|
|
||||||
},
|
|
||||||
context: this,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
context: this,
|
context: this,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
restore: function (version) {
|
restore: async function (version) {
|
||||||
if (!this.map.editEnabled) return
|
if (!this.map.editEnabled) return
|
||||||
if (!confirm(L._('Are you sure you want to restore this version?'))) return
|
if (!confirm(L._('Are you sure you want to restore this version?'))) return
|
||||||
this.map.xhr.get(this.getVersionUrl(version), {
|
const [geojson, response] = await this.map.server.get(this.getVersionUrl(version))
|
||||||
callback: function (geojson) {
|
if (geojson._storage) geojson._umap_options = geojson._storage // Retrocompat.
|
||||||
if (geojson._storage) geojson._umap_options = geojson._storage // Retrocompat.
|
if (geojson._umap_options) this.setOptions(geojson._umap_options)
|
||||||
if (geojson._umap_options) this.setOptions(geojson._umap_options)
|
this.empty()
|
||||||
this.empty()
|
if (this.isRemoteLayer()) this.fetchRemoteData()
|
||||||
if (this.isRemoteLayer()) this.fetchRemoteData()
|
else this.addData(geojson)
|
||||||
else this.addData(geojson)
|
this.isDirty = true
|
||||||
this.isDirty = true
|
|
||||||
},
|
|
||||||
context: this,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
featuresToGeoJSON: function () {
|
featuresToGeoJSON: function () {
|
||||||
|
@ -1548,7 +1531,7 @@ L.U.DataLayer = L.Evented.extend({
|
||||||
return this.isReadOnly() || this.isRemoteLayer()
|
return this.isReadOnly() || this.isRemoteLayer()
|
||||||
},
|
},
|
||||||
|
|
||||||
save: function () {
|
save: async function () {
|
||||||
if (this.isDeleted) return this.saveDelete()
|
if (this.isDeleted) return this.saveDelete()
|
||||||
if (!this.isLoaded()) {
|
if (!this.isLoaded()) {
|
||||||
return
|
return
|
||||||
|
@ -1566,44 +1549,35 @@ L.U.DataLayer = L.Evented.extend({
|
||||||
map_id: this.map.options.umap_id,
|
map_id: this.map.options.umap_id,
|
||||||
pk: this.umap_id,
|
pk: this.umap_id,
|
||||||
})
|
})
|
||||||
this.map.post(saveUrl, {
|
const headers = this._last_modified
|
||||||
data: formData,
|
? { 'If-Unmodified-Since': this._last_modified }
|
||||||
callback: function (data, response) {
|
: {}
|
||||||
// Response contains geojson only if save has conflicted and conflicts have
|
const [data, response] = await this.map.server.post(saveUrl, headers, formData)
|
||||||
// been resolved. So we need to reload to get extra data (saved from someone else)
|
// Response contains geojson only if save has conflicted and conflicts have
|
||||||
if (data.geojson) {
|
// been resolved. So we need to reload to get extra data (saved from someone else)
|
||||||
this.clear()
|
if (data.geojson) {
|
||||||
this.fromGeoJSON(data.geojson)
|
this.clear()
|
||||||
delete data.geojson
|
this.fromGeoJSON(data.geojson)
|
||||||
}
|
delete data.geojson
|
||||||
this._geojson = geojson
|
}
|
||||||
this._last_modified = response.getResponseHeader('Last-Modified')
|
this._geojson = geojson
|
||||||
this.setUmapId(data.id)
|
this._last_modified = response.headers['Last-Modified']
|
||||||
this.updateOptions(data)
|
this.setUmapId(data.id)
|
||||||
this.backupOptions()
|
this.updateOptions(data)
|
||||||
this.connectToMap()
|
this.backupOptions()
|
||||||
this._loaded = true
|
this.connectToMap()
|
||||||
this.redraw() // Needed for reordering features
|
this._loaded = true
|
||||||
this.isDirty = false
|
this.redraw() // Needed for reordering features
|
||||||
this.permissions.save()
|
this.isDirty = false
|
||||||
},
|
this.permissions.save()
|
||||||
context: this,
|
|
||||||
headers: this._last_modified
|
|
||||||
? { 'If-Unmodified-Since': this._last_modified }
|
|
||||||
: {},
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
saveDelete: function () {
|
saveDelete: async function () {
|
||||||
const callback = function () {
|
if (this.umap_id) {
|
||||||
this.isDirty = false
|
await this.map.server.post(this.getDeleteUrl())
|
||||||
this.map.continueSaving()
|
|
||||||
}
|
}
|
||||||
if (!this.umap_id) return callback.call(this)
|
this.isDirty = false
|
||||||
this.map.xhr.post(this.getDeleteUrl(), {
|
this.map.continueSaving()
|
||||||
callback: callback,
|
|
||||||
context: this,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getMap: function () {
|
getMap: function () {
|
||||||
|
|
|
@ -131,21 +131,17 @@ L.U.MapPermissions = L.Class.extend({
|
||||||
this.map.ui.openPanel({ data: { html: container }, className: 'dark' })
|
this.map.ui.openPanel({ data: { html: container }, className: 'dark' })
|
||||||
},
|
},
|
||||||
|
|
||||||
attach: function () {
|
attach: async function () {
|
||||||
this.map.post(this.getAttachUrl(), {
|
await this.map.server.post(this.getAttachUrl())
|
||||||
callback: function () {
|
this.options.owner = this.map.options.user
|
||||||
this.options.owner = this.map.options.user
|
this.map.ui.alert({
|
||||||
this.map.ui.alert({
|
content: L._('Map has been attached to your account'),
|
||||||
content: L._('Map has been attached to your account'),
|
level: 'info',
|
||||||
level: 'info',
|
|
||||||
})
|
|
||||||
this.map.ui.closePanel()
|
|
||||||
},
|
|
||||||
context: this,
|
|
||||||
})
|
})
|
||||||
|
this.map.ui.closePanel()
|
||||||
},
|
},
|
||||||
|
|
||||||
save: function () {
|
save: async function () {
|
||||||
if (!this.isDirty) return this.map.continueSaving()
|
if (!this.isDirty) return this.map.continueSaving()
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
if (!this.isAnonymousMap() && this.options.editors) {
|
if (!this.isAnonymousMap() && this.options.editors) {
|
||||||
|
@ -159,16 +155,11 @@ L.U.MapPermissions = L.Class.extend({
|
||||||
formData.append('owner', this.options.owner && this.options.owner.id)
|
formData.append('owner', this.options.owner && this.options.owner.id)
|
||||||
formData.append('share_status', this.options.share_status)
|
formData.append('share_status', this.options.share_status)
|
||||||
}
|
}
|
||||||
this.map.post(this.getUrl(), {
|
await this.map.server.post(this.getUrl(), {}, formData)
|
||||||
data: formData,
|
this.commit()
|
||||||
context: this,
|
this.isDirty = false
|
||||||
callback: function (data) {
|
this.map.continueSaving()
|
||||||
this.commit()
|
this.map.fire('postsync')
|
||||||
this.isDirty = false
|
|
||||||
this.map.continueSaving()
|
|
||||||
this.map.fire('postsync')
|
|
||||||
},
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getUrl: function () {
|
getUrl: function () {
|
||||||
|
|
Loading…
Reference in a new issue