Merge pull request #1555 from umap-project/request-module
chore: move xhr management to a module and refactor
This commit is contained in:
commit
6fb7b02b40
40 changed files with 1120 additions and 1411 deletions
|
@ -9,6 +9,7 @@
|
|||
"chai": "^3.3.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-plugin-compat": "^4.2.0",
|
||||
"fetch-mock": "^9.11.0",
|
||||
"happen": "~0.1.3",
|
||||
"lebab": "^3.2.1",
|
||||
"mocha": "^10.2.0",
|
||||
|
|
|
@ -60,17 +60,3 @@ def can_view_map(view_func):
|
|||
return view_func(request, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def jsonize_view(view_func):
|
||||
@wraps(view_func)
|
||||
def wrapper(request, *args, **kwargs):
|
||||
response = view_func(request, *args, **kwargs)
|
||||
response_kwargs = {}
|
||||
if hasattr(response, "rendered_content"):
|
||||
response_kwargs["html"] = response.rendered_content
|
||||
if response.has_header("location"):
|
||||
response_kwargs["redirect"] = response["location"]
|
||||
return simple_json_response(**response_kwargs)
|
||||
|
||||
return wrapper
|
||||
|
|
|
@ -242,6 +242,13 @@ class Map(NamedModel):
|
|||
has_anonymous_cookie = False
|
||||
return has_anonymous_cookie
|
||||
|
||||
def can_delete(self, user=None, request=None):
|
||||
if self.owner and user != self.owner:
|
||||
return False
|
||||
if not self.owner and not self.is_anonymous_owner(request):
|
||||
return False
|
||||
return True
|
||||
|
||||
def can_edit(self, user=None, request=None):
|
||||
"""
|
||||
Define if a user can edit or not the instance, according to his account
|
||||
|
|
|
@ -37,6 +37,21 @@ input:-moz-placeholder, :-moz-placeholder {
|
|||
/* **************** */
|
||||
/* Login icons */
|
||||
/* **************** */
|
||||
body.login {
|
||||
width: 320px;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
}
|
||||
body.login header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.login-grid {
|
||||
display: grid;
|
||||
justify-content: space-between;
|
||||
grid-gap: 5px;
|
||||
grid-template-columns: repeat(auto-fill,92px);
|
||||
}
|
||||
.login-grid li,
|
||||
.login-grid a {
|
||||
display: inline-block;
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import * as L from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||
import URLs from './urls.js'
|
||||
import { Request, ServerRequest, RequestError, HTTPError, NOKError } from './request.js'
|
||||
// Import modules and export them to the global scope.
|
||||
// For the not yet module-compatible JS out there.
|
||||
|
||||
// Copy the leaflet module, it's expected by leaflet plugins to be writeable.
|
||||
window.L = { ...L }
|
||||
window.umap = { URLs }
|
||||
window.umap = { URLs, Request, ServerRequest, RequestError, HTTPError, NOKError }
|
||||
|
|
155
umap/static/umap/js/modules/request.js
Normal file
155
umap/static/umap/js/modules/request.js
Normal file
|
@ -0,0 +1,155 @@
|
|||
// Uses `L._`` from Leaflet.i18n which we cannot import as a module yet
|
||||
import { Evented, DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||
|
||||
export class RequestError extends Error {}
|
||||
|
||||
export class HTTPError extends RequestError {
|
||||
constructor(message) {
|
||||
super(message)
|
||||
this.name = this.constructor.name
|
||||
}
|
||||
}
|
||||
|
||||
export class NOKError extends RequestError {
|
||||
constructor(response) {
|
||||
super(response.status)
|
||||
this.response = response
|
||||
this.status = response.status
|
||||
this.name = this.constructor.name
|
||||
}
|
||||
}
|
||||
|
||||
class BaseRequest {
|
||||
async _fetch(method, uri, headers, data) {
|
||||
let response
|
||||
|
||||
try {
|
||||
response = await fetch(uri, {
|
||||
method: method,
|
||||
mode: 'cors',
|
||||
headers: headers,
|
||||
body: data,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
throw new HTTPError(error.message)
|
||||
}
|
||||
if (!response.ok) {
|
||||
throw new NOKError(response)
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
}
|
||||
|
||||
// Basic class to issue request
|
||||
// It returns a response, or null in case of error
|
||||
// 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(ui) {
|
||||
super()
|
||||
this.ui = ui
|
||||
}
|
||||
|
||||
async _fetch(method, uri, headers, data) {
|
||||
const id = Math.random()
|
||||
this.ui.fire('dataloading', { id: id })
|
||||
try {
|
||||
const response = await BaseRequest.prototype._fetch.call(
|
||||
this,
|
||||
method,
|
||||
uri,
|
||||
headers,
|
||||
data
|
||||
)
|
||||
return response
|
||||
} catch (error) {
|
||||
if (error instanceof NOKError) return this._onNOK(error)
|
||||
return this._onError(error)
|
||||
} finally {
|
||||
this.ui.fire('dataload', { id: id })
|
||||
}
|
||||
}
|
||||
|
||||
async get(uri, headers) {
|
||||
return await this._fetch('GET', uri, headers)
|
||||
}
|
||||
|
||||
async post(uri, headers, data) {
|
||||
return await this._fetch('POST', uri, headers, data)
|
||||
}
|
||||
|
||||
_onError(error) {
|
||||
this.ui.alert({ content: L._('Problem in the response'), level: 'error' })
|
||||
}
|
||||
|
||||
_onNOK(error) {
|
||||
this._onError(error)
|
||||
return error.response
|
||||
}
|
||||
}
|
||||
|
||||
// Adds uMap specifics to requests handling
|
||||
// like logging, CSRF, etc.
|
||||
// It expects only json responses.
|
||||
// Returns an array of three elements: [data, response, error]
|
||||
// The consumer must check the error to proceed or not with using the data or response
|
||||
export class ServerRequest extends Request {
|
||||
async _fetch(method, uri, headers, data) {
|
||||
// Add a flag so backend can know we are in ajax and adapt the response
|
||||
// See is_ajax in utils.py
|
||||
headers = headers || {}
|
||||
headers['X-Requested-With'] = 'XMLHttpRequest'
|
||||
return await Request.prototype._fetch.call(this, method, uri, headers, data)
|
||||
}
|
||||
|
||||
async post(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 await this._as_json(response)
|
||||
}
|
||||
|
||||
async get(uri, headers) {
|
||||
const response = await Request.prototype.get.call(this, uri, headers)
|
||||
return await this._as_json(response)
|
||||
}
|
||||
|
||||
async _as_json(response) {
|
||||
if (Array.isArray(response)) return response
|
||||
try {
|
||||
const data = await response.json()
|
||||
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' })
|
||||
return this._onError(new Error(data.error))
|
||||
}
|
||||
return [data, response, null]
|
||||
} catch (error) {
|
||||
return this._onError(error)
|
||||
}
|
||||
}
|
||||
|
||||
_onError(error) {
|
||||
return [{}, null, error]
|
||||
}
|
||||
|
||||
_onNOK(error) {
|
||||
if (error.status === 403) {
|
||||
this.ui.alert({
|
||||
content: message || L._('Action not allowed :('),
|
||||
level: 'error',
|
||||
})
|
||||
}
|
||||
return [{}, error.response, error]
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ L.U.AutoComplete = L.Class.extend({
|
|||
initialize: function (el, options) {
|
||||
this.el = el
|
||||
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)
|
||||
let CURRENT = null
|
||||
try {
|
||||
|
@ -158,21 +158,19 @@ L.U.AutoComplete = L.Class.extend({
|
|||
}
|
||||
},
|
||||
|
||||
search: function () {
|
||||
const val = this.input.value
|
||||
search: async function () {
|
||||
let val = this.input.value
|
||||
if (val.length < this.options.minChar) {
|
||||
this.clear()
|
||||
return
|
||||
}
|
||||
if (`${val}` === `${this.CACHE}`) return
|
||||
else this.CACHE = val
|
||||
this._do_search(
|
||||
val,
|
||||
function (data) {
|
||||
this.handleResults(data.data)
|
||||
},
|
||||
this
|
||||
val = val.toLowerCase()
|
||||
const [{ data }, response] = await this.server.get(
|
||||
`/agnocomplete/AutocompleteUser/?q=${encodeURIComponent(val)}`
|
||||
)
|
||||
this.handleResults(data)
|
||||
},
|
||||
|
||||
createResult: function (item) {
|
||||
|
@ -272,14 +270,6 @@ L.U.AutoComplete.Ajax = L.U.AutoComplete.extend({
|
|||
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({
|
||||
|
|
|
@ -51,19 +51,20 @@ L.U.DataLayerPermissions = L.Class.extend({
|
|||
pk: this.datalayer.umap_id,
|
||||
})
|
||||
},
|
||||
save: function () {
|
||||
save: async function () {
|
||||
if (!this.isDirty) return this.datalayer.map.continueSaving()
|
||||
const formData = new FormData()
|
||||
formData.append('edit_status', this.options.edit_status)
|
||||
this.datalayer.map.post(this.getUrl(), {
|
||||
data: formData,
|
||||
context: this,
|
||||
callback: function (data) {
|
||||
this.commit()
|
||||
this.isDirty = false
|
||||
this.datalayer.map.continueSaving()
|
||||
},
|
||||
})
|
||||
const [data, response, error] = await this.datalayer.map.server.post(
|
||||
this.getUrl(),
|
||||
{},
|
||||
formData
|
||||
)
|
||||
if (!error) {
|
||||
this.commit()
|
||||
this.isDirty = false
|
||||
this.datalayer.map.continueSaving()
|
||||
}
|
||||
},
|
||||
|
||||
commit: function () {
|
||||
|
|
|
@ -685,7 +685,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
|||
return !this.value() || this.value() === this.obj.getMap().options.default_iconUrl
|
||||
},
|
||||
|
||||
showSymbolsTab: function () {
|
||||
showSymbolsTab: async function () {
|
||||
this.openTab('symbols')
|
||||
this.searchInput = L.DomUtil.create('input', '', this.body)
|
||||
this.searchInput.type = 'search'
|
||||
|
@ -695,13 +695,13 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
|||
if (this.pictogram_list) {
|
||||
this.buildSymbolsList()
|
||||
} else {
|
||||
this.builder.map.get(this.builder.map.options.urls.pictogram_list_json, {
|
||||
callback: (data) => {
|
||||
this.pictogram_list = data.pictogram_list
|
||||
this.buildSymbolsList()
|
||||
},
|
||||
context: this,
|
||||
})
|
||||
const [{ pictogram_list }, response, error] = await this.builder.map.server.get(
|
||||
this.builder.map.options.urls.pictogram_list_json
|
||||
)
|
||||
if (!error) {
|
||||
this.pictogram_list = pictogram_list
|
||||
this.buildSymbolsList()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -34,7 +34,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,
|
||||
|
@ -98,9 +98,10 @@ L.U.Map.include({
|
|||
this.urls = new window.umap.URLs(this.options.urls)
|
||||
|
||||
this.ui = new L.U.UI(this._container)
|
||||
this.xhr = new L.U.Xhr(this.ui)
|
||||
this.xhr.on('dataloading', (e) => this.fire('dataloading', e))
|
||||
this.xhr.on('dataload', (e) => this.fire('dataload', e))
|
||||
this.ui.on('dataloading', (e) => this.fire('dataloading', e))
|
||||
this.ui.on('dataload', (e) => this.fire('dataload', e))
|
||||
this.server = new window.umap.ServerRequest(this.ui)
|
||||
this.request = new window.umap.Request(this.ui)
|
||||
|
||||
this.initLoader()
|
||||
this.name = this.options.name
|
||||
|
@ -183,7 +184,7 @@ L.U.Map.include({
|
|||
// Needs locate control and hash to exist
|
||||
this.initCenter()
|
||||
this.handleLimitBounds()
|
||||
this.initDatalayers()
|
||||
this.initDataLayers()
|
||||
|
||||
if (this.options.displayCaptionOnLoad) {
|
||||
// Retrocompat
|
||||
|
@ -236,8 +237,6 @@ L.U.Map.include({
|
|||
this._default_extent = true
|
||||
this.options.name = L._('Untitled map')
|
||||
this.options.editMode = 'advanced'
|
||||
const datalayer = this.createDataLayer()
|
||||
datalayer.connectToMap()
|
||||
this.enableEdit()
|
||||
let dataUrl = L.Util.queryString('dataUrl', null)
|
||||
const dataFormat = L.Util.queryString('dataFormat', 'geojson')
|
||||
|
@ -273,8 +272,6 @@ L.U.Map.include({
|
|||
this.options.onLoadPanel === 'datafilters'
|
||||
)
|
||||
this.openFacet()
|
||||
})
|
||||
this.onceDataLoaded(function () {
|
||||
const slug = L.Util.queryString('feature')
|
||||
if (slug && this.features_index[slug]) this.features_index[slug].view()
|
||||
if (L.Util.queryString('edit')) {
|
||||
|
@ -419,56 +416,22 @@ L.U.Map.include({
|
|||
if (this.options.scaleControl) this._controls.scale.addTo(this)
|
||||
},
|
||||
|
||||
initDatalayers: function () {
|
||||
for (let j = 0; j < this.options.datalayers.length; j++) {
|
||||
this.createDataLayer(this.options.datalayers[j])
|
||||
initDataLayers: async function (datalayers) {
|
||||
datalayers = datalayers || this.options.datalayers
|
||||
for (const options of datalayers) {
|
||||
this.createDataLayer(options)
|
||||
}
|
||||
this.loadDatalayers()
|
||||
await this.loadDataLayers()
|
||||
},
|
||||
|
||||
loadDatalayers: function (force) {
|
||||
const total = this.datalayers_index.length
|
||||
// toload => datalayer metadata remaining to load (synchronous)
|
||||
// dataToload => datalayer data remaining to load (asynchronous)
|
||||
let toload = total,
|
||||
dataToload = total
|
||||
let datalayer
|
||||
const loaded = () => {
|
||||
this.datalayersLoaded = true
|
||||
this.fire('datalayersloaded')
|
||||
}
|
||||
const decrementToLoad = () => {
|
||||
toload--
|
||||
if (toload === 0) loaded()
|
||||
}
|
||||
const dataLoaded = () => {
|
||||
this.dataLoaded = true
|
||||
this.fire('dataloaded')
|
||||
}
|
||||
const decrementDataToLoad = () => {
|
||||
dataToload--
|
||||
if (dataToload === 0) dataLoaded()
|
||||
}
|
||||
this.eachDataLayer(function (datalayer) {
|
||||
if (force && !datalayer.hasDataLoaded()) {
|
||||
datalayer.show()
|
||||
}
|
||||
if (datalayer.showAtLoad() || force) {
|
||||
datalayer.onceLoaded(decrementToLoad)
|
||||
} else {
|
||||
decrementToLoad()
|
||||
}
|
||||
if (datalayer.showAtLoad() || force) {
|
||||
datalayer.onceDataLoaded(decrementDataToLoad)
|
||||
} else {
|
||||
decrementDataToLoad({ sourceTarget: datalayer })
|
||||
}
|
||||
})
|
||||
if (total === 0) {
|
||||
// no datalayer
|
||||
loaded()
|
||||
dataLoaded()
|
||||
loadDataLayers: async function () {
|
||||
this.datalayersLoaded = true
|
||||
this.fire('datalayersloaded')
|
||||
for (const datalayer of Object.values(this.datalayers)) {
|
||||
if (datalayer.showAtLoad()) await datalayer.show()
|
||||
}
|
||||
this.dataloaded = true
|
||||
this.fire('dataloaded')
|
||||
},
|
||||
|
||||
indexDatalayers: function () {
|
||||
|
@ -501,7 +464,7 @@ L.U.Map.include({
|
|||
|
||||
onceDataLoaded: function (callback, context) {
|
||||
// Once datalayers **data** have been loaded
|
||||
if (this.dataLoaded) {
|
||||
if (this.dataloaded) {
|
||||
callback.call(context || this, this)
|
||||
} else {
|
||||
this.once('dataloaded', callback, context)
|
||||
|
@ -835,7 +798,10 @@ L.U.Map.include({
|
|||
self.isDirty = true
|
||||
}
|
||||
if (this._controls.tilelayersChooser)
|
||||
this._controls.tilelayersChooser.openSwitcher({ callback: callback, className: 'dark' })
|
||||
this._controls.tilelayersChooser.openSwitcher({
|
||||
callback: callback,
|
||||
className: 'dark',
|
||||
})
|
||||
},
|
||||
|
||||
manageDatalayers: function () {
|
||||
|
@ -1083,7 +1049,7 @@ L.U.Map.include({
|
|||
return properties
|
||||
},
|
||||
|
||||
saveSelf: function () {
|
||||
saveSelf: async function () {
|
||||
const geojson = {
|
||||
type: 'Feature',
|
||||
geometry: this.geometry(),
|
||||
|
@ -1093,64 +1059,62 @@ L.U.Map.include({
|
|||
formData.append('name', this.options.name)
|
||||
formData.append('center', JSON.stringify(this.geometry()))
|
||||
formData.append('settings', JSON.stringify(geojson))
|
||||
this.post(this.urls.get('map_save', { map_id: this.options.umap_id }), {
|
||||
data: formData,
|
||||
context: this,
|
||||
callback: function (data) {
|
||||
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 &&
|
||||
this.options.urls.map_send_edit_link
|
||||
) {
|
||||
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:'
|
||||
) + `<br>${data.permissions.anonymous_edit_url}`
|
||||
const uri = this.urls.get('map_save', { map_id: this.options.umap_id })
|
||||
const [data, response, error] = await this.server.post(uri, {}, formData)
|
||||
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 &&
|
||||
this.options.urls.map_send_edit_link
|
||||
) {
|
||||
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:'
|
||||
) + `<br>${data.permissions.anonymous_edit_url}`
|
||||
|
||||
alert.actions = [
|
||||
{
|
||||
label: L._('Send me the link'),
|
||||
input: L._('Email'),
|
||||
callback: this.sendEditLink,
|
||||
callbackContext: this,
|
||||
alert.actions = [
|
||||
{
|
||||
label: L._('Send me the link'),
|
||||
input: L._('Email'),
|
||||
callback: this.sendEditLink,
|
||||
callbackContext: this,
|
||||
},
|
||||
{
|
||||
label: L._('Copy link'),
|
||||
callback: () => {
|
||||
L.Util.copyToClipboard(data.permissions.anonymous_edit_url)
|
||||
this.ui.alert({
|
||||
content: L._('Secret edit link copied to clipboard!'),
|
||||
level: 'info',
|
||||
})
|
||||
},
|
||||
{
|
||||
label: L._('Copy link'),
|
||||
callback: () => {
|
||||
L.Util.copyToClipboard(data.permissions.anonymous_edit_url)
|
||||
this.ui.alert({
|
||||
content: L._('Secret edit link copied to clipboard!'),
|
||||
level: 'info',
|
||||
})
|
||||
},
|
||||
callbackContext: this,
|
||||
},
|
||||
]
|
||||
}
|
||||
} 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()
|
||||
callbackContext: this,
|
||||
},
|
||||
]
|
||||
}
|
||||
// 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.ui.alert(alert))
|
||||
this.ui.closePanel()
|
||||
this.permissions.save()
|
||||
},
|
||||
})
|
||||
} 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.ui.alert(alert))
|
||||
this.ui.closePanel()
|
||||
this.permissions.save()
|
||||
}
|
||||
},
|
||||
|
||||
save: function () {
|
||||
|
@ -1793,19 +1757,21 @@ L.U.Map.include({
|
|||
return this.editTools.startPolygon()
|
||||
},
|
||||
|
||||
del: function () {
|
||||
del: async function () {
|
||||
if (confirm(L._('Are you sure you want to delete this map?'))) {
|
||||
const url = this.urls.get('map_delete', { map_id: this.options.umap_id })
|
||||
this.post(url)
|
||||
const [data, response, error] = await this.server.post(url)
|
||||
if (data.redirect) window.location = data.redirect
|
||||
}
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
clone: async function () {
|
||||
if (
|
||||
confirm(L._('Are you sure you want to clone this map and all its datalayers?'))
|
||||
) {
|
||||
const url = this.urls.get('map_clone', { map_id: this.options.umap_id })
|
||||
this.post(url)
|
||||
const [data, response, error] = await this.server.post(url)
|
||||
if (data.redirect) window.location = data.redirect
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1820,23 +1786,6 @@ L.U.Map.include({
|
|||
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 () {
|
||||
this.contextmenu = new L.U.ContextMenu(this)
|
||||
this.contextmenu.enable()
|
||||
|
|
|
@ -581,8 +581,10 @@ L.U.DataLayer = L.Evented.extend({
|
|||
this.backupOptions()
|
||||
this.connectToMap()
|
||||
this.permissions = new L.U.DataLayerPermissions(this)
|
||||
if (this.showAtLoad()) this.show()
|
||||
if (!this.umap_id) this.isDirty = true
|
||||
if (!this.umap_id) {
|
||||
if (this.showAtLoad()) this.show()
|
||||
this.isDirty = true
|
||||
}
|
||||
|
||||
this.onceLoaded(function () {
|
||||
this.map.on('moveend', this.onMoveEnd, this)
|
||||
|
@ -670,30 +672,28 @@ L.U.DataLayer = L.Evented.extend({
|
|||
return this
|
||||
},
|
||||
|
||||
fetchData: function () {
|
||||
fetchData: async function () {
|
||||
if (!this.umap_id) return
|
||||
if (this._loading) return
|
||||
this._loading = true
|
||||
this.map.get(this._dataUrl(), {
|
||||
callback: function (geojson, response) {
|
||||
this._last_modified = response.getResponseHeader('Last-Modified')
|
||||
// FIXME: for now this property is set dynamically from backend
|
||||
// And thus it's not in the geojson file in the server
|
||||
// So do not let all options to be reset
|
||||
// Fix is a proper migration so all datalayers settings are
|
||||
// in DB, and we remove it from geojson flat files.
|
||||
if (geojson._umap_options) {
|
||||
geojson._umap_options.editMode = this.options.editMode
|
||||
}
|
||||
// In case of maps pre 1.0 still around
|
||||
if (geojson._storage) geojson._storage.editMode = this.options.editMode
|
||||
this.fromUmapGeoJSON(geojson)
|
||||
this.backupOptions()
|
||||
this.fire('loaded')
|
||||
this._loading = false
|
||||
},
|
||||
context: this,
|
||||
})
|
||||
const [geojson, response, error] = await this.map.server.get(this._dataUrl())
|
||||
if (!error) {
|
||||
this._last_modified = response.headers.get('last-modified')
|
||||
// FIXME: for now this property is set dynamically from backend
|
||||
// And thus it's not in the geojson file in the server
|
||||
// So do not let all options to be reset
|
||||
// Fix is a proper migration so all datalayers settings are
|
||||
// in DB, and we remove it from geojson flat files.
|
||||
if (geojson._umap_options) {
|
||||
geojson._umap_options.editMode = this.options.editMode
|
||||
}
|
||||
// In case of maps pre 1.0 still around
|
||||
if (geojson._storage) geojson._storage.editMode = this.options.editMode
|
||||
this.fromUmapGeoJSON(geojson)
|
||||
this.backupOptions()
|
||||
this.fire('loaded')
|
||||
this._loading = false
|
||||
}
|
||||
},
|
||||
|
||||
fromGeoJSON: function (geojson) {
|
||||
|
@ -744,23 +744,23 @@ L.U.DataLayer = L.Evented.extend({
|
|||
return !((!isNaN(from) && zoom < from) || (!isNaN(to) && zoom > to))
|
||||
},
|
||||
|
||||
fetchRemoteData: function (force) {
|
||||
fetchRemoteData: async function (force) {
|
||||
if (!this.isRemoteLayer()) return
|
||||
if (!this.options.remoteData.dynamic && this.hasDataLoaded() && !force) return
|
||||
if (!this.isVisible()) return
|
||||
let url = this.map.localizeUrl(this.options.remoteData.url)
|
||||
if (this.options.remoteData.proxy)
|
||||
if (this.options.remoteData.proxy) {
|
||||
url = this.map.proxyUrl(url, this.options.remoteData.ttl)
|
||||
this.map.ajax({
|
||||
uri: url,
|
||||
verb: 'GET',
|
||||
callback: (raw) => {
|
||||
this.clear()
|
||||
this.rawToGeoJSON(raw, this.options.remoteData.format, (geojson) =>
|
||||
this.fromGeoJSON(geojson)
|
||||
)
|
||||
},
|
||||
})
|
||||
}
|
||||
const response = await this.map.request.get(url)
|
||||
if (response && response.ok) {
|
||||
this.clear()
|
||||
this.rawToGeoJSON(
|
||||
await response.text(),
|
||||
this.options.remoteData.format,
|
||||
(geojson) => this.fromGeoJSON(geojson)
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
onceLoaded: function (callback, context) {
|
||||
|
@ -926,7 +926,7 @@ L.U.DataLayer = L.Evented.extend({
|
|||
})
|
||||
}
|
||||
this.map.ui.alert({ content: message, level: 'error', duration: 10000 })
|
||||
console.log(err)
|
||||
console.error(err)
|
||||
}
|
||||
if (result && result.features.length) {
|
||||
callback(result)
|
||||
|
@ -1062,13 +1062,12 @@ L.U.DataLayer = L.Evented.extend({
|
|||
reader.onload = (e) => this.importRaw(e.target.result, type)
|
||||
},
|
||||
|
||||
importFromUrl: function (url, type) {
|
||||
url = this.map.localizeUrl(url)
|
||||
this.map.xhr._ajax({
|
||||
verb: 'GET',
|
||||
uri: url,
|
||||
callback: (data) => this.importRaw(data, type),
|
||||
})
|
||||
importFromUrl: async function (uri, type) {
|
||||
uri = this.map.localizeUrl(uri)
|
||||
const response = await this.map.request.get(uri)
|
||||
if (response && response.ok) {
|
||||
this.importRaw(await response.text(), type)
|
||||
}
|
||||
},
|
||||
|
||||
getColor: function () {
|
||||
|
@ -1385,8 +1384,8 @@ L.U.DataLayer = L.Evented.extend({
|
|||
}
|
||||
},
|
||||
|
||||
buildVersionsFieldset: function (container) {
|
||||
const appendVersion = function (data) {
|
||||
buildVersionsFieldset: async function (container) {
|
||||
const appendVersion = (data) => {
|
||||
const date = new Date(parseInt(data.at, 10))
|
||||
const content = `${date.toLocaleString(L.lang)} (${parseInt(data.size) / 1000}Kb)`
|
||||
const el = L.DomUtil.create('div', 'umap-datalayer-version', versionsContainer)
|
||||
|
@ -1402,34 +1401,30 @@ L.U.DataLayer = L.Evented.extend({
|
|||
}
|
||||
|
||||
const versionsContainer = L.DomUtil.createFieldset(container, L._('Versions'), {
|
||||
callback: function () {
|
||||
this.map.xhr.get(this.getVersionsUrl(), {
|
||||
callback: function (data) {
|
||||
for (let i = 0; i < data.versions.length; i++) {
|
||||
appendVersion.call(this, data.versions[i])
|
||||
}
|
||||
},
|
||||
context: this,
|
||||
})
|
||||
callback: async function () {
|
||||
const [{ versions }, response, error] = await this.map.server.get(
|
||||
this.getVersionsUrl()
|
||||
)
|
||||
if (!error) versions.forEach(appendVersion)
|
||||
},
|
||||
context: this,
|
||||
})
|
||||
},
|
||||
|
||||
restore: function (version) {
|
||||
restore: async function (version) {
|
||||
if (!this.map.editEnabled) return
|
||||
if (!confirm(L._('Are you sure you want to restore this version?'))) return
|
||||
this.map.xhr.get(this.getVersionUrl(version), {
|
||||
callback: function (geojson) {
|
||||
if (geojson._storage) geojson._umap_options = geojson._storage // Retrocompat.
|
||||
if (geojson._umap_options) this.setOptions(geojson._umap_options)
|
||||
this.empty()
|
||||
if (this.isRemoteLayer()) this.fetchRemoteData()
|
||||
else this.addData(geojson)
|
||||
this.isDirty = true
|
||||
},
|
||||
context: this,
|
||||
})
|
||||
const [geojson, response, error] = await this.map.server.get(
|
||||
this.getVersionUrl(version)
|
||||
)
|
||||
if (!error) {
|
||||
if (geojson._storage) geojson._umap_options = geojson._storage // Retrocompat.
|
||||
if (geojson._umap_options) this.setOptions(geojson._umap_options)
|
||||
this.empty()
|
||||
if (this.isRemoteLayer()) this.fetchRemoteData()
|
||||
else this.addData(geojson)
|
||||
this.isDirty = true
|
||||
}
|
||||
},
|
||||
|
||||
featuresToGeoJSON: function () {
|
||||
|
@ -1438,9 +1433,9 @@ L.U.DataLayer = L.Evented.extend({
|
|||
return features
|
||||
},
|
||||
|
||||
show: function () {
|
||||
if (!this.isLoaded()) this.fetchData()
|
||||
show: async function () {
|
||||
this.map.addLayer(this.layer)
|
||||
if (!this.isLoaded()) await this.fetchData()
|
||||
this.fire('show')
|
||||
},
|
||||
|
||||
|
@ -1548,7 +1543,7 @@ L.U.DataLayer = L.Evented.extend({
|
|||
return this.isReadOnly() || this.isRemoteLayer()
|
||||
},
|
||||
|
||||
save: function () {
|
||||
save: async function () {
|
||||
if (this.isDeleted) return this.saveDelete()
|
||||
if (!this.isLoaded()) {
|
||||
return
|
||||
|
@ -1566,44 +1561,66 @@ L.U.DataLayer = L.Evented.extend({
|
|||
map_id: this.map.options.umap_id,
|
||||
pk: this.umap_id,
|
||||
})
|
||||
this.map.post(saveUrl, {
|
||||
data: formData,
|
||||
callback: function (data, response) {
|
||||
// Response contains geojson only if save has conflicted and conflicts have
|
||||
// been resolved. So we need to reload to get extra data (saved from someone else)
|
||||
if (data.geojson) {
|
||||
this.clear()
|
||||
this.fromGeoJSON(data.geojson)
|
||||
delete data.geojson
|
||||
}
|
||||
this._geojson = geojson
|
||||
this._last_modified = response.getResponseHeader('Last-Modified')
|
||||
this.setUmapId(data.id)
|
||||
this.updateOptions(data)
|
||||
this.backupOptions()
|
||||
this.connectToMap()
|
||||
this._loaded = true
|
||||
this.redraw() // Needed for reordering features
|
||||
this.isDirty = false
|
||||
this.permissions.save()
|
||||
},
|
||||
context: this,
|
||||
headers: this._last_modified
|
||||
? { 'If-Unmodified-Since': this._last_modified }
|
||||
: {},
|
||||
})
|
||||
const headers = this._last_modified
|
||||
? { 'If-Unmodified-Since': this._last_modified }
|
||||
: {}
|
||||
await this._trySave(saveUrl, headers, formData)
|
||||
this._geojson = geojson
|
||||
},
|
||||
|
||||
saveDelete: function () {
|
||||
const callback = function () {
|
||||
_trySave: async function (url, headers, formData) {
|
||||
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.'
|
||||
)
|
||||
const actions = [
|
||||
{
|
||||
label: L._('Save anyway'),
|
||||
callback: async () => {
|
||||
// Save again,
|
||||
// but do not pass If-Unmodified-Since this time
|
||||
await this._trySave(url, {}, formData)
|
||||
},
|
||||
},
|
||||
{
|
||||
label: L._('Cancel'),
|
||||
},
|
||||
]
|
||||
this.map.ui.alert({
|
||||
content: msg,
|
||||
level: 'error',
|
||||
duration: 100000,
|
||||
actions: actions,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// Response contains geojson only if save has conflicted and conflicts have
|
||||
// been resolved. So we need to reload to get extra data (added by someone else)
|
||||
if (data.geojson) {
|
||||
this.clear()
|
||||
this.fromGeoJSON(data.geojson)
|
||||
delete data.geojson
|
||||
}
|
||||
this._last_modified = response.headers.get('last-modified')
|
||||
this.setUmapId(data.id)
|
||||
this.updateOptions(data)
|
||||
this.backupOptions()
|
||||
this.connectToMap()
|
||||
this._loaded = true
|
||||
this.redraw() // Needed for reordering features
|
||||
this.isDirty = false
|
||||
this.map.continueSaving()
|
||||
this.permissions.save()
|
||||
}
|
||||
if (!this.umap_id) return callback.call(this)
|
||||
this.map.xhr.post(this.getDeleteUrl(), {
|
||||
callback: callback,
|
||||
context: this,
|
||||
})
|
||||
},
|
||||
|
||||
saveDelete: async function () {
|
||||
if (this.umap_id) {
|
||||
await this.map.server.post(this.getDeleteUrl())
|
||||
}
|
||||
this.isDirty = false
|
||||
this.map.continueSaving()
|
||||
},
|
||||
|
||||
getMap: function () {
|
||||
|
|
|
@ -131,21 +131,19 @@ L.U.MapPermissions = L.Class.extend({
|
|||
this.map.ui.openPanel({ data: { html: container }, className: 'dark' })
|
||||
},
|
||||
|
||||
attach: function () {
|
||||
this.map.post(this.getAttachUrl(), {
|
||||
callback: function () {
|
||||
this.options.owner = this.map.options.user
|
||||
this.map.ui.alert({
|
||||
content: L._('Map has been attached to your account'),
|
||||
level: 'info',
|
||||
})
|
||||
this.map.ui.closePanel()
|
||||
},
|
||||
context: this,
|
||||
})
|
||||
attach: async function () {
|
||||
const [data, response, error] = await this.map.server.post(this.getAttachUrl())
|
||||
if (!error) {
|
||||
this.options.owner = this.map.options.user
|
||||
this.map.ui.alert({
|
||||
content: L._('Map has been attached to your account'),
|
||||
level: 'info',
|
||||
})
|
||||
this.map.ui.closePanel()
|
||||
}
|
||||
},
|
||||
|
||||
save: function () {
|
||||
save: async function () {
|
||||
if (!this.isDirty) return this.map.continueSaving()
|
||||
const formData = new FormData()
|
||||
if (!this.isAnonymousMap() && this.options.editors) {
|
||||
|
@ -159,16 +157,17 @@ L.U.MapPermissions = L.Class.extend({
|
|||
formData.append('owner', this.options.owner && this.options.owner.id)
|
||||
formData.append('share_status', this.options.share_status)
|
||||
}
|
||||
this.map.post(this.getUrl(), {
|
||||
data: formData,
|
||||
context: this,
|
||||
callback: function (data) {
|
||||
this.commit()
|
||||
this.isDirty = false
|
||||
this.map.continueSaving()
|
||||
this.map.fire('postsync')
|
||||
},
|
||||
})
|
||||
const [data, response, error] = await this.map.server.post(
|
||||
this.getUrl(),
|
||||
{},
|
||||
formData
|
||||
)
|
||||
if (!error) {
|
||||
this.commit()
|
||||
this.isDirty = false
|
||||
this.map.continueSaving()
|
||||
this.map.fire('postsync')
|
||||
}
|
||||
},
|
||||
|
||||
getUrl: function () {
|
||||
|
|
|
@ -1,304 +0,0 @@
|
|||
L.U.Xhr = L.Evented.extend({
|
||||
initialize: function (ui) {
|
||||
this.ui = ui
|
||||
},
|
||||
|
||||
_wrapper: function () {
|
||||
let wrapper
|
||||
if (window.XMLHttpRequest === undefined) {
|
||||
wrapper = () => {
|
||||
try {
|
||||
return new window.ActiveXObject('Microsoft.XMLHTTP.6.0')
|
||||
} catch (e1) {
|
||||
try {
|
||||
return new window.ActiveXObject('Microsoft.XMLHTTP.3.0')
|
||||
} catch (e2) {
|
||||
throw new Error('XMLHttpRequest is not supported')
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
wrapper = window.XMLHttpRequest
|
||||
}
|
||||
return new wrapper()
|
||||
},
|
||||
|
||||
_ajax: function (settings) {
|
||||
const xhr = this._wrapper(),
|
||||
id = Math.random(),
|
||||
self = this
|
||||
this.fire('dataloading', { id: id })
|
||||
const loaded = () => {
|
||||
self.fire('dataload', { id: id })
|
||||
}
|
||||
|
||||
try {
|
||||
xhr.open(settings.verb, settings.uri, true)
|
||||
} catch (err) {
|
||||
// Unknown protocol?
|
||||
this.ui.alert({
|
||||
content: L._('Error while fetching {url}', { url: settings.uri }),
|
||||
level: 'error',
|
||||
})
|
||||
loaded()
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
settings.uri.indexOf('http') !== 0 ||
|
||||
settings.uri.indexOf(window.location.origin) === 0
|
||||
) {
|
||||
// "X-" mode headers cause the request to be in preflight mode,
|
||||
// we don"t want that by default for CORS requests
|
||||
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
|
||||
}
|
||||
if (settings.headers) {
|
||||
for (const name in settings.headers) {
|
||||
xhr.setRequestHeader(name, settings.headers[name])
|
||||
}
|
||||
}
|
||||
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status == 200) {
|
||||
settings.callback.call(settings.context || xhr, xhr.responseText, xhr)
|
||||
} else if (xhr.status === 403) {
|
||||
self.ui.alert({
|
||||
content: xhr.responseText || L._('Action not allowed :('),
|
||||
level: 'error',
|
||||
})
|
||||
} else if (xhr.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 () {
|
||||
delete settings.headers['If-Match']
|
||||
self._ajax(settings)
|
||||
},
|
||||
callbackContext: self,
|
||||
},
|
||||
{
|
||||
label: L._('Cancel'),
|
||||
},
|
||||
]
|
||||
self.ui.alert({
|
||||
content: msg,
|
||||
level: 'error',
|
||||
duration: 100000,
|
||||
actions: actions,
|
||||
})
|
||||
} else {
|
||||
if (xhr.status === 0) {
|
||||
// 0 === request cut by user or CORS
|
||||
self.ui.alert({
|
||||
content: L._(
|
||||
'Issue reaching that URL (network problem or CORS protection): {url}',
|
||||
{ url: settings.uri }
|
||||
),
|
||||
level: 'error',
|
||||
})
|
||||
} else {
|
||||
self.ui.alert({ content: L._('Problem in the response'), level: 'error' })
|
||||
}
|
||||
}
|
||||
loaded()
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
xhr.send(settings.data)
|
||||
} catch (e) {
|
||||
// Pass
|
||||
loaded()
|
||||
console.error('Bad Request', e)
|
||||
}
|
||||
},
|
||||
|
||||
// supports only JSON as response data type
|
||||
_json: function (verb, uri, options) {
|
||||
const args = arguments,
|
||||
self = this
|
||||
const default_options = {
|
||||
async: true,
|
||||
callback: null,
|
||||
responseType: 'text',
|
||||
data: null,
|
||||
listen_form: null, // optional form to listen in default callback
|
||||
}
|
||||
const settings = L.Util.extend({}, default_options, options)
|
||||
|
||||
if (verb === 'POST') {
|
||||
// find a way not to make this django specific
|
||||
const token = document.cookie.replace(
|
||||
/(?:(?:^|.*;\s*)csrftoken\s*\=\s*([^;]*).*$)|^.*$/,
|
||||
'$1'
|
||||
)
|
||||
if (token) {
|
||||
settings.headers = settings.headers || {}
|
||||
settings.headers['X-CSRFToken'] = token
|
||||
}
|
||||
}
|
||||
|
||||
const callback = function (responseText, response) {
|
||||
let data
|
||||
try {
|
||||
data = JSON.parse(responseText)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
self.ui.alert({
|
||||
content: L._('Problem in the response format'),
|
||||
level: 'error',
|
||||
})
|
||||
return
|
||||
}
|
||||
if (data.errors) {
|
||||
console.log(data.errors)
|
||||
self.ui.alert({ content: L._('An error occured'), level: 'error' })
|
||||
} else if (data.login_required) {
|
||||
// login_required should be an URL for the login form
|
||||
if (settings.login_callback) settings.login_callback(data)
|
||||
else self.login(data, args)
|
||||
} else {
|
||||
if (settings.callback)
|
||||
L.bind(settings.callback, settings.context || this)(data, response)
|
||||
else self.default_callback(data, settings, response)
|
||||
}
|
||||
}
|
||||
|
||||
this._ajax({
|
||||
verb: verb,
|
||||
uri: uri,
|
||||
data: settings.data,
|
||||
callback: callback,
|
||||
headers: settings.headers,
|
||||
listener: settings.listener,
|
||||
})
|
||||
},
|
||||
|
||||
get: function (uri, options) {
|
||||
this._json('GET', uri, options)
|
||||
},
|
||||
|
||||
post: function (uri, options) {
|
||||
this._json('POST', uri, options)
|
||||
},
|
||||
|
||||
submit_form: function (form_id, options) {
|
||||
if (typeof options === 'undefined') options = {}
|
||||
const form = L.DomUtil.get(form_id)
|
||||
const formData = new FormData(form)
|
||||
if (options.extraFormData) formData.append(options.extraFormData)
|
||||
options.data = formData
|
||||
this.post(form.action, options)
|
||||
return false
|
||||
},
|
||||
|
||||
listen_form: function (form_id, options) {
|
||||
const form = L.DomUtil.get(form_id),
|
||||
self = this
|
||||
if (!form) return
|
||||
L.DomEvent.on(form, 'submit', L.DomEvent.stopPropagation)
|
||||
.on(form, 'submit', L.DomEvent.preventDefault)
|
||||
.on(form, 'submit', () => {
|
||||
self.submit_form(form_id, options)
|
||||
})
|
||||
},
|
||||
|
||||
listen_link: function (link_id, options) {
|
||||
const link = L.DomUtil.get(link_id),
|
||||
self = this
|
||||
if (link) {
|
||||
L.DomEvent.on(link, 'click', L.DomEvent.stop).on(link, 'click', () => {
|
||||
if (options.confirm && !confirm(options.confirm)) {
|
||||
return
|
||||
}
|
||||
self.get(link.href, options)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
default_callback: function (data, options) {
|
||||
// default callback, to avoid boilerplate
|
||||
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: data }
|
||||
let listen_options
|
||||
if (options.className) ui_options.className = options.className
|
||||
this.ui.openPanel(ui_options)
|
||||
// To low boilerplate, if there is a form, listen it
|
||||
if (options.listen_form) {
|
||||
// Listen form again
|
||||
listen_options = L.Util.extend({}, options, options.listen_form.options)
|
||||
this.listen_form(options.listen_form.id, listen_options)
|
||||
}
|
||||
if (options.listen_link) {
|
||||
for (let i = 0, l = options.listen_link.length; i < l; i++) {
|
||||
// Listen link again
|
||||
listen_options = L.Util.extend({}, options, options.listen_link[i].options)
|
||||
this.listen_link(options.listen_link[i].id, listen_options)
|
||||
}
|
||||
}
|
||||
} else if (options.success) {
|
||||
// Success is called only if data contain no msg and no html
|
||||
options.success(data)
|
||||
}
|
||||
},
|
||||
|
||||
login: function (data, args) {
|
||||
// data.html: login form
|
||||
// args: args of the first _json call, to call again at process end
|
||||
const self = this
|
||||
const proceed = () => {
|
||||
self.ui.closePanel()
|
||||
if (typeof args !== 'undefined') self._json.apply(self, args)
|
||||
else self.default_callback(data, {})
|
||||
}
|
||||
const ask_for_login = (data) => {
|
||||
self.ui.openPanel({ data: data, className: 'login-panel' })
|
||||
self.listen_form('login_form', {
|
||||
callback: function (data) {
|
||||
if (data.html) ask_for_login(data) // Problem in the login - ask again
|
||||
else proceed()
|
||||
},
|
||||
})
|
||||
// Auth links
|
||||
const links = document.getElementsByClassName('umap-login-popup')
|
||||
Object.keys(links).forEach((el) => {
|
||||
const link = links[el]
|
||||
L.DomEvent.on(link, 'click', L.DomEvent.stop).on(link, 'click', () => {
|
||||
self.ui.closePanel()
|
||||
const win = window.open(link.href)
|
||||
window.umap_proceed = () => {
|
||||
proceed()
|
||||
win.close()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if (data.login_required) {
|
||||
this.get(data.login_required, {
|
||||
callback: function (data) {
|
||||
ask_for_login(data)
|
||||
},
|
||||
})
|
||||
} else {
|
||||
ask_for_login(data)
|
||||
}
|
||||
},
|
||||
|
||||
logout: function (url) {
|
||||
this.get(url)
|
||||
},
|
||||
})
|
|
@ -176,24 +176,26 @@ const POLYGONS = {
|
|||
],
|
||||
}
|
||||
|
||||
describe('L.U.Choropleth', function () {
|
||||
describe('L.U.Choropleth', () => {
|
||||
let path = '/map/99/datalayer/edit/62/',
|
||||
poly1,
|
||||
poly4,
|
||||
poly9
|
||||
poly9,
|
||||
map,
|
||||
datalayer
|
||||
|
||||
before(function () {
|
||||
this.server = sinon.fakeServer.create()
|
||||
this.server.respondWith(/\/datalayer\/62\/\?.*/, JSON.stringify(POLYGONS))
|
||||
this.map = initMap({ umap_id: 99 })
|
||||
this.datalayer = this.map.getDataLayerByUmapId(62)
|
||||
this.server.respond()
|
||||
this.datalayer.options.type = 'Choropleth'
|
||||
this.datalayer.options.choropleth = {
|
||||
before(async () => {
|
||||
fetchMock.mock(/\/datalayer\/62\/\?.*/, JSON.stringify(POLYGONS))
|
||||
map = initMap({ umap_id: 99 })
|
||||
const datalayer_options = defaultDatalayerData()
|
||||
await map.initDataLayers([datalayer_options])
|
||||
datalayer = map.getDataLayerByUmapId(62)
|
||||
datalayer.options.type = 'Choropleth'
|
||||
datalayer.options.choropleth = {
|
||||
property: 'value',
|
||||
}
|
||||
enableEdit()
|
||||
this.datalayer.eachLayer(function (layer) {
|
||||
datalayer.eachLayer(function (layer) {
|
||||
if (layer.properties.name === 'number 1') {
|
||||
poly1 = layer
|
||||
} else if (layer.properties.name === 'number 4') {
|
||||
|
@ -203,38 +205,38 @@ describe('L.U.Choropleth', function () {
|
|||
}
|
||||
})
|
||||
})
|
||||
after(function () {
|
||||
this.server.restore()
|
||||
after(() => {
|
||||
fetchMock.restore()
|
||||
resetMap()
|
||||
})
|
||||
|
||||
describe('#init()', function () {
|
||||
it('datalayer should have 9 features', function () {
|
||||
assert.equal(this.datalayer._index.length, 9)
|
||||
describe('#init()', () => {
|
||||
it('datalayer should have 9 features', () => {
|
||||
assert.equal(datalayer._index.length, 9)
|
||||
})
|
||||
})
|
||||
describe('#compute()', function () {
|
||||
it('choropleth should compute default colors', function () {
|
||||
this.datalayer.resetLayer(true)
|
||||
describe('#compute()', () => {
|
||||
it('choropleth should compute default colors', () => {
|
||||
datalayer.resetLayer(true)
|
||||
assert.deepEqual(
|
||||
this.datalayer.layer.options.breaks,
|
||||
datalayer.layer.options.breaks,
|
||||
[45, 673, 3829, 4900, 9898, 9898]
|
||||
)
|
||||
assert.equal(poly1._path.attributes.fill.value, '#eff3ff')
|
||||
assert.equal(poly4._path.attributes.fill.value, '#bdd7e7')
|
||||
assert.equal(poly9._path.attributes.fill.value, '#3182bd')
|
||||
})
|
||||
it('can change brewer scheme', function () {
|
||||
this.datalayer.options.choropleth.brewer = 'Reds'
|
||||
this.datalayer.resetLayer(true)
|
||||
it('can change brewer scheme', () => {
|
||||
datalayer.options.choropleth.brewer = 'Reds'
|
||||
datalayer.resetLayer(true)
|
||||
assert.equal(poly1._path.attributes.fill.value, '#fee5d9')
|
||||
assert.equal(poly4._path.attributes.fill.value, '#fcae91')
|
||||
assert.equal(poly9._path.attributes.fill.value, '#de2d26')
|
||||
})
|
||||
it('choropleth should allow to change steps', function () {
|
||||
this.datalayer.options.choropleth.brewer = 'Blues'
|
||||
this.datalayer.options.choropleth.classes = 6
|
||||
this.datalayer.resetLayer(true)
|
||||
it('choropleth should allow to change steps', () => {
|
||||
datalayer.options.choropleth.brewer = 'Blues'
|
||||
datalayer.options.choropleth.classes = 6
|
||||
datalayer.resetLayer(true)
|
||||
assert.equal(poly1._path.attributes.fill.value, '#eff3ff')
|
||||
assert.equal(poly4._path.attributes.fill.value, '#c6dbef')
|
||||
assert.equal(poly9._path.attributes.fill.value, '#3182bd')
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
describe('L.U.Controls', function () {
|
||||
before(function () {
|
||||
this.server = sinon.fakeServer.create()
|
||||
this.server.respondWith(
|
||||
/\/datalayer\/62\/\?.*/,
|
||||
JSON.stringify(RESPONSES.datalayer62_GET)
|
||||
)
|
||||
this.map = initMap({ umap_id: 99 })
|
||||
this.server.respond()
|
||||
this.datalayer = this.map.getDataLayerByUmapId(62)
|
||||
})
|
||||
after(function () {
|
||||
this.server.restore()
|
||||
resetMap()
|
||||
})
|
||||
|
||||
describe('#databrowser()', function () {
|
||||
let poly, marker, line
|
||||
before(function () {
|
||||
this.datalayer.eachLayer(function (layer) {
|
||||
if (!poly && layer instanceof L.Polygon) {
|
||||
poly = layer
|
||||
} else if (!line && layer instanceof L.Polyline) {
|
||||
line = layer
|
||||
} else if (!marker && layer instanceof L.Marker) {
|
||||
marker = layer
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('should be opened at datalayer button click', function () {
|
||||
var button = qs('.umap-browse-actions .umap-browse-link')
|
||||
assert.ok(button)
|
||||
happen.click(button)
|
||||
assert.ok(qs('#umap-ui-container .umap-browse-data'))
|
||||
})
|
||||
|
||||
it('should contain datalayer section', function () {
|
||||
assert.ok(qs('#browse_data_datalayer_62'))
|
||||
})
|
||||
|
||||
it("should contain datalayer's features list", function () {
|
||||
assert.equal(qsa('#browse_data_datalayer_62 ul li').length, 3)
|
||||
})
|
||||
|
||||
it('should sort feature in natural order', function () {
|
||||
poly.properties.name = '9. a poly'
|
||||
marker.properties.name = '1. a marker'
|
||||
line.properties.name = '100. a line'
|
||||
this.datalayer.reindex()
|
||||
this.map.openBrowser()
|
||||
const els = qsa('.umap-browse-features li')
|
||||
assert.equal(els.length, 3)
|
||||
assert.equal(els[0].textContent, '1. a marker')
|
||||
assert.equal(els[1].textContent, '9. a poly')
|
||||
assert.equal(els[2].textContent, '100. a line')
|
||||
})
|
||||
|
||||
it("should redraw datalayer's features list at feature delete", function () {
|
||||
var oldConfirm = window.confirm
|
||||
window.confirm = function () {
|
||||
return true
|
||||
}
|
||||
enableEdit()
|
||||
happen.once(qs('path[fill="DarkBlue"]'), { type: 'contextmenu' })
|
||||
happen.click(qs('.leaflet-contextmenu .umap-delete'))
|
||||
assert.equal(qsa('#browse_data_datalayer_62 ul li').length, 2)
|
||||
window.confirm = oldConfirm
|
||||
})
|
||||
|
||||
it("should redraw datalayer's features list on edit cancel", function () {
|
||||
clickCancel()
|
||||
happen.click(qs('.umap-browse-actions .umap-browse-link'))
|
||||
assert.equal(qsa('#browse_data_datalayer_62 ul li').length, 3)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#exportPanel()', function () {
|
||||
it('should be opened at datalayer button click', function () {
|
||||
let button = qs('.leaflet-control-embed button')
|
||||
assert.ok(button)
|
||||
happen.click(button)
|
||||
assert.ok(qs('#umap-ui-container .umap-share'))
|
||||
})
|
||||
it('should update iframe link', function () {
|
||||
let textarea = qs('.umap-share-iframe')
|
||||
assert.ok(textarea)
|
||||
console.log(textarea.textContent)
|
||||
assert.include(textarea.textContent, 'src="')
|
||||
assert.include(textarea.textContent, 'href="')
|
||||
// We should ave both, once for iframe link, once for full screen
|
||||
assert.include(textarea.textContent, 'scrollWheelZoom=true')
|
||||
assert.include(textarea.textContent, 'scrollWheelZoom=false')
|
||||
assert.notInclude(textarea.textContent, 'datalayers=62')
|
||||
let switcher = qs('label[title="Keep current visible layers"]')
|
||||
happen.click(switcher)
|
||||
assert.include(textarea.textContent, 'datalayers=62')
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,55 +1,54 @@
|
|||
describe('L.U.DataLayer', function () {
|
||||
var path = '/map/99/datalayer/edit/62/'
|
||||
describe('L.U.DataLayer', () => {
|
||||
let path = '/map/99/datalayer/update/62/',
|
||||
map,
|
||||
datalayer
|
||||
|
||||
before(function () {
|
||||
this.server = sinon.fakeServer.create()
|
||||
this.server.respondWith(
|
||||
/\/datalayer\/62\/\?.*/,
|
||||
JSON.stringify(RESPONSES.datalayer62_GET)
|
||||
)
|
||||
this.map = initMap({ umap_id: 99 })
|
||||
this.datalayer = this.map.getDataLayerByUmapId(62)
|
||||
this.server.respond()
|
||||
before(async () => {
|
||||
fetchMock.mock(/\/datalayer\/62\/\?.*/, JSON.stringify(RESPONSES.datalayer62_GET))
|
||||
fetchMock.sticky('/map/99/update/settings/', { id: 99 })
|
||||
this.options = {
|
||||
umap_id: 99,
|
||||
}
|
||||
MAP = map = initMap({ umap_id: 99 })
|
||||
const datalayer_options = defaultDatalayerData()
|
||||
await map.initDataLayers([datalayer_options])
|
||||
datalayer = map.getDataLayerByUmapId(62)
|
||||
enableEdit()
|
||||
})
|
||||
after(function () {
|
||||
this.server.restore()
|
||||
after(() => {
|
||||
fetchMock.restore()
|
||||
resetMap()
|
||||
})
|
||||
|
||||
describe('#init()', function () {
|
||||
it('should be added in datalayers index', function () {
|
||||
assert.notEqual(this.map.datalayers_index.indexOf(this.datalayer), -1)
|
||||
describe('#init()', () => {
|
||||
it('should be added in datalayers index', () => {
|
||||
assert.notEqual(map.datalayers_index.indexOf(datalayer), -1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#edit()', function () {
|
||||
describe('#edit()', () => {
|
||||
var editButton, form, input, forceButton
|
||||
|
||||
it('row in control should be active', function () {
|
||||
it('row in control should be active', () => {
|
||||
assert.notOk(
|
||||
qs(
|
||||
'.leaflet-control-browse #browse_data_toggle_' +
|
||||
L.stamp(this.datalayer) +
|
||||
'.off'
|
||||
)
|
||||
qs('.leaflet-control-browse #browse_data_toggle_' + L.stamp(datalayer) + '.off')
|
||||
)
|
||||
})
|
||||
|
||||
it('should have edit button', function () {
|
||||
editButton = qs('#browse_data_toggle_' + L.stamp(this.datalayer) + ' .layer-edit')
|
||||
it('should have edit button', () => {
|
||||
editButton = qs('#browse_data_toggle_' + L.stamp(datalayer) + ' .layer-edit')
|
||||
assert.ok(editButton)
|
||||
})
|
||||
|
||||
it('should have toggle visibility element', function () {
|
||||
it('should have toggle visibility element', () => {
|
||||
assert.ok(qs('.leaflet-control-browse i.layer-toggle'))
|
||||
})
|
||||
|
||||
it('should exist only one datalayer', function () {
|
||||
it('should exist only one datalayer', () => {
|
||||
assert.equal(qsa('.leaflet-control-browse i.layer-toggle').length, 1)
|
||||
})
|
||||
|
||||
it('should build a form on edit button click', function () {
|
||||
it('should build a form on edit button click', () => {
|
||||
happen.click(editButton)
|
||||
form = qs('form.umap-form')
|
||||
input = qs('form.umap-form input[name="name"]')
|
||||
|
@ -57,97 +56,81 @@ describe('L.U.DataLayer', function () {
|
|||
assert.ok(input)
|
||||
})
|
||||
|
||||
it('should update name on input change', function () {
|
||||
it('should update name on input change', () => {
|
||||
var new_name = 'This is a new name'
|
||||
input.value = new_name
|
||||
happen.once(input, { type: 'input' })
|
||||
assert.equal(this.datalayer.options.name, new_name)
|
||||
assert.equal(datalayer.options.name, new_name)
|
||||
})
|
||||
|
||||
it('should have made datalayer dirty', function () {
|
||||
assert.ok(this.datalayer.isDirty)
|
||||
assert.notEqual(this.map.dirty_datalayers.indexOf(this.datalayer), -1)
|
||||
it('should have made datalayer dirty', () => {
|
||||
assert.ok(datalayer.isDirty)
|
||||
assert.notEqual(map.dirty_datalayers.indexOf(datalayer), -1)
|
||||
})
|
||||
|
||||
it('should have made Map dirty', function () {
|
||||
assert.ok(this.map.isDirty)
|
||||
it('should have made Map dirty', () => {
|
||||
assert.ok(map.isDirty)
|
||||
})
|
||||
|
||||
it('should call datalayer.save on save button click', function (done) {
|
||||
sinon.spy(this.datalayer, 'save')
|
||||
this.server.flush()
|
||||
this.server.respondWith(
|
||||
'POST',
|
||||
'/map/99/update/settings/',
|
||||
JSON.stringify({ id: 99 })
|
||||
)
|
||||
this.server.respondWith(
|
||||
'POST',
|
||||
'/map/99/datalayer/update/62/',
|
||||
JSON.stringify(defaultDatalayerData())
|
||||
)
|
||||
it('should call datalayer.save on save button click', (done) => {
|
||||
const postDatalayer = fetchMock.post(path, () => {
|
||||
return defaultDatalayerData()
|
||||
})
|
||||
clickSave()
|
||||
this.server.respond()
|
||||
this.server.respond()
|
||||
assert(this.datalayer.save.calledOnce)
|
||||
this.datalayer.save.restore()
|
||||
done()
|
||||
window.setTimeout(() => {
|
||||
assert(fetchMock.called(path))
|
||||
done()
|
||||
}, 500)
|
||||
})
|
||||
|
||||
it('should show alert if server respond 412', function () {
|
||||
it('should show alert if server respond 412', (done) => {
|
||||
cleanAlert()
|
||||
this.server.flush()
|
||||
this.server.respondWith(
|
||||
'POST',
|
||||
'/map/99/update/settings/',
|
||||
JSON.stringify({ id: 99 })
|
||||
)
|
||||
this.server.respondWith('POST', '/map/99/datalayer/update/62/', [412, {}, ''])
|
||||
fetchMock.restore()
|
||||
fetchMock.post(path, 412)
|
||||
happen.click(editButton)
|
||||
input = qs('form.umap-form input[name="name"]')
|
||||
input.value = 'a new name'
|
||||
happen.once(input, { type: 'input' })
|
||||
clickSave()
|
||||
this.server.respond()
|
||||
this.server.respond()
|
||||
assert(L.DomUtil.hasClass(this.map._container, 'umap-alert'))
|
||||
assert.notEqual(this.map.dirty_datalayers.indexOf(this.datalayer), -1)
|
||||
forceButton = qs('#umap-alert-container .umap-action')
|
||||
assert.ok(forceButton)
|
||||
window.setTimeout(() => {
|
||||
assert(L.DomUtil.hasClass(map._container, 'umap-alert'))
|
||||
assert.notEqual(map.dirty_datalayers.indexOf(datalayer), -1)
|
||||
const forceButton = qs('#umap-alert-container .umap-action')
|
||||
assert.ok(forceButton)
|
||||
done()
|
||||
}, 500)
|
||||
})
|
||||
|
||||
it('should save anyway on force save button click', function () {
|
||||
sinon.spy(this.map, 'continueSaving')
|
||||
it('should save anyway on force save button click', (done) => {
|
||||
const forceButton = qs('#umap-alert-container .umap-action')
|
||||
fetchMock.restore()
|
||||
fetchMock.post(path, defaultDatalayerData)
|
||||
happen.click(forceButton)
|
||||
this.server.flush()
|
||||
this.server.respond(
|
||||
'POST',
|
||||
'/map/99/datalayer/update/62/',
|
||||
JSON.stringify(defaultDatalayerData())
|
||||
)
|
||||
assert.notOk(qs('#umap-alert-container .umap-action'))
|
||||
assert(this.map.continueSaving.calledOnce)
|
||||
this.map.continueSaving.restore()
|
||||
assert.equal(this.map.dirty_datalayers.indexOf(this.datalayer), -1)
|
||||
window.setTimeout(() => {
|
||||
assert.notOk(qs('#umap-alert-container .umap-action'))
|
||||
assert(fetchMock.called(path))
|
||||
assert.equal(map.dirty_datalayers.indexOf(datalayer), -1)
|
||||
done()
|
||||
}, 500)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#save() new', function () {
|
||||
var newLayerButton, form, input, newDatalayer, editButton, manageButton
|
||||
describe('#save() new', () => {
|
||||
let newLayerButton, form, input, newDatalayer, editButton, manageButton
|
||||
|
||||
it('should have a manage datalayers action', function () {
|
||||
it('should have a manage datalayers action', () => {
|
||||
enableEdit()
|
||||
manageButton = qs('.manage-datalayers')
|
||||
assert.ok(manageButton)
|
||||
happen.click(manageButton)
|
||||
})
|
||||
|
||||
it('should have a new layer button', function () {
|
||||
it('should have a new layer button', () => {
|
||||
newLayerButton = qs('#umap-ui-container .add-datalayer')
|
||||
assert.ok(newLayerButton)
|
||||
})
|
||||
|
||||
it('should build a form on new layer button click', function () {
|
||||
it('should build a form on new layer button click', () => {
|
||||
happen.click(newLayerButton)
|
||||
form = qs('form.umap-form')
|
||||
input = qs('form.umap-form input[name="name"]')
|
||||
|
@ -155,86 +138,72 @@ describe('L.U.DataLayer', function () {
|
|||
assert.ok(input)
|
||||
})
|
||||
|
||||
it('should have an empty name', function () {
|
||||
it('should have an empty name', () => {
|
||||
assert.notOk(input.value)
|
||||
})
|
||||
|
||||
it('should have created a new datalayer', function () {
|
||||
assert.equal(this.map.datalayers_index.length, 2)
|
||||
newDatalayer = this.map.datalayers_index[1]
|
||||
it('should have created a new datalayer', () => {
|
||||
assert.equal(map.datalayers_index.length, 2)
|
||||
newDatalayer = map.datalayers_index[1]
|
||||
})
|
||||
|
||||
it('should have made Map dirty', function () {
|
||||
assert.ok(this.map.isDirty)
|
||||
it('should have made Map dirty', () => {
|
||||
assert.ok(map.isDirty)
|
||||
})
|
||||
|
||||
it('should update name on input change', function () {
|
||||
it('should update name on input change', () => {
|
||||
var new_name = 'This is a new name'
|
||||
input.value = new_name
|
||||
happen.once(input, { type: 'input' })
|
||||
assert.equal(newDatalayer.options.name, new_name)
|
||||
})
|
||||
|
||||
it('should set umap_id on save callback', function () {
|
||||
it('should set umap_id on save callback', async () => {
|
||||
assert.notOk(newDatalayer.umap_id)
|
||||
this.server.flush()
|
||||
this.server.respondWith(
|
||||
'POST',
|
||||
'/map/99/update/settings/',
|
||||
JSON.stringify({ id: 99 })
|
||||
)
|
||||
this.server.respondWith(
|
||||
'POST',
|
||||
'/map/99/datalayer/create/',
|
||||
JSON.stringify(defaultDatalayerData({ id: 63 }))
|
||||
)
|
||||
fetchMock.post('/map/99/datalayer/create/', defaultDatalayerData({ id: 63 }))
|
||||
clickSave()
|
||||
this.server.respond()
|
||||
this.server.respond() // First respond will then trigger another Xhr request (continueSaving)
|
||||
assert.equal(newDatalayer.umap_id, 63)
|
||||
return new Promise((resolve) => {
|
||||
window.setTimeout(() => {
|
||||
assert.equal(newDatalayer.umap_id, 63)
|
||||
resolve()
|
||||
}, 1000)
|
||||
})
|
||||
})
|
||||
|
||||
it('should have unset map dirty', function () {
|
||||
assert.notOk(this.map.isDirty)
|
||||
it('should have unset map dirty', () => {
|
||||
assert.notOk(map.isDirty)
|
||||
})
|
||||
|
||||
it('should have edit button', function () {
|
||||
it('should have edit button', () => {
|
||||
editButton = qs('#browse_data_toggle_' + L.stamp(newDatalayer) + ' .layer-edit')
|
||||
assert.ok(editButton)
|
||||
})
|
||||
|
||||
it('should call update if we edit again', function () {
|
||||
it('should call update if we edit again', async () => {
|
||||
happen.click(editButton)
|
||||
assert.notOk(this.map.isDirty)
|
||||
assert.notOk(map.isDirty)
|
||||
input = qs('form.umap-form input[name="name"]')
|
||||
input.value = "a new name again but we don't care which"
|
||||
happen.once(input, { type: 'input' })
|
||||
assert.ok(this.map.isDirty)
|
||||
var response = function (request) {
|
||||
return request.respond(
|
||||
200,
|
||||
{},
|
||||
JSON.stringify(defaultDatalayerData({ pk: 63 }))
|
||||
)
|
||||
assert.ok(map.isDirty)
|
||||
var response = () => {
|
||||
return defaultDatalayerData({ pk: 63 })
|
||||
}
|
||||
var spy = sinon.spy(response)
|
||||
this.server.flush()
|
||||
this.server.respondWith(
|
||||
'POST',
|
||||
'/map/99/update/settings/',
|
||||
JSON.stringify({ id: 99 })
|
||||
)
|
||||
this.server.respondWith('POST', '/map/99/datalayer/update/63/', spy)
|
||||
clickSave()
|
||||
this.server.respond()
|
||||
this.server.respond()
|
||||
assert.ok(spy.calledOnce)
|
||||
fetchMock.post('/map/99/datalayer/update/63/', spy)
|
||||
return new Promise((resolve) => {
|
||||
clickSave()
|
||||
window.setTimeout(() => {
|
||||
assert.ok(spy.calledOnce)
|
||||
resolve()
|
||||
}, 1000)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('#iconClassChange()', function () {
|
||||
it('should change icon class', function () {
|
||||
happen.click(qs('[data-id="' + this.datalayer._leaflet_id + '"] .layer-edit'))
|
||||
describe('#iconClassChange()', () => {
|
||||
it('should change icon class', () => {
|
||||
happen.click(qs('[data-id="' + datalayer._leaflet_id + '"] .layer-edit'))
|
||||
changeSelectValue(
|
||||
qs('form#datalayer-advanced-properties select[name=iconClass]'),
|
||||
'Circle'
|
||||
|
@ -250,53 +219,53 @@ describe('L.U.DataLayer', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('#show/hide', function () {
|
||||
it('should hide features on hide', function () {
|
||||
describe('#show/hide', () => {
|
||||
it('should hide features on hide', () => {
|
||||
assert.ok(qs('div.umap-div-icon'))
|
||||
assert.ok(qs('path[fill="none"]'))
|
||||
this.datalayer.hide()
|
||||
datalayer.hide()
|
||||
assert.notOk(qs('div.umap-div-icon'))
|
||||
assert.notOk(qs('path[fill="none"]'))
|
||||
})
|
||||
|
||||
it('should show features on show', function () {
|
||||
it('should show features on show', () => {
|
||||
assert.notOk(qs('div.umap-div-icon'))
|
||||
assert.notOk(qs('path[fill="none"]'))
|
||||
this.datalayer.show()
|
||||
datalayer.show()
|
||||
assert.ok(qs('div.umap-div-icon'))
|
||||
assert.ok(qs('path[fill="none"]'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('#clone()', function () {
|
||||
it('should clone everything but the id and the name', function () {
|
||||
describe('#clone()', () => {
|
||||
it('should clone everything but the id and the name', () => {
|
||||
enableEdit()
|
||||
var clone = this.datalayer.clone()
|
||||
var clone = datalayer.clone()
|
||||
assert.notOk(clone.umap_id)
|
||||
assert.notEqual(clone.options.name, this.datalayer.name)
|
||||
assert.notEqual(clone.options.name, datalayer.name)
|
||||
assert.ok(clone.options.name)
|
||||
assert.equal(clone.options.color, this.datalayer.options.color)
|
||||
assert.equal(clone.options.stroke, this.datalayer.options.stroke)
|
||||
assert.equal(clone.options.color, datalayer.options.color)
|
||||
assert.equal(clone.options.stroke, datalayer.options.stroke)
|
||||
clone._delete()
|
||||
clickSave()
|
||||
})
|
||||
})
|
||||
|
||||
describe('#restore()', function () {
|
||||
describe('#restore()', () => {
|
||||
var oldConfirm,
|
||||
newConfirm = function () {
|
||||
newConfirm = () => {
|
||||
return true
|
||||
}
|
||||
|
||||
before(function () {
|
||||
before(() => {
|
||||
oldConfirm = window.confirm
|
||||
window.confirm = newConfirm
|
||||
})
|
||||
after(function () {
|
||||
after(() => {
|
||||
window.confirm = oldConfirm
|
||||
})
|
||||
|
||||
it('should restore everything', function () {
|
||||
it('should restore everything', (done) => {
|
||||
enableEdit()
|
||||
var geojson = L.Util.CopyJSON(RESPONSES.datalayer62_GET)
|
||||
geojson.features.push({
|
||||
|
@ -309,33 +278,31 @@ describe('L.U.DataLayer', function () {
|
|||
properties: { _umap_options: {}, name: 'new point from restore' },
|
||||
})
|
||||
geojson._umap_options.color = 'Chocolate'
|
||||
this.server.respondWith(
|
||||
'GET',
|
||||
'/datalayer/62/olderversion.geojson',
|
||||
JSON.stringify(geojson)
|
||||
)
|
||||
fetchMock.get('/datalayer/62/olderversion.geojson', geojson)
|
||||
sinon.spy(window, 'confirm')
|
||||
this.datalayer.restore('olderversion.geojson')
|
||||
this.server.respond()
|
||||
assert(window.confirm.calledOnce)
|
||||
window.confirm.restore()
|
||||
assert.equal(this.datalayer.umap_id, 62)
|
||||
assert.ok(this.datalayer.isDirty)
|
||||
assert.equal(this.datalayer._index.length, 4)
|
||||
assert.ok(qs('path[fill="Chocolate"]'))
|
||||
datalayer.restore('olderversion.geojson')
|
||||
window.setTimeout(() => {
|
||||
assert(window.confirm.calledOnce)
|
||||
window.confirm.restore()
|
||||
assert.equal(datalayer.umap_id, 62)
|
||||
assert.ok(datalayer.isDirty)
|
||||
assert.equal(datalayer._index.length, 4)
|
||||
assert.ok(qs('path[fill="Chocolate"]'))
|
||||
done()
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
it('should revert anything on cancel click', function () {
|
||||
it('should revert anything on cancel click', () => {
|
||||
clickCancel()
|
||||
assert.equal(this.datalayer._index.length, 3)
|
||||
assert.equal(datalayer._index.length, 3)
|
||||
assert.notOk(qs('path[fill="Chocolate"]'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('#smart-options()', function () {
|
||||
describe('#smart-options()', () => {
|
||||
let poly, marker
|
||||
before(function () {
|
||||
this.datalayer.eachLayer(function (layer) {
|
||||
before(() => {
|
||||
datalayer.eachLayer(function (layer) {
|
||||
if (!poly && layer instanceof L.Polygon) {
|
||||
poly = layer
|
||||
}
|
||||
|
@ -345,39 +312,35 @@ describe('L.U.DataLayer', function () {
|
|||
})
|
||||
})
|
||||
|
||||
it('should parse color variable', function () {
|
||||
it('should parse color variable', () => {
|
||||
let icon = qs('div.umap-div-icon .icon_container')
|
||||
poly.properties.mycolor = 'DarkGoldenRod'
|
||||
marker.properties.mycolor = 'DarkRed'
|
||||
marker.properties._umap_options.color = undefined
|
||||
assert.notOk(qs('path[fill="DarkGoldenRod"]'))
|
||||
assert.equal(icon.style.backgroundColor, 'olivedrab')
|
||||
this.datalayer.options.color = '{mycolor}'
|
||||
this.datalayer.options.fillColor = '{mycolor}'
|
||||
this.datalayer.indexProperties(poly)
|
||||
this.datalayer.indexProperties(marker)
|
||||
this.datalayer.redraw()
|
||||
datalayer.options.color = '{mycolor}'
|
||||
datalayer.options.fillColor = '{mycolor}'
|
||||
datalayer.indexProperties(poly)
|
||||
datalayer.indexProperties(marker)
|
||||
datalayer.redraw()
|
||||
icon = qs('div.umap-div-icon .icon_container')
|
||||
assert.equal(icon.style.backgroundColor, 'darkred')
|
||||
assert.ok(qs('path[fill="DarkGoldenRod"]'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('#facet-search()', function () {
|
||||
before(function () {
|
||||
this.server.respondWith(
|
||||
/\/datalayer\/63\/\?.*/,
|
||||
JSON.stringify(RESPONSES.datalayer63_GET)
|
||||
)
|
||||
this.map.options.facetKey = 'name'
|
||||
this.map.createDataLayer(RESPONSES.datalayer63_GET._umap_options)
|
||||
this.server.respond()
|
||||
describe('#facet-search()', () => {
|
||||
before(async () => {
|
||||
fetchMock.get(/\/datalayer\/63\/\?.*/, RESPONSES.datalayer63_GET)
|
||||
map.options.facetKey = 'name'
|
||||
await map.initDataLayers([RESPONSES.datalayer63_GET._umap_options])
|
||||
})
|
||||
it('should not impact non browsable layer', function () {
|
||||
it('should not impact non browsable layer', () => {
|
||||
assert.ok(qs('path[fill="SteelBlue"]'))
|
||||
})
|
||||
it('should allow advanced filter', function () {
|
||||
this.map.openFacet()
|
||||
it('should allow advanced filter', () => {
|
||||
map.openFacet()
|
||||
assert.ok(qs('div.umap-facet-search'))
|
||||
// This one if from the normal datalayer
|
||||
// it's name is "test", so it should be hidden
|
||||
|
@ -390,104 +353,109 @@ describe('L.U.DataLayer', function () {
|
|||
assert.ok(qs('path[fill="SteelBlue"]'))
|
||||
happen.click(qs('input[data-value="name poly"]')) // Undo
|
||||
})
|
||||
it('should allow to control facet label', function () {
|
||||
this.map.options.facetKey = 'name|Nom'
|
||||
this.map.openFacet()
|
||||
it('should allow to control facet label', () => {
|
||||
map.options.facetKey = 'name|Nom'
|
||||
map.openFacet()
|
||||
assert.ok(qs('div.umap-facet-search h5'))
|
||||
assert.equal(qs('div.umap-facet-search h5').textContent, 'Nom')
|
||||
})
|
||||
})
|
||||
describe('#zoomEnd', function () {
|
||||
it('should honour the fromZoom option', function () {
|
||||
this.map.setZoom(6, { animate: false })
|
||||
describe('#zoomEnd', () => {
|
||||
it('should honour the fromZoom option', () => {
|
||||
map.setZoom(6, { animate: false })
|
||||
assert.ok(qs('path[fill="none"]'))
|
||||
this.datalayer.options.fromZoom = 6
|
||||
this.map.setZoom(5, { animate: false })
|
||||
datalayer.options.fromZoom = 6
|
||||
map.setZoom(5, { animate: false })
|
||||
assert.notOk(qs('path[fill="none"]'))
|
||||
this.map.setZoom(6, { animate: false })
|
||||
map.setZoom(6, { animate: false })
|
||||
assert.ok(qs('path[fill="none"]'))
|
||||
})
|
||||
|
||||
it('should honour the toZoom option', function () {
|
||||
this.map.setZoom(6, { animate: false })
|
||||
it('should honour the toZoom option', () => {
|
||||
map.setZoom(6, { animate: false })
|
||||
assert.ok(qs('path[fill="none"]'))
|
||||
this.datalayer.options.toZoom = 6
|
||||
this.map.setZoom(7, { animate: false })
|
||||
datalayer.options.toZoom = 6
|
||||
map.setZoom(7, { animate: false })
|
||||
assert.notOk(qs('path[fill="none"]'))
|
||||
this.map.setZoom(6, { animate: false })
|
||||
map.setZoom(6, { animate: false })
|
||||
assert.ok(qs('path[fill="none"]'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('#displayOnLoad', function () {
|
||||
beforeEach(function () {
|
||||
this.server.respondWith(
|
||||
/\/datalayer\/64\/\?.*/,
|
||||
JSON.stringify(RESPONSES.datalayer64_GET)
|
||||
)
|
||||
this.datalayer = this.map.createDataLayer(RESPONSES.datalayer64_GET._umap_options)
|
||||
// Force fetching the data, so to deal here with fake server
|
||||
this.datalayer.fetchData()
|
||||
this.server.respond()
|
||||
this.map.setZoom(10, { animate: false })
|
||||
describe('#displayOnLoad', () => {
|
||||
before(() => {
|
||||
fetchMock.get(/\/datalayer\/64\/\?.*/, RESPONSES.datalayer64_GET)
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
this.datalayer._delete()
|
||||
beforeEach(async () => {
|
||||
await map.initDataLayers([RESPONSES.datalayer64_GET._umap_options])
|
||||
datalayer = map.getDataLayerByUmapId(64)
|
||||
map.setZoom(10, { animate: false })
|
||||
})
|
||||
|
||||
it('should not display layer at load', function () {
|
||||
afterEach(() => {
|
||||
datalayer._delete()
|
||||
})
|
||||
|
||||
it('should not display layer at load', () => {
|
||||
assert.notOk(qs('path[fill="AliceBlue"]'))
|
||||
})
|
||||
|
||||
it('should display on click', function () {
|
||||
happen.click(qs(`[data-id='${L.stamp(this.datalayer)}'] .layer-toggle`))
|
||||
assert.ok(qs('path[fill="AliceBlue"]'))
|
||||
it('should display on click', (done) => {
|
||||
happen.click(qs(`[data-id='${L.stamp(datalayer)}'] .layer-toggle`))
|
||||
window.setTimeout(() => {
|
||||
assert.ok(qs('path[fill="AliceBlue"]'))
|
||||
done()
|
||||
}, 500)
|
||||
})
|
||||
|
||||
it('should not display on zoom', function () {
|
||||
this.map.setZoom(9, { animate: false })
|
||||
assert.notOk(qs('path[fill="AliceBlue"]'))
|
||||
it('should not display on zoom', (done) => {
|
||||
map.setZoom(9, { animate: false })
|
||||
window.setTimeout(() => {
|
||||
assert.notOk(qs('path[fill="AliceBlue"]'))
|
||||
done()
|
||||
}, 500)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#delete()', function () {
|
||||
var deleteLink,
|
||||
describe('#delete()', () => {
|
||||
let deleteLink,
|
||||
deletePath = '/map/99/datalayer/delete/62/'
|
||||
before(() => {
|
||||
datalayer = map.getDataLayerByUmapId(62)
|
||||
})
|
||||
|
||||
it('should have a delete link in update form', function () {
|
||||
it('should have a delete link in update form', () => {
|
||||
enableEdit()
|
||||
happen.click(
|
||||
qs('#browse_data_toggle_' + L.stamp(this.datalayer) + ' .layer-edit')
|
||||
)
|
||||
happen.click(qs('#browse_data_toggle_' + L.stamp(datalayer) + ' .layer-edit'))
|
||||
deleteLink = qs('button.delete_datalayer_button')
|
||||
assert.ok(deleteLink)
|
||||
})
|
||||
|
||||
it('should delete features on datalayer delete', function () {
|
||||
it('should delete features on datalayer delete', () => {
|
||||
happen.click(deleteLink)
|
||||
assert.notOk(qs('div.icon_container'))
|
||||
})
|
||||
|
||||
it('should have set map dirty', function () {
|
||||
assert.ok(this.map.isDirty)
|
||||
it('should have set map dirty', () => {
|
||||
assert.ok(map.isDirty)
|
||||
})
|
||||
|
||||
it('should delete layer control row on delete', function () {
|
||||
it('should delete layer control row on delete', () => {
|
||||
assert.notOk(
|
||||
qs('.leaflet-control-browse #browse_data_toggle_' + L.stamp(this.datalayer))
|
||||
qs('.leaflet-control-browse #browse_data_toggle_' + L.stamp(datalayer))
|
||||
)
|
||||
})
|
||||
|
||||
it('should be removed from map.datalayers_index', function () {
|
||||
assert.equal(this.map.datalayers_index.indexOf(this.datalayer), -1)
|
||||
it('should be removed from map.datalayers_index', () => {
|
||||
assert.equal(map.datalayers_index.indexOf(datalayer), -1)
|
||||
})
|
||||
|
||||
it('should be removed from map.datalayers', function () {
|
||||
assert.notOk(this.map.datalayers[L.stamp(this.datalayer)])
|
||||
it('should be removed from map.datalayers', () => {
|
||||
assert.notOk(map.datalayers[L.stamp(datalayer)])
|
||||
})
|
||||
|
||||
it('should be visible again on edit cancel', function () {
|
||||
it('should be visible again on edit cancel', () => {
|
||||
clickCancel()
|
||||
assert.ok(qs('div.icon_container'))
|
||||
})
|
||||
|
|
|
@ -1,21 +1,25 @@
|
|||
describe('L.U.FeatureMixin', function () {
|
||||
before(function () {
|
||||
this.server = sinon.fakeServer.create()
|
||||
this.server.respondWith(
|
||||
let map, datalayer
|
||||
before(async () => {
|
||||
await fetchMock.mock(
|
||||
/\/datalayer\/62\/\?.*/,
|
||||
JSON.stringify(RESPONSES.datalayer62_GET)
|
||||
)
|
||||
this.map = initMap({ umap_id: 99 })
|
||||
this.datalayer = this.map.getDataLayerByUmapId(62)
|
||||
this.server.respond()
|
||||
this.options = {
|
||||
umap_id: 99,
|
||||
}
|
||||
MAP = map = initMap({ umap_id: 99 })
|
||||
const datalayer_options = defaultDatalayerData()
|
||||
await map.initDataLayers([datalayer_options])
|
||||
datalayer = map.getDataLayerByUmapId(62)
|
||||
})
|
||||
after(function () {
|
||||
this.server.restore()
|
||||
fetchMock.restore()
|
||||
resetMap()
|
||||
})
|
||||
|
||||
describe('#edit()', function () {
|
||||
var link
|
||||
let link
|
||||
|
||||
it('should have datalayer features created', function () {
|
||||
assert.equal(
|
||||
|
@ -45,7 +49,7 @@ describe('L.U.FeatureMixin', function () {
|
|||
|
||||
it('should take into account styles changes made in the datalayer', function () {
|
||||
happen.click(
|
||||
qs('#browse_data_toggle_' + L.stamp(this.datalayer) + ' .layer-edit')
|
||||
qs('#browse_data_toggle_' + L.stamp(datalayer) + ' .layer-edit')
|
||||
)
|
||||
var colorInput = qs('form#datalayer-advanced-properties input[name=color]')
|
||||
changeInputValue(colorInput, 'DarkRed')
|
||||
|
@ -101,7 +105,7 @@ describe('L.U.FeatureMixin', function () {
|
|||
|
||||
it('should not override already set style on features', function () {
|
||||
happen.click(
|
||||
qs('#browse_data_toggle_' + L.stamp(this.datalayer) + ' .layer-edit')
|
||||
qs('#browse_data_toggle_' + L.stamp(datalayer) + ' .layer-edit')
|
||||
)
|
||||
changeInputValue(qs('#umap-ui-container form input[name=color]'), 'Chocolate')
|
||||
assert.notOk(qs('path[fill="DarkBlue"]'))
|
||||
|
@ -120,22 +124,22 @@ describe('L.U.FeatureMixin', function () {
|
|||
|
||||
it('should set map.editedFeature on edit', function () {
|
||||
enableEdit()
|
||||
assert.notOk(this.map.editedFeature)
|
||||
assert.notOk(map.editedFeature)
|
||||
happen.click(qs('path[fill="DarkBlue"]'))
|
||||
happen.click(qs('ul.leaflet-inplace-toolbar a.umap-toggle-edit'))
|
||||
assert.ok(this.map.editedFeature)
|
||||
assert.ok(map.editedFeature)
|
||||
disableEdit()
|
||||
})
|
||||
|
||||
it('should reset map.editedFeature on panel open', function (done) {
|
||||
enableEdit()
|
||||
assert.notOk(this.map.editedFeature)
|
||||
assert.notOk(map.editedFeature)
|
||||
happen.click(qs('path[fill="DarkBlue"]'))
|
||||
happen.click(qs('ul.leaflet-inplace-toolbar a.umap-toggle-edit'))
|
||||
assert.ok(this.map.editedFeature)
|
||||
this.map.displayCaption()
|
||||
assert.ok(map.editedFeature)
|
||||
map.displayCaption()
|
||||
window.setTimeout(function () {
|
||||
assert.notOk(this.map.editedFeature)
|
||||
assert.notOk(map.editedFeature)
|
||||
disableEdit()
|
||||
done()
|
||||
}, 1001) // CSS transition time.
|
||||
|
@ -155,7 +159,7 @@ describe('L.U.FeatureMixin', function () {
|
|||
})
|
||||
}
|
||||
it('should generate a valid geojson', function () {
|
||||
setFeatures(this.datalayer)
|
||||
setFeatures(datalayer)
|
||||
assert.ok(poly)
|
||||
assert.deepEqual(poly.toGeoJSON().geometry, {
|
||||
type: 'Polygon',
|
||||
|
@ -176,7 +180,7 @@ describe('L.U.FeatureMixin', function () {
|
|||
})
|
||||
|
||||
it('should remove empty _umap_options from exported geojson', function () {
|
||||
setFeatures(this.datalayer)
|
||||
setFeatures(datalayer)
|
||||
assert.ok(poly)
|
||||
assert.deepEqual(poly.toGeoJSON().properties, { name: 'name poly' })
|
||||
assert.ok(marker)
|
||||
|
@ -190,7 +194,7 @@ describe('L.U.FeatureMixin', function () {
|
|||
describe('#openPopup()', function () {
|
||||
let poly
|
||||
before(function () {
|
||||
this.datalayer.eachLayer(function (layer) {
|
||||
datalayer.eachLayer(function (layer) {
|
||||
if (!poly && layer instanceof L.Polygon) {
|
||||
poly = layer
|
||||
}
|
||||
|
@ -233,8 +237,8 @@ describe('L.U.FeatureMixin', function () {
|
|||
})
|
||||
|
||||
it('should still highlight marker after hide() and show()', function () {
|
||||
this.datalayer.hide()
|
||||
this.datalayer.show()
|
||||
datalayer.hide()
|
||||
datalayer.show()
|
||||
happen.click(qs('div.leaflet-marker-icon'))
|
||||
assert.ok(qs('.umap-icon-active'))
|
||||
})
|
||||
|
@ -254,9 +258,9 @@ describe('L.U.FeatureMixin', function () {
|
|||
|
||||
describe('#tooltip', function () {
|
||||
it('should have a tooltip when active and allow variables', function () {
|
||||
this.map.options.showLabel = true
|
||||
this.map.options.labelKey = 'Foo {name}'
|
||||
this.datalayer.redraw()
|
||||
map.options.showLabel = true
|
||||
map.options.labelKey = 'Foo {name}'
|
||||
datalayer.redraw()
|
||||
assert.equal(
|
||||
qs('.leaflet-tooltip-pane .leaflet-tooltip').textContent,
|
||||
'Foo name poly'
|
||||
|
@ -266,7 +270,7 @@ describe('L.U.FeatureMixin', function () {
|
|||
|
||||
describe('#properties()', function () {
|
||||
it('should rename property', function () {
|
||||
var poly = this.datalayer._lineToLayer({}, [
|
||||
var poly = datalayer._lineToLayer({}, [
|
||||
[0, 0],
|
||||
[0, 1],
|
||||
[0, 2],
|
||||
|
@ -278,7 +282,7 @@ describe('L.U.FeatureMixin', function () {
|
|||
})
|
||||
|
||||
it('should not create property when renaming', function () {
|
||||
var poly = this.datalayer._lineToLayer({}, [
|
||||
var poly = datalayer._lineToLayer({}, [
|
||||
[0, 0],
|
||||
[0, 1],
|
||||
[0, 2],
|
||||
|
@ -289,7 +293,7 @@ describe('L.U.FeatureMixin', function () {
|
|||
})
|
||||
|
||||
it('should delete property', function () {
|
||||
var poly = this.datalayer._lineToLayer({}, [
|
||||
var poly = datalayer._lineToLayer({}, [
|
||||
[0, 0],
|
||||
[0, 1],
|
||||
[0, 2],
|
||||
|
@ -305,7 +309,7 @@ describe('L.U.FeatureMixin', function () {
|
|||
var poly
|
||||
|
||||
it('should filter on properties', function () {
|
||||
poly = this.datalayer._lineToLayer({}, [
|
||||
poly = datalayer._lineToLayer({}, [
|
||||
[0, 0],
|
||||
[0, 1],
|
||||
[0, 2],
|
||||
|
@ -329,35 +333,6 @@ describe('L.U.FeatureMixin', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('#quick-delete()', function () {
|
||||
let poly, _confirm
|
||||
before(function () {
|
||||
_confirm = window.confirm
|
||||
window.confirm = function (text) {
|
||||
return true
|
||||
}
|
||||
|
||||
this.datalayer.eachLayer(function (layer) {
|
||||
if (!poly && layer instanceof L.Polygon) {
|
||||
poly = layer
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
after(function () {
|
||||
window.confirm = _confirm
|
||||
})
|
||||
|
||||
it('should allow to delete from data browser', function () {
|
||||
enableEdit()
|
||||
assert.ok(qs('path[fill="DarkBlue"]'))
|
||||
this.map.openBrowser()
|
||||
happen.click(qs('.feature-delete'))
|
||||
assert.notOk(qs('path[fill="DarkBlue"]'))
|
||||
clickCancel()
|
||||
})
|
||||
})
|
||||
|
||||
describe('#changeDataLayer()', function () {
|
||||
it('should change style on datalayer select change', function () {
|
||||
enableEdit()
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
describe('L.U.Map.Export', function () {
|
||||
before(function () {
|
||||
this.server = sinon.fakeServer.create()
|
||||
this.server.respondWith(
|
||||
let map
|
||||
before(async () => {
|
||||
await fetchMock.mock(
|
||||
/\/datalayer\/62\/\?.*/,
|
||||
JSON.stringify(RESPONSES.datalayer62_GET)
|
||||
)
|
||||
this.options = {
|
||||
umap_id: 99,
|
||||
}
|
||||
this.map = initMap({ umap_id: 99 })
|
||||
this.server.respond()
|
||||
this.datalayer = this.map.getDataLayerByUmapId(62)
|
||||
map = initMap({ umap_id: 99 })
|
||||
const datalayer_options = defaultDatalayerData()
|
||||
await map.initDataLayers([datalayer_options])
|
||||
})
|
||||
after(function () {
|
||||
this.server.restore()
|
||||
fetchMock.restore()
|
||||
clickCancel()
|
||||
resetMap()
|
||||
})
|
||||
|
||||
describe('#formatters()', function () {
|
||||
it('should export to geojson', function () {
|
||||
const { content, filetype, filename } = this.map.share.format('geojson')
|
||||
const { content, filetype, filename } = map.share.format('geojson')
|
||||
assert.equal(filetype, 'application/json')
|
||||
assert.equal(filename, 'name_of_the_map.geojson')
|
||||
assert.deepEqual(JSON.parse(content), {
|
||||
|
@ -86,7 +86,7 @@ describe('L.U.Map.Export', function () {
|
|||
})
|
||||
|
||||
it('should export to gpx', function () {
|
||||
const { content, filetype, filename } = this.map.share.format('gpx')
|
||||
const { content, filetype, filename } = map.share.format('gpx')
|
||||
assert.equal(filetype, 'application/gpx+xml')
|
||||
assert.equal(filename, 'name_of_the_map.gpx')
|
||||
const expected =
|
||||
|
@ -95,7 +95,7 @@ describe('L.U.Map.Export', function () {
|
|||
})
|
||||
|
||||
it('should export to kml', function () {
|
||||
const { content, filetype, filename } = this.map.share.format('kml')
|
||||
const { content, filetype, filename } = map.share.format('kml')
|
||||
assert.equal(filetype, 'application/vnd.google-earth.kml+xml')
|
||||
assert.equal(filename, 'name_of_the_map.kml')
|
||||
const expected =
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
describe('L.U.Map.initialize', function () {
|
||||
afterEach(function () {
|
||||
resetMap()
|
||||
})
|
||||
|
||||
describe('Controls', function () {
|
||||
it('should not show a minimap by default', function () {
|
||||
this.map = initMap()
|
||||
assert.notOk(qs('.leaflet-control-minimap'))
|
||||
})
|
||||
|
||||
it('should show a minimap', function () {
|
||||
this.map = initMap({ miniMap: true })
|
||||
assert.ok(qs('.leaflet-control-minimap'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('DefaultView', function () {
|
||||
it('should set default view in default mode without data', function (done) {
|
||||
this.map = initMap({ datalayers: [] })
|
||||
// Did not find a better way to wait for tiles to be actually loaded
|
||||
window.setTimeout(() => {
|
||||
assert.ok(qs('#map .leaflet-tile-pane img.leaflet-tile.leaflet-tile-loaded'))
|
||||
done()
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
it("should set default view in 'data' mode without data", function (done) {
|
||||
this.map = initMap({ datalayers: [], defaultView: 'data' })
|
||||
// Did not find a better way to wait for tiles to be actually loaded
|
||||
window.setTimeout(() => {
|
||||
assert.ok(qs('#map .leaflet-tile-pane img.leaflet-tile.leaflet-tile-loaded'))
|
||||
done()
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
it("should set default view in 'latest' mode without data", function (done) {
|
||||
this.map = initMap({ datalayers: [], defaultView: 'latest' })
|
||||
// Did not find a better way to wait for tiles to be actually loaded
|
||||
window.setTimeout(() => {
|
||||
assert.ok(qs('#map .leaflet-tile-pane img.leaflet-tile.leaflet-tile-loaded'))
|
||||
done()
|
||||
}, 1000)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,26 +1,27 @@
|
|||
describe('L.U.Map', function () {
|
||||
before(function () {
|
||||
this.server = sinon.fakeServer.create()
|
||||
this.server.respondWith(
|
||||
describe('L.U.Map', () => {
|
||||
let map, datalayer
|
||||
before(async () => {
|
||||
await fetchMock.mock(
|
||||
/\/datalayer\/62\/\?.*/,
|
||||
JSON.stringify(RESPONSES.datalayer62_GET)
|
||||
)
|
||||
this.options = {
|
||||
umap_id: 99,
|
||||
}
|
||||
this.map = initMap({ umap_id: 99 })
|
||||
this.server.respond()
|
||||
this.datalayer = this.map.getDataLayerByUmapId(62)
|
||||
map = initMap({ umap_id: 99 })
|
||||
const datalayer_options = defaultDatalayerData()
|
||||
await map.initDataLayers([datalayer_options])
|
||||
datalayer = map.getDataLayerByUmapId(62)
|
||||
})
|
||||
after(function () {
|
||||
this.server.restore()
|
||||
after(() => {
|
||||
fetchMock.restore()
|
||||
clickCancel()
|
||||
resetMap()
|
||||
})
|
||||
|
||||
describe('#init()', function () {
|
||||
describe('#init()', () => {
|
||||
it('should be initialized', function () {
|
||||
assert.equal(this.map.options.umap_id, 99)
|
||||
assert.equal(map.options.umap_id, 99)
|
||||
})
|
||||
|
||||
it('should have created the edit button', function () {
|
||||
|
@ -42,7 +43,7 @@ describe('L.U.Map', function () {
|
|||
it('should hide icon container div when hiding datalayer', function () {
|
||||
var el = qs(
|
||||
'.leaflet-control-browse #browse_data_toggle_' +
|
||||
L.stamp(this.datalayer) +
|
||||
L.stamp(datalayer) +
|
||||
' .layer-toggle'
|
||||
)
|
||||
happen.click(el)
|
||||
|
@ -56,7 +57,7 @@ describe('L.U.Map', function () {
|
|||
})
|
||||
|
||||
it('should have only one datalayer in its index', function () {
|
||||
assert.equal(this.map.datalayers_index.length, 1)
|
||||
assert.equal(map.datalayers_index.length, 1)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -78,20 +79,20 @@ describe('L.U.Map', function () {
|
|||
var new_name = 'This is a new name'
|
||||
input.value = new_name
|
||||
happen.once(input, { type: 'input' })
|
||||
assert.equal(this.map.options.name, new_name)
|
||||
assert.equal(map.options.name, new_name)
|
||||
})
|
||||
|
||||
it('should have made Map dirty', function () {
|
||||
assert.ok(this.map.isDirty)
|
||||
assert.ok(map.isDirty)
|
||||
})
|
||||
|
||||
it('should have added dirty class on map container', function () {
|
||||
assert.ok(L.DomUtil.hasClass(this.map._container, 'umap-is-dirty'))
|
||||
assert.ok(L.DomUtil.hasClass(map._container, 'umap-is-dirty'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('#delete()', function () {
|
||||
var path = '/map/99/delete/',
|
||||
let path = '/map/99/update/delete/',
|
||||
oldConfirm,
|
||||
newConfirm = function () {
|
||||
return true
|
||||
|
@ -105,24 +106,22 @@ describe('L.U.Map', function () {
|
|||
window.confirm = oldConfirm
|
||||
})
|
||||
|
||||
it('should ask for confirmation on delete link click', function () {
|
||||
var button = qs('a.update-map-settings')
|
||||
it('should ask for confirmation on delete link click', async function () {
|
||||
let button = qs('a.update-map-settings')
|
||||
assert.ok(button, 'update map info button exists')
|
||||
happen.click(button)
|
||||
var deleteLink = qs('button.umap-delete')
|
||||
let deleteLink = qs('button.umap-delete')
|
||||
assert.ok(deleteLink, 'delete map button exists')
|
||||
sinon.spy(window, 'confirm')
|
||||
this.server.respondWith('POST', path, JSON.stringify({ redirect: '#' }))
|
||||
await fetchMock.post(path, { redirect: '#' })
|
||||
happen.click(deleteLink)
|
||||
this.server.respond()
|
||||
assert(window.confirm.calledOnce)
|
||||
window.confirm.restore()
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
describe('#importData()', function () {
|
||||
var fileInput, textarea, submit, formatSelect, layerSelect, clearFlag
|
||||
let fileInput, textarea, submit, formatSelect, layerSelect, clearFlag
|
||||
|
||||
it('should build a form on click', function () {
|
||||
happen.click(qs('a.upload-data'))
|
||||
|
@ -139,82 +138,82 @@ describe('L.U.Map', function () {
|
|||
})
|
||||
|
||||
it('should import geojson from textarea', function () {
|
||||
this.datalayer.empty()
|
||||
assert.equal(this.datalayer._index.length, 0)
|
||||
datalayer.empty()
|
||||
assert.equal(datalayer._index.length, 0)
|
||||
textarea.value =
|
||||
'{"type": "FeatureCollection", "features": [{"geometry": {"type": "Point", "coordinates": [6.922931671142578, 47.481161607175736]}, "type": "Feature", "properties": {"color": "", "name": "Chez R\u00e9my", "description": ""}}, {"geometry": {"type": "LineString", "coordinates": [[2.4609375, 48.88639177703194], [2.48291015625, 48.76343113791796], [2.164306640625, 48.719961222646276]]}, "type": "Feature", "properties": {"color": "", "name": "P\u00e9rif", "description": ""}}]}'
|
||||
changeSelectValue(formatSelect, 'geojson')
|
||||
happen.click(submit)
|
||||
assert.equal(this.datalayer._index.length, 2)
|
||||
assert.equal(datalayer._index.length, 2)
|
||||
})
|
||||
|
||||
it('should remove dot in property name', function () {
|
||||
this.datalayer.empty()
|
||||
assert.equal(this.datalayer._index.length, 0)
|
||||
datalayer.empty()
|
||||
assert.equal(datalayer._index.length, 0)
|
||||
textarea.value =
|
||||
'{"type": "FeatureCollection", "features": [{"geometry": {"type": "Point", "coordinates": [6.922931671142578, 47.481161607175736]}, "type": "Feature", "properties": {"color": "", "name": "Chez R\u00e9my", "A . in the name": ""}}, {"geometry": {"type": "LineString", "coordinates": [[2.4609375, 48.88639177703194], [2.48291015625, 48.76343113791796], [2.164306640625, 48.719961222646276]]}, "type": "Feature", "properties": {"color": "", "name": "P\u00e9rif", "with a dot.": ""}}]}'
|
||||
changeSelectValue(formatSelect, 'geojson')
|
||||
happen.click(submit)
|
||||
assert.equal(this.datalayer._index.length, 2)
|
||||
assert.ok(this.datalayer._propertiesIndex.includes('A _ in the name'))
|
||||
assert.ok(this.datalayer._propertiesIndex.includes('with a dot_'))
|
||||
assert.equal(datalayer._index.length, 2)
|
||||
assert.ok(datalayer._propertiesIndex.includes('A _ in the name'))
|
||||
assert.ok(datalayer._propertiesIndex.includes('with a dot_'))
|
||||
})
|
||||
|
||||
it('should import osm from textarea', function () {
|
||||
this.datalayer.empty()
|
||||
datalayer.empty()
|
||||
happen.click(qs('a.upload-data'))
|
||||
textarea = qs('.umap-upload textarea')
|
||||
submit = qs('.umap-upload input[type="button"]')
|
||||
formatSelect = qs('.umap-upload select[name="format"]')
|
||||
assert.equal(this.datalayer._index.length, 0)
|
||||
assert.equal(datalayer._index.length, 0)
|
||||
textarea.value =
|
||||
'{"version": 0.6,"generator": "Overpass API 0.7.55.4 3079d8ea","osm3s": {"timestamp_osm_base": "2018-09-22T05:26:02Z","copyright": "The data included in this document is from www.openstreetmap.org. The data is made available under ODbL."},"elements": [{"type": "node","id": 3619112991,"lat": 48.9352995,"lon": 2.3570684,"tags": {"information": "map","map_size": "city","map_type": "scheme","tourism": "information"}},{"type": "node","id": 3682500756,"lat": 48.9804426,"lon": 2.2719725,"tags": {"information": "map","level": "0","tourism": "information"}}]}'
|
||||
changeSelectValue(formatSelect, 'osm')
|
||||
happen.click(submit)
|
||||
assert.equal(this.datalayer._index.length, 2)
|
||||
assert.equal(datalayer._index.length, 2)
|
||||
assert.equal(
|
||||
this.datalayer._layers[this.datalayer._index[0]].properties.tourism,
|
||||
datalayer._layers[datalayer._index[0]].properties.tourism,
|
||||
'information'
|
||||
)
|
||||
})
|
||||
|
||||
it('should import kml from textarea', function () {
|
||||
this.datalayer.empty()
|
||||
datalayer.empty()
|
||||
happen.click(qs('a.upload-data'))
|
||||
textarea = qs('.umap-upload textarea')
|
||||
submit = qs('.umap-upload input[type="button"]')
|
||||
formatSelect = qs('.umap-upload select[name="format"]')
|
||||
assert.equal(this.datalayer._index.length, 0)
|
||||
assert.equal(datalayer._index.length, 0)
|
||||
textarea.value = kml_example
|
||||
changeSelectValue(formatSelect, 'kml')
|
||||
happen.click(submit)
|
||||
assert.equal(this.datalayer._index.length, 3)
|
||||
assert.equal(datalayer._index.length, 3)
|
||||
})
|
||||
|
||||
it('should import gpx from textarea', function () {
|
||||
this.datalayer.empty()
|
||||
datalayer.empty()
|
||||
happen.click(qs('a.upload-data'))
|
||||
textarea = qs('.umap-upload textarea')
|
||||
submit = qs('.umap-upload input[type="button"]')
|
||||
formatSelect = qs('.umap-upload select[name="format"]')
|
||||
assert.equal(this.datalayer._index.length, 0)
|
||||
assert.equal(datalayer._index.length, 0)
|
||||
textarea.value = gpx_example
|
||||
changeSelectValue(formatSelect, 'gpx')
|
||||
happen.click(submit)
|
||||
assert.equal(this.datalayer._index.length, 2)
|
||||
assert.equal(datalayer._index.length, 2)
|
||||
})
|
||||
|
||||
it('should import csv from textarea', function () {
|
||||
this.datalayer.empty()
|
||||
datalayer.empty()
|
||||
happen.click(qs('a.upload-data'))
|
||||
textarea = qs('.umap-upload textarea')
|
||||
submit = qs('.umap-upload input[type="button"]')
|
||||
formatSelect = qs('.umap-upload select[name="format"]')
|
||||
assert.equal(this.datalayer._index.length, 0)
|
||||
assert.equal(datalayer._index.length, 0)
|
||||
textarea.value = csv_example
|
||||
changeSelectValue(formatSelect, 'csv')
|
||||
happen.click(submit)
|
||||
assert.equal(this.datalayer._index.length, 1)
|
||||
assert.equal(datalayer._index.length, 1)
|
||||
})
|
||||
|
||||
it('should replace content if asked so', function () {
|
||||
|
@ -224,52 +223,52 @@ describe('L.U.Map', function () {
|
|||
formatSelect = qs('.umap-upload select[name="format"]')
|
||||
clearFlag = qs('.umap-upload input[name="clear"]')
|
||||
clearFlag.checked = true
|
||||
assert.equal(this.datalayer._index.length, 1)
|
||||
assert.equal(datalayer._index.length, 1)
|
||||
textarea.value = csv_example
|
||||
changeSelectValue(formatSelect, 'csv')
|
||||
happen.click(submit)
|
||||
assert.equal(this.datalayer._index.length, 1)
|
||||
assert.equal(datalayer._index.length, 1)
|
||||
})
|
||||
|
||||
it('should import GeometryCollection from textarea', function () {
|
||||
this.datalayer.empty()
|
||||
datalayer.empty()
|
||||
textarea.value =
|
||||
'{"type": "GeometryCollection","geometries": [{"type": "Point","coordinates": [-80.66080570220947,35.04939206472683]},{"type": "Polygon","coordinates": [[[-80.66458225250244,35.04496519190309],[-80.66344499588013,35.04603679820616],[-80.66258668899536,35.045580049697556],[-80.66387414932251,35.044280059194946],[-80.66458225250244,35.04496519190309]]]},{"type": "LineString","coordinates": [[-80.66237211227417,35.05950973022538],[-80.66269397735596,35.0592638296087],[-80.66284418106079,35.05893010615862],[-80.66308021545409,35.05833291342246],[-80.66359519958496,35.057753281001425],[-80.66387414932251,35.05740198662245],[-80.66441059112549,35.05703312589789],[-80.66486120223999,35.056787217822475],[-80.66541910171509,35.05650617911516],[-80.66563367843628,35.05631296444281],[-80.66601991653441,35.055891403570705],[-80.66619157791138,35.05545227534804],[-80.66619157791138,35.05517123204622],[-80.66625595092773,35.05489018777713],[-80.6662130355835,35.054222703761525],[-80.6662130355835,35.05392409072499],[-80.66595554351807,35.05290528508858],[-80.66569805145262,35.052044560077285],[-80.66550493240356,35.0514824490509],[-80.665762424469,35.05048117920187],[-80.66617012023926,35.04972582715769],[-80.66651344299316,35.049286665781096],[-80.66692113876343,35.0485313026898],[-80.66700696945189,35.048215102112344],[-80.66707134246826,35.04777593261294],[-80.66704988479614,35.04738946150025],[-80.66696405410767,35.04698542156371],[-80.66681385040283,35.046353007216055],[-80.66659927368164,35.04596652937105],[-80.66640615463257,35.04561518428889],[-80.6659984588623,35.045193568195565],[-80.66552639007568,35.044877354697526],[-80.6649899482727,35.04454357245502],[-80.66449642181396,35.04417465365292],[-80.66385269165039,35.04387600387859],[-80.66303730010986,35.043717894732545]]}]}'
|
||||
formatSelect = qs('.umap-upload select[name="format"]')
|
||||
changeSelectValue(formatSelect, 'geojson')
|
||||
happen.click(submit)
|
||||
assert.equal(this.datalayer._index.length, 3)
|
||||
assert.equal(datalayer._index.length, 3)
|
||||
})
|
||||
|
||||
it('should import multipolygon', function () {
|
||||
this.datalayer.empty()
|
||||
datalayer.empty()
|
||||
textarea.value =
|
||||
'{"type": "Feature", "properties": { "name": "Some states" }, "geometry": { "type": "MultiPolygon", "coordinates": [[[[-109, 36], [-109, 40], [-102, 37], [-109, 36]], [[-108, 39], [-107, 37], [-104, 37], [-108, 39]]], [[[-119, 42], [-120, 39], [-114, 41], [-119, 42]]]] }}'
|
||||
changeSelectValue(formatSelect, 'geojson')
|
||||
happen.click(submit)
|
||||
assert.equal(this.datalayer._index.length, 1)
|
||||
var layer = this.datalayer.getFeatureByIndex(0)
|
||||
assert.equal(datalayer._index.length, 1)
|
||||
var layer = datalayer.getFeatureByIndex(0)
|
||||
assert.equal(layer._latlngs.length, 2) // Two shapes.
|
||||
assert.equal(layer._latlngs[0].length, 2) // Hole.
|
||||
})
|
||||
|
||||
it('should import multipolyline', function () {
|
||||
this.datalayer.empty()
|
||||
datalayer.empty()
|
||||
textarea.value =
|
||||
'{"type": "FeatureCollection", "features": [{ "type": "Feature", "properties": {}, "geometry": { "type": "MultiLineString", "coordinates": [[[-108, 46], [-113, 43]], [[-112, 45], [-115, 44]]] } }]}'
|
||||
changeSelectValue(formatSelect, 'geojson')
|
||||
happen.click(submit)
|
||||
assert.equal(this.datalayer._index.length, 1)
|
||||
var layer = this.datalayer.getFeatureByIndex(0)
|
||||
assert.equal(datalayer._index.length, 1)
|
||||
var layer = datalayer.getFeatureByIndex(0)
|
||||
assert.equal(layer._latlngs.length, 2) // Two shapes.
|
||||
})
|
||||
|
||||
it('should import raw umap data from textarea', function () {
|
||||
//Right now, the import function will try to save and reload. Stop this from happening.
|
||||
var disabledSaveFunction = this.map.save
|
||||
this.map.save = function () {}
|
||||
var disabledSaveFunction = map.save
|
||||
map.save = function () {}
|
||||
happen.click(qs('a.upload-data'))
|
||||
var initialLayerCount = Object.keys(this.map.datalayers).length
|
||||
var initialLayerCount = Object.keys(map.datalayers).length
|
||||
formatSelect = qs('.umap-upload select[name="format"]')
|
||||
textarea = qs('.umap-upload textarea')
|
||||
textarea.value =
|
||||
|
@ -277,12 +276,12 @@ describe('L.U.Map', function () {
|
|||
formatSelect.value = 'umap'
|
||||
submit = qs('.umap-upload input[type="button"]')
|
||||
happen.click(submit)
|
||||
assert.equal(Object.keys(this.map.datalayers).length, initialLayerCount + 2)
|
||||
assert.equal(this.map.options.name, 'Imported map')
|
||||
assert.equal(Object.keys(map.datalayers).length, initialLayerCount + 2)
|
||||
assert.equal(map.options.name, 'Imported map')
|
||||
var foundFirstLayer = false
|
||||
var foundSecondLayer = false
|
||||
for (var idx in this.map.datalayers) {
|
||||
var datalayer = this.map.datalayers[idx]
|
||||
for (var idx in map.datalayers) {
|
||||
var datalayer = map.datalayers[idx]
|
||||
if (datalayer.options.name === 'Cities') {
|
||||
foundFirstLayer = true
|
||||
assert.equal(datalayer._index.length, 2)
|
||||
|
@ -297,7 +296,7 @@ describe('L.U.Map', function () {
|
|||
})
|
||||
|
||||
it('should only import options on the whitelist (umap format import)', function () {
|
||||
assert.equal(this.map.options.umap_id, 99)
|
||||
assert.equal(map.options.umap_id, 99)
|
||||
})
|
||||
|
||||
it('should update title bar (umap format import)', function () {
|
||||
|
@ -318,7 +317,7 @@ describe('L.U.Map', function () {
|
|||
|
||||
it('should set the tilelayer (umap format import)', function () {
|
||||
assert.equal(
|
||||
this.map.selected_tilelayer._url,
|
||||
map.selected_tilelayer._url,
|
||||
'http://{s}.tile.stamen.com/watercolor/{z}/{x}/{y}.jpg'
|
||||
)
|
||||
})
|
||||
|
@ -327,14 +326,14 @@ describe('L.U.Map', function () {
|
|||
describe('#localizeUrl()', function () {
|
||||
it('should replace known variables', function () {
|
||||
assert.equal(
|
||||
this.map.localizeUrl('http://example.org/{zoom}'),
|
||||
'http://example.org/' + this.map.getZoom()
|
||||
map.localizeUrl('http://example.org/{zoom}'),
|
||||
'http://example.org/' + map.getZoom()
|
||||
)
|
||||
})
|
||||
|
||||
it('should keep unknown variables', function () {
|
||||
assert.equal(
|
||||
this.map.localizeUrl('http://example.org/{unkown}'),
|
||||
map.localizeUrl('http://example.org/{unkown}'),
|
||||
'http://example.org/{unkown}'
|
||||
)
|
||||
})
|
||||
|
|
|
@ -1,20 +1,24 @@
|
|||
describe('L.U.Marker', function () {
|
||||
before(function () {
|
||||
this.server = sinon.fakeServer.create()
|
||||
var datalayer_response = JSON.parse(JSON.stringify(RESPONSES.datalayer62_GET)) // Copy.
|
||||
describe('L.U.Marker', () => {
|
||||
let map, datalayer
|
||||
before(async () => {
|
||||
const datalayer_response = JSON.parse(JSON.stringify(RESPONSES.datalayer62_GET)) // Copy.
|
||||
datalayer_response._umap_options.iconClass = 'Drop'
|
||||
this.server.respondWith(/\/datalayer\/62\/\?.*/, JSON.stringify(datalayer_response))
|
||||
this.map = initMap({ umap_id: 99 })
|
||||
this.datalayer = this.map.getDataLayerByUmapId(62)
|
||||
this.server.respond()
|
||||
await fetchMock.mock(/\/datalayer\/62\/\?.*/, datalayer_response)
|
||||
this.options = {
|
||||
umap_id: 99,
|
||||
}
|
||||
MAP = map = initMap({ umap_id: 99 })
|
||||
const datalayer_options = defaultDatalayerData()
|
||||
await map.initDataLayers([datalayer_options])
|
||||
datalayer = map.getDataLayerByUmapId(62)
|
||||
})
|
||||
after(function () {
|
||||
this.server.restore()
|
||||
after(() => {
|
||||
fetchMock.restore()
|
||||
resetMap()
|
||||
})
|
||||
|
||||
describe('#iconClassChange()', function () {
|
||||
it('should change icon class', function () {
|
||||
describe('#iconClassChange()', () => {
|
||||
it('should change icon class', () => {
|
||||
enableEdit()
|
||||
happen.click(qs('div.umap-drop-icon'))
|
||||
happen.click(qs('ul.leaflet-inplace-toolbar a.umap-toggle-edit'))
|
||||
|
@ -35,8 +39,8 @@ describe('L.U.Marker', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('#iconSymbolChange()', function () {
|
||||
it('should change icon symbol', function () {
|
||||
describe('#iconSymbolChange()', () => {
|
||||
it('should change icon symbol', () => {
|
||||
enableEdit()
|
||||
happen.click(qs('div.umap-drop-icon'))
|
||||
happen.click(qs('ul.leaflet-inplace-toolbar a.umap-toggle-edit'))
|
||||
|
@ -58,8 +62,8 @@ describe('L.U.Marker', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('#iconClassChange()', function () {
|
||||
it('should change icon class', function () {
|
||||
describe('#iconClassChange()', () => {
|
||||
it('should change icon class', () => {
|
||||
enableEdit()
|
||||
happen.click(qs('div.umap-drop-icon'))
|
||||
happen.click(qs('ul.leaflet-inplace-toolbar a.umap-toggle-edit'))
|
||||
|
@ -80,15 +84,15 @@ describe('L.U.Marker', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('#clone', function () {
|
||||
it('should clone marker', function () {
|
||||
var layer = new L.U.Marker(this.map, [10, 20], {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
assert.equal(this.datalayer._index.length, 4)
|
||||
describe('#clone', () => {
|
||||
it('should clone marker', () => {
|
||||
var layer = new L.U.Marker(map, [10, 20], {
|
||||
datalayer: datalayer,
|
||||
}).addTo(datalayer)
|
||||
assert.equal(datalayer._index.length, 4)
|
||||
other = layer.clone()
|
||||
assert.ok(this.map.hasLayer(other))
|
||||
assert.equal(this.datalayer._index.length, 5)
|
||||
assert.ok(map.hasLayer(other))
|
||||
assert.equal(datalayer._index.length, 5)
|
||||
// Must not be the same reference
|
||||
assert.notEqual(layer._latlng, other._latlng)
|
||||
assert.equal(L.Util.formatNum(layer._latlng.lat), other._latlng.lat)
|
||||
|
@ -97,20 +101,20 @@ describe('L.U.Marker', function () {
|
|||
})
|
||||
|
||||
describe('#edit()', function (done) {
|
||||
it('should allow changing coordinates manually', function () {
|
||||
var layer = new L.U.Marker(this.map, [10, 20], {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
it('should allow changing coordinates manually', () => {
|
||||
var layer = new L.U.Marker(map, [10, 20], {
|
||||
datalayer: datalayer,
|
||||
}).addTo(datalayer)
|
||||
enableEdit()
|
||||
layer.edit()
|
||||
changeInputValue(qs('form.umap-form input[name="lat"]'), '54.43')
|
||||
assert.equal(layer._latlng.lat, 54.43)
|
||||
})
|
||||
|
||||
it('should not allow invalid latitude nor longitude', function () {
|
||||
var layer = new L.U.Marker(this.map, [10, 20], {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
it('should not allow invalid latitude nor longitude', () => {
|
||||
var layer = new L.U.Marker(map, [10, 20], {
|
||||
datalayer: datalayer,
|
||||
}).addTo(datalayer)
|
||||
enableEdit()
|
||||
layer.edit()
|
||||
changeInputValue(qs('form.umap-form input[name="lat"]'), '5443')
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
describe('L.U.Polygon', function () {
|
||||
var p2ll, map
|
||||
var p2ll, map, datalayer
|
||||
|
||||
before(function () {
|
||||
this.map = map = initMap({ umap_id: 99 })
|
||||
map = initMap({ umap_id: 99 })
|
||||
enableEdit()
|
||||
p2ll = function (x, y) {
|
||||
return map.containerPointToLatLng([x, y])
|
||||
}
|
||||
this.datalayer = this.map.createDataLayer()
|
||||
this.datalayer.connectToMap()
|
||||
datalayer = map.createDataLayer()
|
||||
datalayer.connectToMap()
|
||||
})
|
||||
|
||||
after(function () {
|
||||
|
@ -17,32 +17,32 @@ describe('L.U.Polygon', function () {
|
|||
})
|
||||
|
||||
afterEach(function () {
|
||||
this.datalayer.empty()
|
||||
datalayer.empty()
|
||||
})
|
||||
|
||||
describe('#isMulti()', function () {
|
||||
it('should return false for basic Polygon', function () {
|
||||
var layer = new L.U.Polygon(
|
||||
this.map,
|
||||
map,
|
||||
[
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
[5, 6],
|
||||
],
|
||||
{ datalayer: this.datalayer }
|
||||
{ datalayer: datalayer }
|
||||
)
|
||||
assert.notOk(layer.isMulti())
|
||||
})
|
||||
|
||||
it('should return false for nested basic Polygon', function () {
|
||||
var latlngs = [[[p2ll(100, 150), p2ll(150, 200), p2ll(200, 100)]]],
|
||||
layer = new L.U.Polygon(this.map, latlngs, { datalayer: this.datalayer })
|
||||
layer = new L.U.Polygon(map, latlngs, { datalayer: datalayer })
|
||||
assert.notOk(layer.isMulti())
|
||||
})
|
||||
|
||||
it('should return false for simple Polygon with hole', function () {
|
||||
var layer = new L.U.Polygon(
|
||||
this.map,
|
||||
map,
|
||||
[
|
||||
[
|
||||
[1, 2],
|
||||
|
@ -55,7 +55,7 @@ describe('L.U.Polygon', function () {
|
|||
[11, 12],
|
||||
],
|
||||
],
|
||||
{ datalayer: this.datalayer }
|
||||
{ datalayer: datalayer }
|
||||
)
|
||||
assert.notOk(layer.isMulti())
|
||||
})
|
||||
|
@ -77,7 +77,7 @@ describe('L.U.Polygon', function () {
|
|||
],
|
||||
],
|
||||
]
|
||||
var layer = new L.U.Polygon(this.map, latLngs, { datalayer: this.datalayer })
|
||||
var layer = new L.U.Polygon(map, latLngs, { datalayer: datalayer })
|
||||
assert.ok(layer.isMulti())
|
||||
})
|
||||
|
||||
|
@ -103,7 +103,7 @@ describe('L.U.Polygon', function () {
|
|||
],
|
||||
],
|
||||
]
|
||||
var layer = new L.U.Polygon(this.map, latLngs, { datalayer: this.datalayer })
|
||||
var layer = new L.U.Polygon(map, latLngs, { datalayer: datalayer })
|
||||
assert.ok(layer.isMulti())
|
||||
})
|
||||
})
|
||||
|
@ -120,27 +120,27 @@ describe('L.U.Polygon', function () {
|
|||
[[p2ll(100, 150), p2ll(150, 200), p2ll(200, 100)]],
|
||||
[[p2ll(300, 350), p2ll(350, 400), p2ll(400, 300)]],
|
||||
],
|
||||
layer = new L.U.Polygon(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
layer = new L.U.Polygon(map, latlngs, {
|
||||
datalayer: datalayer,
|
||||
}).addTo(datalayer)
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.equal(qst('Remove shape from the multi'), 1)
|
||||
})
|
||||
|
||||
it('should not allow to remove shape when not multi', function () {
|
||||
var latlngs = [[[p2ll(100, 150), p2ll(150, 200), p2ll(200, 100)]]],
|
||||
layer = new L.U.Polygon(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
layer = new L.U.Polygon(map, latlngs, {
|
||||
datalayer: datalayer,
|
||||
}).addTo(datalayer)
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.notOk(qst('Remove shape from the multi'))
|
||||
})
|
||||
|
||||
it('should not allow to isolate shape when not multi', function () {
|
||||
var latlngs = [[[p2ll(100, 150), p2ll(150, 200), p2ll(200, 100)]]],
|
||||
layer = new L.U.Polygon(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
layer = new L.U.Polygon(map, latlngs, {
|
||||
datalayer: datalayer,
|
||||
}).addTo(datalayer)
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.notOk(qst('Extract shape to separate feature'))
|
||||
})
|
||||
|
@ -150,9 +150,9 @@ describe('L.U.Polygon', function () {
|
|||
[[p2ll(100, 150), p2ll(150, 200), p2ll(200, 100)]],
|
||||
[[p2ll(300, 350), p2ll(350, 400), p2ll(400, 300)]],
|
||||
],
|
||||
layer = new L.U.Polygon(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
layer = new L.U.Polygon(map, latlngs, {
|
||||
datalayer: datalayer,
|
||||
}).addTo(datalayer)
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.ok(qst('Extract shape to separate feature'))
|
||||
})
|
||||
|
@ -162,9 +162,9 @@ describe('L.U.Polygon', function () {
|
|||
[[p2ll(100, 150), p2ll(150, 200), p2ll(200, 100)]],
|
||||
[[p2ll(300, 350), p2ll(350, 400), p2ll(400, 300)]],
|
||||
],
|
||||
layer = new L.U.Polygon(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
layer = new L.U.Polygon(map, latlngs, {
|
||||
datalayer: datalayer,
|
||||
}).addTo(datalayer)
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.notOk(qst('Transform to lines'))
|
||||
})
|
||||
|
@ -176,26 +176,26 @@ describe('L.U.Polygon', function () {
|
|||
[p2ll(120, 150), p2ll(150, 180), p2ll(180, 120)],
|
||||
],
|
||||
],
|
||||
layer = new L.U.Polygon(this.map, latlngs, {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
layer = new L.U.Polygon(map, latlngs, {
|
||||
datalayer: datalayer,
|
||||
}).addTo(datalayer)
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.notOk(qst('Transform to lines'))
|
||||
})
|
||||
|
||||
it('should allow to transform to lines when not multi', function () {
|
||||
var latlngs = [[[p2ll(100, 150), p2ll(150, 200), p2ll(200, 100)]]]
|
||||
new L.U.Polygon(this.map, latlngs, { datalayer: this.datalayer }).addTo(
|
||||
this.datalayer
|
||||
new L.U.Polygon(map, latlngs, { datalayer: datalayer }).addTo(
|
||||
datalayer
|
||||
)
|
||||
happen.at('contextmenu', 150, 150)
|
||||
assert.equal(qst('Transform to lines'), 1)
|
||||
})
|
||||
|
||||
it('should not allow to transfer shape when not editedFeature', function () {
|
||||
new L.U.Polygon(this.map, [p2ll(100, 150), p2ll(100, 200), p2ll(200, 150)], {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
new L.U.Polygon(map, [p2ll(100, 150), p2ll(100, 200), p2ll(200, 150)], {
|
||||
datalayer: datalayer,
|
||||
}).addTo(datalayer)
|
||||
happen.at('contextmenu', 110, 160)
|
||||
assert.equal(qst('Delete this feature'), 1) // Make sure we have right clicked on the polygon.
|
||||
assert.notOk(qst('Transfer shape to edited feature'))
|
||||
|
@ -203,13 +203,13 @@ describe('L.U.Polygon', function () {
|
|||
|
||||
it('should not allow to transfer shape when editedFeature is not a polygon', function () {
|
||||
var layer = new L.U.Polygon(
|
||||
this.map,
|
||||
map,
|
||||
[p2ll(100, 150), p2ll(100, 200), p2ll(200, 150)],
|
||||
{ datalayer: this.datalayer }
|
||||
).addTo(this.datalayer),
|
||||
other = new L.U.Polyline(this.map, [p2ll(200, 250), p2ll(200, 300)], {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
{ datalayer: datalayer }
|
||||
).addTo(datalayer),
|
||||
other = new L.U.Polyline(map, [p2ll(200, 250), p2ll(200, 300)], {
|
||||
datalayer: datalayer,
|
||||
}).addTo(datalayer)
|
||||
other.edit()
|
||||
happen.once(layer._path, { type: 'contextmenu' })
|
||||
assert.equal(qst('Delete this feature'), 1) // Make sure we have right clicked on the polygon.
|
||||
|
@ -217,18 +217,18 @@ describe('L.U.Polygon', function () {
|
|||
})
|
||||
|
||||
it('should allow to transfer shape when another polygon is edited', function () {
|
||||
this.datalayer.empty()
|
||||
datalayer.empty()
|
||||
var layer = new L.U.Polygon(
|
||||
this.map,
|
||||
map,
|
||||
[p2ll(200, 300), p2ll(300, 200), p2ll(200, 100)],
|
||||
{ datalayer: this.datalayer }
|
||||
).addTo(this.datalayer)
|
||||
{ datalayer: datalayer }
|
||||
).addTo(datalayer)
|
||||
layer.edit() // This moves the map to put "other" at the center.
|
||||
var other = new L.U.Polygon(
|
||||
this.map,
|
||||
map,
|
||||
[p2ll(100, 150), p2ll(100, 200), p2ll(200, 150)],
|
||||
{ datalayer: this.datalayer }
|
||||
).addTo(this.datalayer)
|
||||
{ datalayer: datalayer }
|
||||
).addTo(datalayer)
|
||||
happen.once(other._path, { type: 'contextmenu' })
|
||||
assert.equal(qst('Transfer shape to edited feature'), 1)
|
||||
layer.remove()
|
||||
|
@ -242,19 +242,19 @@ describe('L.U.Polygon', function () {
|
|||
})
|
||||
|
||||
it('"add shape" control should be visible when editing a Polygon', function () {
|
||||
var layer = new L.U.Polygon(this.map, [p2ll(100, 100), p2ll(100, 200)], {
|
||||
datalayer: this.datalayer,
|
||||
}).addTo(this.datalayer)
|
||||
var layer = new L.U.Polygon(map, [p2ll(100, 100), p2ll(100, 200)], {
|
||||
datalayer: datalayer,
|
||||
}).addTo(datalayer)
|
||||
layer.edit()
|
||||
assert.ok(qs('.umap-draw-polygon-multi'))
|
||||
})
|
||||
|
||||
it('"add shape" control should extend the same multi', function () {
|
||||
var layer = new L.U.Polygon(
|
||||
this.map,
|
||||
map,
|
||||
[p2ll(100, 150), p2ll(150, 200), p2ll(200, 100)],
|
||||
{ datalayer: this.datalayer }
|
||||
).addTo(this.datalayer)
|
||||
{ datalayer: datalayer }
|
||||
).addTo(datalayer)
|
||||
layer.edit()
|
||||
assert.notOk(layer.isMulti())
|
||||
happen.click(qs('.umap-draw-polygon-multi'))
|
||||
|
@ -264,26 +264,26 @@ describe('L.U.Polygon', function () {
|
|||
happen.at('click', 350, 300)
|
||||
happen.at('click', 350, 300)
|
||||
assert.ok(layer.isMulti())
|
||||
assert.equal(this.datalayer._index.length, 1)
|
||||
assert.equal(datalayer._index.length, 1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#transferShape', function () {
|
||||
it('should transfer simple polygon shape to another polygon', function () {
|
||||
var latlngs = [p2ll(100, 150), p2ll(100, 200), p2ll(200, 100)],
|
||||
layer = new L.U.Polygon(this.map, latlngs, { datalayer: this.datalayer }).addTo(
|
||||
this.datalayer
|
||||
layer = new L.U.Polygon(map, latlngs, { datalayer: datalayer }).addTo(
|
||||
datalayer
|
||||
),
|
||||
other = new L.U.Polygon(
|
||||
this.map,
|
||||
map,
|
||||
[p2ll(200, 350), p2ll(200, 300), p2ll(300, 200)],
|
||||
{ datalayer: this.datalayer }
|
||||
).addTo(this.datalayer)
|
||||
assert.ok(this.map.hasLayer(layer))
|
||||
{ datalayer: datalayer }
|
||||
).addTo(datalayer)
|
||||
assert.ok(map.hasLayer(layer))
|
||||
layer.transferShape(p2ll(150, 150), other)
|
||||
assert.equal(other._latlngs.length, 2)
|
||||
assert.deepEqual(other._latlngs[1][0], latlngs)
|
||||
assert.notOk(this.map.hasLayer(layer))
|
||||
assert.notOk(map.hasLayer(layer))
|
||||
})
|
||||
|
||||
it('should transfer multipolygon shape to another polygon', function () {
|
||||
|
@ -294,19 +294,19 @@ describe('L.U.Polygon', function () {
|
|||
],
|
||||
[[p2ll(200, 300), p2ll(300, 200)]],
|
||||
],
|
||||
layer = new L.U.Polygon(this.map, latlngs, { datalayer: this.datalayer }).addTo(
|
||||
this.datalayer
|
||||
layer = new L.U.Polygon(map, latlngs, { datalayer: datalayer }).addTo(
|
||||
datalayer
|
||||
),
|
||||
other = new L.U.Polygon(
|
||||
this.map,
|
||||
map,
|
||||
[p2ll(200, 350), p2ll(200, 300), p2ll(300, 200)],
|
||||
{ datalayer: this.datalayer }
|
||||
).addTo(this.datalayer)
|
||||
assert.ok(this.map.hasLayer(layer))
|
||||
{ datalayer: datalayer }
|
||||
).addTo(datalayer)
|
||||
assert.ok(map.hasLayer(layer))
|
||||
layer.transferShape(p2ll(150, 150), other)
|
||||
assert.equal(other._latlngs.length, 2)
|
||||
assert.deepEqual(other._latlngs[1][0], latlngs[0][0])
|
||||
assert.ok(this.map.hasLayer(layer))
|
||||
assert.ok(map.hasLayer(layer))
|
||||
assert.equal(layer._latlngs.length, 1)
|
||||
})
|
||||
})
|
||||
|
@ -314,14 +314,14 @@ describe('L.U.Polygon', function () {
|
|||
describe('#isolateShape', function () {
|
||||
it('should not allow to isolate simple polygon', function () {
|
||||
var latlngs = [p2ll(100, 150), p2ll(100, 200), p2ll(200, 100)],
|
||||
layer = new L.U.Polygon(this.map, latlngs, { datalayer: this.datalayer }).addTo(
|
||||
this.datalayer
|
||||
layer = new L.U.Polygon(map, latlngs, { datalayer: datalayer }).addTo(
|
||||
datalayer
|
||||
)
|
||||
assert.equal(this.datalayer._index.length, 1)
|
||||
assert.ok(this.map.hasLayer(layer))
|
||||
assert.equal(datalayer._index.length, 1)
|
||||
assert.ok(map.hasLayer(layer))
|
||||
layer.isolateShape(p2ll(150, 150))
|
||||
assert.equal(layer._latlngs[0].length, 3)
|
||||
assert.equal(this.datalayer._index.length, 1)
|
||||
assert.equal(datalayer._index.length, 1)
|
||||
})
|
||||
|
||||
it('should isolate multipolygon shape', function () {
|
||||
|
@ -332,17 +332,17 @@ describe('L.U.Polygon', function () {
|
|||
],
|
||||
[[p2ll(200, 300), p2ll(300, 200)]],
|
||||
],
|
||||
layer = new L.U.Polygon(this.map, latlngs, { datalayer: this.datalayer }).addTo(
|
||||
this.datalayer
|
||||
layer = new L.U.Polygon(map, latlngs, { datalayer: datalayer }).addTo(
|
||||
datalayer
|
||||
)
|
||||
assert.equal(this.datalayer._index.length, 1)
|
||||
assert.ok(this.map.hasLayer(layer))
|
||||
assert.equal(datalayer._index.length, 1)
|
||||
assert.ok(map.hasLayer(layer))
|
||||
var other = layer.isolateShape(p2ll(150, 150))
|
||||
assert.equal(this.datalayer._index.length, 2)
|
||||
assert.equal(datalayer._index.length, 2)
|
||||
assert.equal(other._latlngs.length, 2)
|
||||
assert.deepEqual(other._latlngs[0], latlngs[0][0])
|
||||
assert.ok(this.map.hasLayer(layer))
|
||||
assert.ok(this.map.hasLayer(other))
|
||||
assert.ok(map.hasLayer(layer))
|
||||
assert.ok(map.hasLayer(other))
|
||||
assert.equal(layer._latlngs.length, 1)
|
||||
other.remove()
|
||||
})
|
||||
|
@ -351,13 +351,13 @@ describe('L.U.Polygon', function () {
|
|||
describe('#clone', function () {
|
||||
it('should clone polygon', function () {
|
||||
var latlngs = [p2ll(100, 150), p2ll(100, 200), p2ll(200, 100)],
|
||||
layer = new L.U.Polygon(this.map, latlngs, { datalayer: this.datalayer }).addTo(
|
||||
this.datalayer
|
||||
layer = new L.U.Polygon(map, latlngs, { datalayer: datalayer }).addTo(
|
||||
datalayer
|
||||
)
|
||||
assert.equal(this.datalayer._index.length, 1)
|
||||
assert.equal(datalayer._index.length, 1)
|
||||
other = layer.clone()
|
||||
assert.ok(this.map.hasLayer(other))
|
||||
assert.equal(this.datalayer._index.length, 2)
|
||||
assert.ok(map.hasLayer(other))
|
||||
assert.equal(datalayer._index.length, 2)
|
||||
// Must not be the same reference
|
||||
assert.notEqual(layer._latlngs, other._latlngs)
|
||||
assert.equal(L.Util.formatNum(layer._latlngs[0][0].lat), other._latlngs[0][0].lat)
|
||||
|
|
|
@ -1,50 +1,54 @@
|
|||
describe('L.TableEditor', function () {
|
||||
var path = '/map/99/datalayer/edit/62/'
|
||||
describe('L.TableEditor', () => {
|
||||
let path = '/map/99/datalayer/edit/62/',
|
||||
datalayer
|
||||
|
||||
before(function () {
|
||||
this.server = sinon.fakeServer.create()
|
||||
this.server.respondWith(
|
||||
before(async () => {
|
||||
await fetchMock.mock(
|
||||
/\/datalayer\/62\/\?.*/,
|
||||
JSON.stringify(RESPONSES.datalayer62_GET)
|
||||
)
|
||||
this.map = initMap({ umap_id: 99 })
|
||||
this.datalayer = this.map.getDataLayerByUmapId(62)
|
||||
this.server.respond()
|
||||
this.options = {
|
||||
umap_id: 99,
|
||||
}
|
||||
map = initMap({ umap_id: 99 })
|
||||
const datalayer_options = defaultDatalayerData()
|
||||
await map.initDataLayers([datalayer_options])
|
||||
datalayer = map.getDataLayerByUmapId(62)
|
||||
enableEdit()
|
||||
})
|
||||
after(function () {
|
||||
after(() => {
|
||||
fetchMock.restore()
|
||||
clickCancel()
|
||||
this.server.restore()
|
||||
resetMap()
|
||||
})
|
||||
|
||||
describe('#open()', function () {
|
||||
describe('#open()', () => {
|
||||
var button
|
||||
|
||||
it('should exist table click on edit mode', function () {
|
||||
it('should exist table click on edit mode', () => {
|
||||
button = qs(
|
||||
'#browse_data_toggle_' + L.stamp(this.datalayer) + ' .layer-table-edit'
|
||||
'#browse_data_toggle_' + L.stamp(datalayer) + ' .layer-table-edit'
|
||||
)
|
||||
expect(button).to.be.ok
|
||||
})
|
||||
|
||||
it('should open table button click', function () {
|
||||
it('should open table button click', () => {
|
||||
happen.click(button)
|
||||
expect(qs('#umap-ui-container div.table')).to.be.ok
|
||||
expect(qsa('#umap-ui-container div.table form').length).to.eql(3) // One per feature.
|
||||
expect(qsa('#umap-ui-container div.table input').length).to.eql(3) // One per feature and per property.
|
||||
})
|
||||
})
|
||||
describe('#properties()', function () {
|
||||
describe('#properties()', () => {
|
||||
var feature
|
||||
|
||||
before(function () {
|
||||
var firstIndex = this.datalayer._index[0]
|
||||
feature = this.datalayer._layers[firstIndex]
|
||||
before(() => {
|
||||
var firstIndex = datalayer._index[0]
|
||||
feature = datalayer._layers[firstIndex]
|
||||
})
|
||||
|
||||
it('should create new property column', function () {
|
||||
var newPrompt = function () {
|
||||
it('should create new property column', () => {
|
||||
var newPrompt = () => {
|
||||
return 'newprop'
|
||||
}
|
||||
var oldPrompt = window.prompt
|
||||
|
@ -56,7 +60,7 @@ describe('L.TableEditor', function () {
|
|||
window.prompt = oldPrompt
|
||||
})
|
||||
|
||||
it('should populate feature property on fill', function () {
|
||||
it('should populate feature property on fill', () => {
|
||||
var input = qs(
|
||||
'form#umap-feature-properties_' + L.stamp(feature) + ' input[name=newprop]'
|
||||
)
|
||||
|
@ -64,8 +68,8 @@ describe('L.TableEditor', function () {
|
|||
expect(feature.properties.newprop).to.eql('the value')
|
||||
})
|
||||
|
||||
it('should update property name on update click', function () {
|
||||
var newPrompt = function () {
|
||||
it('should update property name on update click', () => {
|
||||
var newPrompt = () => {
|
||||
return 'newname'
|
||||
}
|
||||
var oldPrompt = window.prompt
|
||||
|
@ -79,9 +83,9 @@ describe('L.TableEditor', function () {
|
|||
window.prompt = oldPrompt
|
||||
})
|
||||
|
||||
it('should update property on delete click', function () {
|
||||
it('should update property on delete click', () => {
|
||||
var oldConfirm,
|
||||
newConfirm = function () {
|
||||
newConfirm = () => {
|
||||
return true
|
||||
}
|
||||
oldConfirm = window.confirm
|
||||
|
|
|
@ -213,7 +213,6 @@ function initMap(options) {
|
|||
},
|
||||
},
|
||||
}
|
||||
default_options.properties.datalayers.push(defaultDatalayerData())
|
||||
options = options || {}
|
||||
options.properties = L.extend({}, default_options.properties, options)
|
||||
options.geometry = {
|
||||
|
@ -386,10 +385,6 @@ var RESPONSES = {
|
|||
},
|
||||
}
|
||||
|
||||
sinon.fakeServer.flush = function () {
|
||||
this.responses = []
|
||||
}
|
||||
|
||||
var kml_example =
|
||||
'<?xml version="1.0" encoding="UTF-8"?>' +
|
||||
'<kml xmlns="http://www.opengis.net/kml/2.2">' +
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
<script src="../js/umap.core.js" defer></script>
|
||||
<script src="../js/umap.autocomplete.js" defer></script>
|
||||
<script src="../js/umap.popup.js" defer></script>
|
||||
<script src="../js/umap.xhr.js" defer></script>
|
||||
<script src="../js/umap.forms.js" defer></script>
|
||||
<script src="../js/umap.icon.js" defer></script>
|
||||
<script src="../js/umap.features.js" defer></script>
|
||||
|
@ -76,6 +75,10 @@
|
|||
<script src="../../../../node_modules/chai/chai.js"></script>
|
||||
<script src="../../../../node_modules/happen/happen.js"></script>
|
||||
<link rel="stylesheet" href="../../../../node_modules/mocha/mocha.css" />
|
||||
<script type="module">
|
||||
import fetchMock from '../../../../node_modules/fetch-mock/esm/client.js';
|
||||
window.fetchMock = fetchMock
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
mocha.setup({
|
||||
ui: 'bdd',
|
||||
|
@ -86,7 +89,6 @@
|
|||
</script>
|
||||
<script src="./_pre.js" defer></script>
|
||||
<script src="./Map.js" defer></script>
|
||||
<script src="./Map.Init.js" defer></script>
|
||||
<script src="./Map.Export.js" defer></script>
|
||||
<script src="./DataLayer.js" defer></script>
|
||||
<script src="./TableEditor.js" defer></script>
|
||||
|
@ -95,7 +97,6 @@
|
|||
<script src="./Polyline.js" defer></script>
|
||||
<script src="./Polygon.js" defer></script>
|
||||
<script src="./Util.js" defer></script>
|
||||
<script src="./Controls.js" defer></script>
|
||||
<script src="./Permissions.js" defer></script>
|
||||
<script src="./Choropleth.js" defer></script>
|
||||
<script type="module" src="./URLs.js" defer></script>
|
||||
|
|
|
@ -1,37 +1,51 @@
|
|||
{% load i18n %}
|
||||
{% if ENABLE_ACCOUNT_LOGIN %}
|
||||
<h5>{% trans "Please log in with your account" %}</h5>
|
||||
<div>
|
||||
{% if form.non_field_errors %}
|
||||
<ul class="form-errors">
|
||||
{% for error in form.non_field_errors %}<li>{{ error }}</li>{% endfor %}
|
||||
{% extends "base.html" %}
|
||||
{% load umap_tags i18n %}
|
||||
{% block extra_head %}
|
||||
{% umap_css %}
|
||||
{% endblock extra_head %}
|
||||
{% block body_class %}
|
||||
login
|
||||
{% endblock body_class %}
|
||||
{% block content %}
|
||||
<section>
|
||||
<header class="umap-nav">
|
||||
{% include "umap/branding.html" %}
|
||||
</header>
|
||||
{% if ENABLE_ACCOUNT_LOGIN %}
|
||||
<h2>{% trans "Please log in with your account" %}</h2>
|
||||
<div>
|
||||
{% if form.non_field_errors %}
|
||||
<ul class="form-errors">
|
||||
{% for error in form.non_field_errors %}<li>{{ error }}</li>{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
<form id="login_form" action="{% url "login" %}" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.username.errors }}
|
||||
<input type="text"
|
||||
name="username"
|
||||
placeholder="{% trans "Username" %}"
|
||||
autofocus />
|
||||
{{ form.password.errors }}
|
||||
<input type="password" name="password" placeholder="{% trans "Password" %}" />
|
||||
<input type="submit" value="{% trans "Login" %}" />
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if backends.backends|length %}
|
||||
<h2>{% trans "Please choose a provider" %}</h2>
|
||||
<div>
|
||||
<ul class="login-grid block-grid">
|
||||
{% for name in backends.backends %}
|
||||
<li>
|
||||
<a rel="nofollow"
|
||||
href="{% url "social:begin" name %}"
|
||||
class="umap-login-popup login-{{ name }}"
|
||||
title="{{ name|title }}"></a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
<form id="login_form" action="{% url "login" %}" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.username.errors }}
|
||||
<input type="text"
|
||||
name="username"
|
||||
placeholder="{% trans "Username" %}"
|
||||
autofocus />
|
||||
{{ form.password.errors }}
|
||||
<input type="password" name="password" placeholder="{% trans "Password" %}" />
|
||||
<input type="submit" value="{% trans "Login" %}" />
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if backends.backends|length %}
|
||||
<h5>{% trans "Please choose a provider" %}</h5>
|
||||
<div>
|
||||
<ul class="login-grid block-grid">
|
||||
{% for name in backends.backends %}
|
||||
<li>
|
||||
<a rel="nofollow"
|
||||
href="{% url "social:begin" name %}"
|
||||
class="umap-login-popup login-{{ name }}"
|
||||
title="{{ name|title }}"></a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endblock content %}
|
||||
|
|
3
umap/templates/umap/branding.html
Normal file
3
umap/templates/umap/branding.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
<h1>
|
||||
<a href="{% url "home" %}">{{ SITE_NAME }}</a>
|
||||
</h1>
|
|
@ -36,51 +36,26 @@
|
|||
{% block bottom_js %}
|
||||
{{ block.super }}
|
||||
<script type="text/javascript">
|
||||
window.addEventListener('DOMContentLoaded', (event => {
|
||||
|
||||
!(function () {
|
||||
window.addEventListener('DOMContentLoaded', event => {
|
||||
const ui = new L.U.UI(document.querySelector('header'))
|
||||
const xhr = new L.U.Xhr(ui)
|
||||
const login = document.querySelector('a.login')
|
||||
if (login) {
|
||||
L.DomEvent.on(login, 'click', function (e) {
|
||||
L.DomEvent.stop(e)
|
||||
xhr.login({
|
||||
login_required: this.getAttribute('href'),
|
||||
redirect: '/',
|
||||
})
|
||||
})
|
||||
}
|
||||
const logout = document.querySelector('a.logout')
|
||||
if (logout) {
|
||||
L.DomEvent.on(logout, 'click', function (e) {
|
||||
L.DomEvent.stop(e)
|
||||
xhr.logout(this.getAttribute('href'))
|
||||
})
|
||||
}
|
||||
const getMore = function (e) {
|
||||
const server = new window.umap.ServerRequest(ui)
|
||||
const getMore = async function (e) {
|
||||
L.DomEvent.stop(e)
|
||||
xhr._ajax({
|
||||
uri: this.href,
|
||||
verb: 'GET',
|
||||
callback: function (data) {
|
||||
const container = this.parentNode
|
||||
container.innerHTML = data
|
||||
const more = document.querySelector('.more_button')
|
||||
if (more) {
|
||||
L.DomEvent.on(more, 'click', getMore, more)
|
||||
}
|
||||
},
|
||||
context: this,
|
||||
})
|
||||
const [{html}, response, error] = await server.get(this.href)
|
||||
if (!error) {
|
||||
const container = this.parentNode
|
||||
container.innerHTML = html
|
||||
const more = document.querySelector('.more_button')
|
||||
if (more) {
|
||||
L.DomEvent.on(more, 'click', getMore, more)
|
||||
}
|
||||
}
|
||||
}
|
||||
const more = document.querySelector('.more_button')
|
||||
if (more) {
|
||||
L.DomEvent.on(more, 'click', getMore, more)
|
||||
}
|
||||
})(this)
|
||||
}
|
||||
))
|
||||
})
|
||||
</script>
|
||||
{% endblock bottom_js %}
|
||||
{% block footer %}
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
<script src="{% static 'umap/js/umap.core.js' %}" defer></script>
|
||||
<script src="{% static 'umap/js/umap.autocomplete.js' %}" defer></script>
|
||||
<script src="{% static 'umap/js/umap.popup.js' %}" defer></script>
|
||||
<script src="{% static 'umap/js/umap.xhr.js' %}" defer></script>
|
||||
<script src="{% static 'umap/js/umap.forms.js' %}" defer></script>
|
||||
<script src="{% static 'umap/js/umap.icon.js' %}" defer></script>
|
||||
<script src="{% static 'umap/js/umap.features.js' %}" defer></script>
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
{% load i18n %}
|
||||
<nav class="umap-nav">
|
||||
<section>
|
||||
<h1>
|
||||
<a href="{% url "home" %}">{{ title }}</a>
|
||||
</h1>
|
||||
{% include "umap/branding.html" %}
|
||||
</section>
|
||||
<section>
|
||||
<ul>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import re
|
||||
from time import sleep
|
||||
|
||||
import pytest
|
||||
from django.core.signing import get_cookie_signer
|
||||
|
@ -126,10 +125,14 @@ def test_anonymous_can_add_marker_on_editable_layer(
|
|||
|
||||
def test_can_change_perms_after_create(tilelayer, live_server, page):
|
||||
page.goto(f"{live_server.url}/en/map/new")
|
||||
# Create a layer
|
||||
page.get_by_title("Manage layers").click()
|
||||
page.get_by_role("button", name="Add a layer").click()
|
||||
page.locator("input[name=name]").fill("Layer 1")
|
||||
save = page.get_by_role("button", name="Save")
|
||||
expect(save).to_be_visible()
|
||||
save.click()
|
||||
sleep(1) # Let save ajax go back
|
||||
with page.expect_response(re.compile(r".*/datalayer/create/.*")):
|
||||
save.click()
|
||||
edit_permissions = page.get_by_title("Update permissions and editors")
|
||||
expect(edit_permissions).to_be_visible()
|
||||
edit_permissions.click()
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
from copy import deepcopy
|
||||
from time import sleep
|
||||
|
||||
import pytest
|
||||
from playwright.sync_api import expect
|
||||
|
||||
from umap.models import Map
|
||||
|
||||
from ..base import DataLayerFactory
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
@ -170,3 +173,46 @@ def test_data_browser_with_variable_in_name(live_server, page, bootstrap, map):
|
|||
expect(page.get_by_text("one point in france (point)")).to_be_visible()
|
||||
expect(page.get_by_text("one line in new zeland (line)")).to_be_visible()
|
||||
expect(page.get_by_text("one polygon in greenland (polygon)")).to_be_visible()
|
||||
|
||||
|
||||
def test_can_open_databrowser_from_layers_list(live_server, map, page, bootstrap):
|
||||
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
||||
page.get_by_title("See data layers").click()
|
||||
page.get_by_role("button", name="Browse data").click()
|
||||
browser = page.locator(".umap-browse-data")
|
||||
expect(browser).to_be_visible()
|
||||
expect(browser.get_by_text("test datalayer")).to_be_visible()
|
||||
expect(browser.get_by_text("one point in france")).to_be_visible()
|
||||
expect(browser.get_by_text("one line in new zeland")).to_be_visible()
|
||||
expect(browser.get_by_text("one polygon in greenland")).to_be_visible()
|
||||
|
||||
|
||||
def test_should_sort_features_in_natural_order(live_server, map, page):
|
||||
map.settings["properties"]["onLoadPanel"] = "databrowser"
|
||||
map.save()
|
||||
datalayer_data = deepcopy(DATALAYER_DATA)
|
||||
datalayer_data["features"][0]["properties"]["name"] = "9. a marker"
|
||||
datalayer_data["features"][1]["properties"]["name"] = "1. a poly"
|
||||
datalayer_data["features"][2]["properties"]["name"] = "100. a line"
|
||||
DataLayerFactory(map=map, data=datalayer_data)
|
||||
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
||||
features = page.locator(".umap-browse-data li")
|
||||
expect(features).to_have_count(3)
|
||||
expect(features.nth(0)).to_have_text("1. a poly")
|
||||
expect(features.nth(1)).to_have_text("9. a marker")
|
||||
expect(features.nth(2)).to_have_text("100. a line")
|
||||
|
||||
|
||||
def test_should_redraw_list_on_feature_delete(live_server, map, page, bootstrap):
|
||||
map.edit_status = Map.ANONYMOUS
|
||||
map.save()
|
||||
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
||||
# Enable edit
|
||||
page.get_by_role("button", name="Edit").click()
|
||||
buttons = page.locator(".umap-browse-data li .feature-delete")
|
||||
expect(buttons).to_have_count(3)
|
||||
page.on("dialog", lambda dialog: dialog.accept())
|
||||
buttons.nth(0).click()
|
||||
expect(buttons).to_have_count(2)
|
||||
page.get_by_role("button", name="Cancel edits").click()
|
||||
expect(buttons).to_have_count(3)
|
||||
|
|
|
@ -9,9 +9,10 @@ def test_should_have_fieldset_for_layer_type_properties(page, live_server, tilel
|
|||
expect(button).to_be_visible()
|
||||
button.click()
|
||||
|
||||
edit = page.locator("#umap-ui-container").get_by_title("Edit", exact=True)
|
||||
expect(edit).to_be_visible()
|
||||
edit.click()
|
||||
# Create a layer
|
||||
page.get_by_title("Manage layers").click()
|
||||
page.get_by_role("button", name="Add a layer").click()
|
||||
page.locator("input[name=name]").fill("Layer 1")
|
||||
|
||||
select = page.locator("#umap-ui-container .umap-field-type select")
|
||||
expect(select).to_be_visible()
|
||||
|
|
|
@ -21,7 +21,7 @@ def test_umap_import_from_file(live_server, datalayer, page):
|
|||
expect(button).to_be_visible()
|
||||
button.click()
|
||||
layers = page.locator(".umap-browse-datalayers li")
|
||||
expect(layers).to_have_count(3)
|
||||
expect(layers).to_have_count(2)
|
||||
nonloaded = page.locator(".umap-browse-datalayers li.off")
|
||||
expect(nonloaded).to_have_count(1)
|
||||
assert file_input.input_value()
|
||||
|
@ -37,7 +37,7 @@ def test_umap_import_geojson_from_textarea(live_server, datalayer, page):
|
|||
paths = page.locator("path")
|
||||
expect(markers).to_have_count(0)
|
||||
expect(paths).to_have_count(0)
|
||||
expect(layers).to_have_count(1)
|
||||
expect(layers).to_have_count(0)
|
||||
button = page.get_by_title("Import data")
|
||||
expect(button).to_be_visible()
|
||||
button.click()
|
||||
|
@ -48,7 +48,7 @@ def test_umap_import_geojson_from_textarea(live_server, datalayer, page):
|
|||
button = page.get_by_role("button", name="Import", exact=True)
|
||||
expect(button).to_be_visible()
|
||||
button.click()
|
||||
# No layer has been created
|
||||
# A layer has been created
|
||||
expect(layers).to_have_count(1)
|
||||
expect(markers).to_have_count(2)
|
||||
expect(paths).to_have_count(3)
|
||||
|
|
|
@ -41,6 +41,18 @@ def test_preconnect_for_tilelayer(map, page, live_server, tilelayer):
|
|||
expect(meta).to_have_count(0)
|
||||
|
||||
|
||||
def test_default_view_without_datalayer_should_use_default_center(
|
||||
map, live_server, datalayer, page
|
||||
):
|
||||
datalayer.settings["displayOnLoad"] = False
|
||||
datalayer.save()
|
||||
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
||||
# Hash is defined, so map is initialized
|
||||
expect(page).to_have_url(re.compile(r".*#7/48\..+/13\..+"))
|
||||
layers = page.locator(".umap-browse-datalayers li")
|
||||
expect(layers).to_have_count(1)
|
||||
|
||||
|
||||
def test_default_view_latest_without_datalayer_should_use_default_center(
|
||||
map, live_server, datalayer, page
|
||||
):
|
||||
|
@ -55,6 +67,20 @@ def test_default_view_latest_without_datalayer_should_use_default_center(
|
|||
expect(layers).to_have_count(1)
|
||||
|
||||
|
||||
def test_default_view_data_without_datalayer_should_use_default_center(
|
||||
map, live_server, datalayer, page
|
||||
):
|
||||
datalayer.settings["displayOnLoad"] = False
|
||||
datalayer.save()
|
||||
map.settings["properties"]["defaultView"] = "data"
|
||||
map.save()
|
||||
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
||||
# Hash is defined, so map is initialized
|
||||
expect(page).to_have_url(re.compile(r".*#7/48\..+/13\..+"))
|
||||
layers = page.locator(".umap-browse-datalayers li")
|
||||
expect(layers).to_have_count(1)
|
||||
|
||||
|
||||
def test_default_view_latest_with_marker(map, live_server, datalayer, page):
|
||||
map.settings["properties"]["defaultView"] = "latest"
|
||||
map.save()
|
||||
|
@ -193,3 +219,12 @@ def test_basic_choropleth_map(map, live_server, page):
|
|||
# Bretagne, Pays de la Loire, AURA
|
||||
paths = page.locator("path[fill='#eff3ff']")
|
||||
expect(paths).to_have_count(3)
|
||||
|
||||
|
||||
def test_minimap_on_load(map, live_server, datalayer, page):
|
||||
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
||||
expect(page.locator(".leaflet-control-minimap")).to_be_hidden()
|
||||
map.settings["properties"]["miniMap"] = True
|
||||
map.save()
|
||||
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
||||
expect(page.locator(".leaflet-control-minimap")).to_be_visible()
|
||||
|
|
|
@ -191,6 +191,10 @@ def test_create(tilelayer, live_server, login, user):
|
|||
def test_can_change_perms_after_create(tilelayer, live_server, login, user):
|
||||
page = login(user)
|
||||
page.goto(f"{live_server.url}/en/map/new")
|
||||
# Create a layer
|
||||
page.get_by_title("Manage layers").click()
|
||||
page.get_by_role("button", name="Add a layer").click()
|
||||
page.locator("input[name=name]").fill("Layer 1")
|
||||
save = page.get_by_role("button", name="Save")
|
||||
expect(save).to_be_visible()
|
||||
save.click()
|
||||
|
|
22
umap/tests/integration/test_share.py
Normal file
22
umap/tests/integration/test_share.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
import re
|
||||
|
||||
import pytest
|
||||
from playwright.sync_api import expect
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
def test_iframe_code(map, live_server, datalayer, page):
|
||||
page.goto(f"{live_server.url}{map.get_absolute_url()}?share")
|
||||
textarea = page.locator(".umap-share-iframe")
|
||||
expect(textarea).to_be_visible()
|
||||
expect(textarea).to_have_text(re.compile('src="'))
|
||||
expect(textarea).to_have_text(re.compile('href="'))
|
||||
# We should ave both, once for iframe link, once for full screen
|
||||
expect(textarea).to_have_text(re.compile("scrollWheelZoom=true"))
|
||||
expect(textarea).to_have_text(re.compile("scrollWheelZoom=false"))
|
||||
expect(textarea).not_to_have_text(re.compile(f"datalayers={datalayer.pk}"))
|
||||
# Open options
|
||||
page.get_by_text("Embed and link options").click()
|
||||
page.get_by_title("Keep current visible layers").click()
|
||||
expect(textarea).to_have_text(re.compile(f"datalayers={datalayer.pk}"))
|
|
@ -304,16 +304,6 @@ def test_user_dashboard_display_user_maps_distinct(client, map):
|
|||
assert body.count(anonymap.name) == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_logout_should_return_json_in_ajax(client, user, settings):
|
||||
client.login(username=user.username, password="123123")
|
||||
response = client.get(
|
||||
reverse("logout"), headers={"X_REQUESTED_WITH": "XMLHttpRequest"}
|
||||
)
|
||||
data = json.loads(response.content.decode())
|
||||
assert data["redirect"] == "/"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_logout_should_return_redirect(client, user, settings):
|
||||
client.login(username=user.username, password="123123")
|
||||
|
|
|
@ -15,7 +15,6 @@ from . import views
|
|||
from .decorators import (
|
||||
can_edit_map,
|
||||
can_view_map,
|
||||
jsonize_view,
|
||||
login_required_if_not_anonymous_allowed,
|
||||
)
|
||||
from .utils import decorated_patterns
|
||||
|
@ -50,7 +49,7 @@ urlpatterns = [
|
|||
]
|
||||
|
||||
i18n_urls = [
|
||||
re_path(r"^login/$", jsonize_view(auth_views.LoginView.as_view()), name="login"),
|
||||
re_path(r"^login/$", auth_views.LoginView.as_view(), name="login"),
|
||||
re_path(
|
||||
r"^login/popup/end/$", views.LoginPopupEnd.as_view(), name="login_popup_end"
|
||||
),
|
||||
|
|
|
@ -108,6 +108,12 @@ class PaginatorMixin:
|
|||
return [self.list_template_name]
|
||||
return super().get_template_names()
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
response = super().get(*args, **kwargs)
|
||||
if is_ajax(self.request):
|
||||
return simple_json_response(html=response.rendered_content)
|
||||
return response
|
||||
|
||||
|
||||
class PublicMapsMixin(object):
|
||||
def get_public_maps(self):
|
||||
|
@ -329,7 +335,6 @@ showcase = MapsShowCase.as_view()
|
|||
|
||||
def validate_url(request):
|
||||
assert request.method == "GET"
|
||||
assert is_ajax(request)
|
||||
url = request.GET.get("url")
|
||||
assert url
|
||||
try:
|
||||
|
@ -824,10 +829,8 @@ class MapDelete(DeleteView):
|
|||
|
||||
def form_valid(self, form):
|
||||
self.object = self.get_object()
|
||||
if self.object.owner and self.request.user != self.object.owner:
|
||||
if not self.object.can_delete(self.request.user, self.request):
|
||||
return HttpResponseForbidden(_("Only its owner can delete the map."))
|
||||
if not self.object.owner and not self.object.is_anonymous_owner(self.request):
|
||||
return HttpResponseForbidden()
|
||||
self.object.delete()
|
||||
return simple_json_response(redirect="/")
|
||||
|
||||
|
@ -1172,8 +1175,6 @@ def webmanifest(request):
|
|||
|
||||
def logout(request):
|
||||
do_logout(request)
|
||||
if is_ajax(request):
|
||||
return simple_json_response(redirect="/")
|
||||
return HttpResponseRedirect("/")
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue