mirror of
https://github.com/umap-project/umap.git
synced 2025-05-04 21:51:50 +02:00
Apply PrettierJS and Lebab to all remaining JS files
This commit is contained in:
parent
48288cc8cb
commit
5ef666a069
13 changed files with 8575 additions and 7450 deletions
|
@ -1,314 +1,340 @@
|
|||
L.U.AutoComplete = L.Class.extend({
|
||||
options: {
|
||||
placeholder: 'Start typing...',
|
||||
emptyMessage: 'No result',
|
||||
allowFree: true,
|
||||
minChar: 2,
|
||||
maxResults: 5,
|
||||
},
|
||||
|
||||
options: {
|
||||
placeholder: 'Start typing...',
|
||||
emptyMessage: 'No result',
|
||||
allowFree: true,
|
||||
minChar: 2,
|
||||
maxResults: 5
|
||||
},
|
||||
CACHE: '',
|
||||
RESULTS: [],
|
||||
|
||||
CACHE: '',
|
||||
RESULTS: [],
|
||||
|
||||
initialize: function (el, options) {
|
||||
this.el = el;
|
||||
var ui = new L.U.UI(document.querySelector('header'));
|
||||
this.xhr = new L.U.Xhr(ui);
|
||||
L.setOptions(this, options);
|
||||
var CURRENT = null;
|
||||
try {
|
||||
Object.defineProperty(this, 'CURRENT', {
|
||||
get: function () {
|
||||
return CURRENT;
|
||||
},
|
||||
set: function (index) {
|
||||
if (typeof index === 'object') {
|
||||
index = this.resultToIndex(index);
|
||||
}
|
||||
CURRENT = index;
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
// Hello IE8
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
createInput: function () {
|
||||
this.input = L.DomUtil.element('input', {
|
||||
type: 'text',
|
||||
placeholder: this.options.placeholder,
|
||||
autocomplete: 'off',
|
||||
className: this.options.className
|
||||
}, this.el);
|
||||
L.DomEvent.on(this.input, 'keydown', this.onKeyDown, this);
|
||||
L.DomEvent.on(this.input, 'keyup', this.onKeyUp, this);
|
||||
L.DomEvent.on(this.input, 'blur', this.onBlur, this);
|
||||
},
|
||||
|
||||
createContainer: function () {
|
||||
this.container = L.DomUtil.element('ul', {className: 'umap-autocomplete'}, document.body);
|
||||
},
|
||||
|
||||
resizeContainer: function()
|
||||
{
|
||||
var l = this.getLeft(this.input);
|
||||
var t = this.getTop(this.input) + this.input.offsetHeight;
|
||||
this.container.style.left = l + 'px';
|
||||
this.container.style.top = t + 'px';
|
||||
var width = this.options.width ? this.options.width : this.input.offsetWidth - 2;
|
||||
this.container.style.width = width + 'px';
|
||||
},
|
||||
|
||||
|
||||
onKeyDown: function (e) {
|
||||
switch (e.keyCode) {
|
||||
case L.U.Keys.TAB:
|
||||
if(this.CURRENT !== null) this.setChoice();
|
||||
L.DomEvent.stop(e);
|
||||
break;
|
||||
case L.U.Keys.ENTER:
|
||||
L.DomEvent.stop(e);
|
||||
this.setChoice();
|
||||
break;
|
||||
case L.U.Keys.ESC:
|
||||
L.DomEvent.stop(e);
|
||||
this.hide();
|
||||
break;
|
||||
case L.U.Keys.DOWN:
|
||||
if(this.RESULTS.length > 0) {
|
||||
if(this.CURRENT !== null && this.CURRENT < this.RESULTS.length - 1) { // what if one result?
|
||||
this.CURRENT++;
|
||||
this.highlight();
|
||||
}
|
||||
else if(this.CURRENT === null) {
|
||||
this.CURRENT = 0;
|
||||
this.highlight();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case L.U.Keys.UP:
|
||||
if(this.CURRENT !== null) {
|
||||
L.DomEvent.stop(e);
|
||||
}
|
||||
if(this.RESULTS.length > 0) {
|
||||
if(this.CURRENT > 0) {
|
||||
this.CURRENT--;
|
||||
this.highlight();
|
||||
}
|
||||
else if(this.CURRENT === 0) {
|
||||
this.CURRENT = null;
|
||||
this.highlight();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
onKeyUp: function (e) {
|
||||
var special = [
|
||||
L.U.Keys.TAB,
|
||||
L.U.Keys.ENTER,
|
||||
L.U.Keys.LEFT,
|
||||
L.U.Keys.RIGHT,
|
||||
L.U.Keys.DOWN,
|
||||
L.U.Keys.UP,
|
||||
L.U.Keys.APPLE,
|
||||
L.U.Keys.SHIFT,
|
||||
L.U.Keys.ALT,
|
||||
L.U.Keys.CTRL
|
||||
];
|
||||
if (special.indexOf(e.keyCode) === -1)
|
||||
{
|
||||
this.search();
|
||||
}
|
||||
},
|
||||
|
||||
onBlur: function () {
|
||||
var self = this;
|
||||
setTimeout(function () {
|
||||
self.hide();
|
||||
}, 100);
|
||||
},
|
||||
|
||||
clear: function () {
|
||||
this.RESULTS = [];
|
||||
this.CURRENT = null;
|
||||
this.CACHE = '';
|
||||
this.container.innerHTML = '';
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
this.clear();
|
||||
this.container.style.display = 'none';
|
||||
this.input.value = '';
|
||||
},
|
||||
|
||||
setChoice: function (choice) {
|
||||
choice = choice || this.RESULTS[this.CURRENT];
|
||||
if (choice) {
|
||||
this.input.value = choice.item.label;
|
||||
this.options.on_select(choice);
|
||||
this.displaySelected(choice);
|
||||
this.hide();
|
||||
if (this.options.callback) {
|
||||
L.Util.bind(this.options.callback, this)(choice);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
search: function() {
|
||||
var 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);
|
||||
},
|
||||
|
||||
createResult: function (item) {
|
||||
var el = L.DomUtil.element('li', {}, this.container);
|
||||
el.textContent = item.label;
|
||||
var result = {
|
||||
item: item,
|
||||
el: el
|
||||
};
|
||||
L.DomEvent.on(el, 'mouseover', function () {
|
||||
this.CURRENT = result;
|
||||
this.highlight();
|
||||
}, this);
|
||||
L.DomEvent.on(el, 'mousedown', function () {
|
||||
this.setChoice();
|
||||
}, this);
|
||||
return result;
|
||||
},
|
||||
|
||||
resultToIndex: function (result) {
|
||||
var out = null;
|
||||
this.forEach(this.RESULTS, function (item, index) {
|
||||
if (item.item.value == result.item.value) {
|
||||
out = index;
|
||||
return;
|
||||
}
|
||||
});
|
||||
return out;
|
||||
},
|
||||
|
||||
handleResults: function(data) {
|
||||
var self = this;
|
||||
this.clear();
|
||||
this.container.style.display = 'block';
|
||||
this.resizeContainer();
|
||||
this.forEach(data, function (item) {
|
||||
self.RESULTS.push(self.createResult(item));
|
||||
});
|
||||
this.CURRENT = 0;
|
||||
this.highlight();
|
||||
//TODO manage no results
|
||||
},
|
||||
|
||||
highlight: function () {
|
||||
var self = this;
|
||||
this.forEach(this.RESULTS, function (result, index) {
|
||||
if (index === self.CURRENT) L.DomUtil.addClass(result.el, 'on');
|
||||
else L.DomUtil.removeClass(result.el, 'on');
|
||||
});
|
||||
},
|
||||
|
||||
getLeft: function (el) {
|
||||
var tmp = el.offsetLeft;
|
||||
el = el.offsetParent;
|
||||
while(el) {
|
||||
tmp += el.offsetLeft;
|
||||
el = el.offsetParent;
|
||||
}
|
||||
return tmp;
|
||||
},
|
||||
|
||||
getTop: function (el) {
|
||||
var tmp = el.offsetTop;
|
||||
el = el.offsetParent;
|
||||
while(el) {
|
||||
tmp += el.offsetTop;
|
||||
el = el.offsetParent;
|
||||
}
|
||||
return tmp;
|
||||
},
|
||||
|
||||
forEach: function (els, callback) {
|
||||
Array.prototype.forEach.call(els, callback);
|
||||
initialize(el, options) {
|
||||
this.el = el
|
||||
const ui = new L.U.UI(document.querySelector('header'))
|
||||
this.xhr = new L.U.Xhr(ui)
|
||||
L.setOptions(this, options)
|
||||
let CURRENT = null
|
||||
try {
|
||||
Object.defineProperty(this, 'CURRENT', {
|
||||
get() {
|
||||
return CURRENT
|
||||
},
|
||||
set(index) {
|
||||
if (typeof index === 'object') {
|
||||
index = this.resultToIndex(index)
|
||||
}
|
||||
CURRENT = index
|
||||
},
|
||||
})
|
||||
} catch (e) {
|
||||
// Hello IE8
|
||||
}
|
||||
return this
|
||||
},
|
||||
|
||||
});
|
||||
createInput() {
|
||||
this.input = L.DomUtil.element(
|
||||
'input',
|
||||
{
|
||||
type: 'text',
|
||||
placeholder: this.options.placeholder,
|
||||
autocomplete: 'off',
|
||||
className: this.options.className,
|
||||
},
|
||||
this.el
|
||||
)
|
||||
L.DomEvent.on(this.input, 'keydown', this.onKeyDown, this)
|
||||
L.DomEvent.on(this.input, 'keyup', this.onKeyUp, this)
|
||||
L.DomEvent.on(this.input, 'blur', this.onBlur, this)
|
||||
},
|
||||
|
||||
createContainer() {
|
||||
this.container = L.DomUtil.element(
|
||||
'ul',
|
||||
{ className: 'umap-autocomplete' },
|
||||
document.body
|
||||
)
|
||||
},
|
||||
|
||||
resizeContainer() {
|
||||
const l = this.getLeft(this.input)
|
||||
const t = this.getTop(this.input) + this.input.offsetHeight
|
||||
this.container.style.left = `${l}px`
|
||||
this.container.style.top = `${t}px`
|
||||
const width = this.options.width ? this.options.width : this.input.offsetWidth - 2
|
||||
this.container.style.width = `${width}px`
|
||||
},
|
||||
|
||||
onKeyDown(e) {
|
||||
switch (e.keyCode) {
|
||||
case L.U.Keys.TAB:
|
||||
if (this.CURRENT !== null) this.setChoice()
|
||||
L.DomEvent.stop(e)
|
||||
break
|
||||
case L.U.Keys.ENTER:
|
||||
L.DomEvent.stop(e)
|
||||
this.setChoice()
|
||||
break
|
||||
case L.U.Keys.ESC:
|
||||
L.DomEvent.stop(e)
|
||||
this.hide()
|
||||
break
|
||||
case L.U.Keys.DOWN:
|
||||
if (this.RESULTS.length > 0) {
|
||||
if (this.CURRENT !== null && this.CURRENT < this.RESULTS.length - 1) {
|
||||
// what if one result?
|
||||
this.CURRENT++
|
||||
this.highlight()
|
||||
} else if (this.CURRENT === null) {
|
||||
this.CURRENT = 0
|
||||
this.highlight()
|
||||
}
|
||||
}
|
||||
break
|
||||
case L.U.Keys.UP:
|
||||
if (this.CURRENT !== null) {
|
||||
L.DomEvent.stop(e)
|
||||
}
|
||||
if (this.RESULTS.length > 0) {
|
||||
if (this.CURRENT > 0) {
|
||||
this.CURRENT--
|
||||
this.highlight()
|
||||
} else if (this.CURRENT === 0) {
|
||||
this.CURRENT = null
|
||||
this.highlight()
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
},
|
||||
|
||||
onKeyUp({ keyCode }) {
|
||||
const special = [
|
||||
L.U.Keys.TAB,
|
||||
L.U.Keys.ENTER,
|
||||
L.U.Keys.LEFT,
|
||||
L.U.Keys.RIGHT,
|
||||
L.U.Keys.DOWN,
|
||||
L.U.Keys.UP,
|
||||
L.U.Keys.APPLE,
|
||||
L.U.Keys.SHIFT,
|
||||
L.U.Keys.ALT,
|
||||
L.U.Keys.CTRL,
|
||||
]
|
||||
if (!special.includes(keyCode)) {
|
||||
this.search()
|
||||
}
|
||||
},
|
||||
|
||||
onBlur() {
|
||||
const self = this
|
||||
setTimeout(() => {
|
||||
self.hide()
|
||||
}, 100)
|
||||
},
|
||||
|
||||
clear() {
|
||||
this.RESULTS = []
|
||||
this.CURRENT = null
|
||||
this.CACHE = ''
|
||||
this.container.innerHTML = ''
|
||||
},
|
||||
|
||||
hide() {
|
||||
this.clear()
|
||||
this.container.style.display = 'none'
|
||||
this.input.value = ''
|
||||
},
|
||||
|
||||
setChoice(choice = this.RESULTS[this.CURRENT]) {
|
||||
if (choice) {
|
||||
this.input.value = choice.item.label
|
||||
this.options.on_select(choice)
|
||||
this.displaySelected(choice)
|
||||
this.hide()
|
||||
if (this.options.callback) {
|
||||
L.Util.bind(this.options.callback, this)(choice)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
search() {
|
||||
const 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
|
||||
)
|
||||
},
|
||||
|
||||
createResult(item) {
|
||||
const el = L.DomUtil.element('li', {}, this.container)
|
||||
el.textContent = item.label
|
||||
const result = {
|
||||
item,
|
||||
el,
|
||||
}
|
||||
L.DomEvent.on(
|
||||
el,
|
||||
'mouseover',
|
||||
function () {
|
||||
this.CURRENT = result
|
||||
this.highlight()
|
||||
},
|
||||
this
|
||||
)
|
||||
L.DomEvent.on(
|
||||
el,
|
||||
'mousedown',
|
||||
function () {
|
||||
this.setChoice()
|
||||
},
|
||||
this
|
||||
)
|
||||
return result
|
||||
},
|
||||
|
||||
resultToIndex(result) {
|
||||
let out = null
|
||||
this.forEach(this.RESULTS, (item, index) => {
|
||||
if (item.item.value == result.item.value) {
|
||||
out = index
|
||||
return
|
||||
}
|
||||
})
|
||||
return out
|
||||
},
|
||||
|
||||
handleResults(data) {
|
||||
const self = this
|
||||
this.clear()
|
||||
this.container.style.display = 'block'
|
||||
this.resizeContainer()
|
||||
this.forEach(data, (item) => {
|
||||
self.RESULTS.push(self.createResult(item))
|
||||
})
|
||||
this.CURRENT = 0
|
||||
this.highlight()
|
||||
//TODO manage no results
|
||||
},
|
||||
|
||||
highlight() {
|
||||
const self = this
|
||||
this.forEach(this.RESULTS, ({ el }, index) => {
|
||||
if (index === self.CURRENT) L.DomUtil.addClass(el, 'on')
|
||||
else L.DomUtil.removeClass(el, 'on')
|
||||
})
|
||||
},
|
||||
|
||||
getLeft(el) {
|
||||
let tmp = el.offsetLeft
|
||||
el = el.offsetParent
|
||||
while (el) {
|
||||
tmp += el.offsetLeft
|
||||
el = el.offsetParent
|
||||
}
|
||||
return tmp
|
||||
},
|
||||
|
||||
getTop(el) {
|
||||
let tmp = el.offsetTop
|
||||
el = el.offsetParent
|
||||
while (el) {
|
||||
tmp += el.offsetTop
|
||||
el = el.offsetParent
|
||||
}
|
||||
return tmp
|
||||
},
|
||||
|
||||
forEach(els, callback) {
|
||||
Array.prototype.forEach.call(els, callback)
|
||||
},
|
||||
})
|
||||
|
||||
L.U.AutoComplete.Ajax = L.U.AutoComplete.extend({
|
||||
initialize(el, options) {
|
||||
L.U.AutoComplete.prototype.initialize.call(this, el, options)
|
||||
if (!this.el) return this
|
||||
this.createInput()
|
||||
this.createContainer()
|
||||
this.selected_container = this.initSelectedContainer()
|
||||
},
|
||||
|
||||
initialize: function (el, options) {
|
||||
L.U.AutoComplete.prototype.initialize.call(this, el, options);
|
||||
if (!this.el) return this;
|
||||
this.createInput();
|
||||
this.createContainer();
|
||||
this.selected_container = this.initSelectedContainer();
|
||||
},
|
||||
|
||||
optionToResult: function (option) {
|
||||
return {
|
||||
value: option.value,
|
||||
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});
|
||||
optionToResult({ value, innerHTML }) {
|
||||
return {
|
||||
value: value,
|
||||
label: innerHTML,
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
_do_search(val, callback, context) {
|
||||
val = val.toLowerCase()
|
||||
this.xhr.get(`/agnocomplete/AutocompleteUser/?q=${encodeURIComponent(val)}`, {
|
||||
callback,
|
||||
context: context || this,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
L.U.AutoComplete.Ajax.SelectMultiple = L.U.AutoComplete.Ajax.extend({
|
||||
initSelectedContainer() {
|
||||
return L.DomUtil.after(
|
||||
this.input,
|
||||
L.DomUtil.element('ul', { className: 'umap-multiresult' })
|
||||
)
|
||||
},
|
||||
|
||||
initSelectedContainer: function () {
|
||||
return L.DomUtil.after(this.input, L.DomUtil.element('ul', {className: 'umap-multiresult'}));
|
||||
},
|
||||
|
||||
displaySelected: function (result) {
|
||||
var result_el = L.DomUtil.element('li', {}, this.selected_container);
|
||||
result_el.textContent = result.item.label;
|
||||
var close = L.DomUtil.element('span', {className: 'close'}, result_el);
|
||||
close.textContent = '×';
|
||||
L.DomEvent.on(close, 'click', function () {
|
||||
this.selected_container.removeChild(result_el);
|
||||
this.options.on_unselect(result);
|
||||
}, this);
|
||||
this.hide();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
displaySelected(result) {
|
||||
const result_el = L.DomUtil.element('li', {}, this.selected_container)
|
||||
result_el.textContent = result.item.label
|
||||
const close = L.DomUtil.element('span', { className: 'close' }, result_el)
|
||||
close.textContent = '×'
|
||||
L.DomEvent.on(
|
||||
close,
|
||||
'click',
|
||||
function () {
|
||||
this.selected_container.removeChild(result_el)
|
||||
this.options.on_unselect(result)
|
||||
},
|
||||
this
|
||||
)
|
||||
this.hide()
|
||||
},
|
||||
})
|
||||
|
||||
L.U.AutoComplete.Ajax.Select = L.U.AutoComplete.Ajax.extend({
|
||||
initSelectedContainer() {
|
||||
return L.DomUtil.after(
|
||||
this.input,
|
||||
L.DomUtil.element('div', { className: 'umap-singleresult' })
|
||||
)
|
||||
},
|
||||
|
||||
initSelectedContainer: function () {
|
||||
return L.DomUtil.after(this.input, L.DomUtil.element('div', {className: 'umap-singleresult'}));
|
||||
},
|
||||
|
||||
displaySelected: function (result) {
|
||||
var result_el = L.DomUtil.element('div', {}, this.selected_container);
|
||||
result_el.textContent = result.item.label;
|
||||
var close = L.DomUtil.element('span', {className: 'close'}, result_el);
|
||||
close.textContent = '×';
|
||||
this.input.style.display = 'none';
|
||||
L.DomEvent.on(close, 'click', function () {
|
||||
this.selected_container.innerHTML = '';
|
||||
this.input.style.display = 'block';
|
||||
}, this);
|
||||
this.hide();
|
||||
}
|
||||
|
||||
});
|
||||
displaySelected({ item }) {
|
||||
const result_el = L.DomUtil.element('div', {}, this.selected_container)
|
||||
result_el.textContent = item.label
|
||||
const close = L.DomUtil.element('span', { className: 'close' }, result_el)
|
||||
close.textContent = '×'
|
||||
this.input.style.display = 'none'
|
||||
L.DomEvent.on(
|
||||
close,
|
||||
'click',
|
||||
function () {
|
||||
this.selected_container.innerHTML = ''
|
||||
this.input.style.display = 'block'
|
||||
},
|
||||
this
|
||||
)
|
||||
this.hide()
|
||||
},
|
||||
})
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,143 +1,197 @@
|
|||
// Dedicated object so we can deal with a separate dirty status, and thus
|
||||
// call the endpoint only when needed, saving one call at each save.
|
||||
L.U.MapPermissions = L.Class.extend({
|
||||
options: {
|
||||
owner: null,
|
||||
editors: [],
|
||||
share_status: null,
|
||||
edit_status: null,
|
||||
},
|
||||
|
||||
options: {
|
||||
owner: null,
|
||||
editors: [],
|
||||
share_status: null,
|
||||
edit_status: null
|
||||
},
|
||||
|
||||
initialize: function (map) {
|
||||
this.setOptions(map.options.permissions);
|
||||
this.map = map;
|
||||
var isDirty = false,
|
||||
self = this;
|
||||
try {
|
||||
Object.defineProperty(this, 'isDirty', {
|
||||
get: function () {
|
||||
return isDirty;
|
||||
},
|
||||
set: function (status) {
|
||||
isDirty = status;
|
||||
if (status) self.map.isDirty = status;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
// Certainly IE8, which has a limited version of defineProperty
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
setOptions: function (options) {
|
||||
this.options = L.Util.setOptions(this, options);
|
||||
},
|
||||
|
||||
isOwner: function () {
|
||||
return this.map.options.user && this.map.options.permissions.owner && this.map.options.user.id == this.map.options.permissions.owner.id;
|
||||
},
|
||||
|
||||
isAnonymousMap: function () {
|
||||
return !this.map.options.permissions.owner;
|
||||
},
|
||||
|
||||
getMap: function () {
|
||||
return this.map;
|
||||
},
|
||||
|
||||
edit: function () {
|
||||
if (!this.map.options.umap_id) return this.map.ui.alert({content: L._('Please save the map first'), level: 'info'});
|
||||
var container = L.DomUtil.create('div', 'permissions-panel'),
|
||||
fields = [],
|
||||
title = L.DomUtil.create('h4', '', container);
|
||||
if (this.isAnonymousMap()) {
|
||||
if (this.options.anonymous_edit_url) {
|
||||
var helpText = L._('Secret edit link is:<br>{link}', {link: this.options.anonymous_edit_url});
|
||||
fields.push(['options.edit_status', {handler: 'IntSelect', label: L._('Who can edit'), selectOptions: this.map.options.anonymous_edit_statuses, helpText: helpText}]);
|
||||
}
|
||||
} else {
|
||||
if (this.isOwner()) {
|
||||
fields.push(['options.edit_status', {handler: 'IntSelect', label: L._('Who can edit'), selectOptions: this.map.options.edit_statuses}]);
|
||||
fields.push(['options.share_status', {handler: 'IntSelect', label: L._('Who can view'), selectOptions: this.map.options.share_statuses}]);
|
||||
fields.push(['options.owner', {handler: 'ManageOwner', label: L._("Map's owner")}]);
|
||||
}
|
||||
fields.push(['options.editors', {handler: 'ManageEditors', label: L._("Map's editors")}]);
|
||||
}
|
||||
title.textContent = L._('Update permissions');
|
||||
var builder = new L.U.FormBuilder(this, fields);
|
||||
var form = builder.build();
|
||||
container.appendChild(form);
|
||||
if (this.isAnonymousMap() && this.map.options.user) {
|
||||
// We have a user, and this user has come through here, so they can edit the map, so let's allow to own the map.
|
||||
// Note: real check is made on the back office anyway.
|
||||
var advancedActions = L.DomUtil.createFieldset(container, L._('Advanced actions'));
|
||||
var advancedButtons = L.DomUtil.create('div', 'button-bar', advancedActions);
|
||||
var download = L.DomUtil.create('a', 'button', advancedButtons);
|
||||
download.href = '#';
|
||||
download.textContent = L._('Attach the map to my account');
|
||||
L.DomEvent
|
||||
.on(download, 'click', L.DomEvent.stop)
|
||||
.on(download, 'click', this.attach, this);
|
||||
}
|
||||
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
|
||||
})
|
||||
},
|
||||
|
||||
save: function () {
|
||||
if (!this.isDirty) return this.map.continueSaving();
|
||||
var formData = new FormData();
|
||||
if (!this.isAnonymousMap() && this.options.editors) {
|
||||
var editors = this.options.editors.map(function (u) {return u.id});
|
||||
for (var i = 0; i < this.options.editors.length; i++) formData.append('editors', this.options.editors[i].id);
|
||||
}
|
||||
if (this.isOwner() || this.isAnonymousMap()) formData.append('edit_status', this.options.edit_status);
|
||||
if (this.isOwner()) {
|
||||
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();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getUrl: function () {
|
||||
return L.Util.template(this.map.options.urls.map_update_permissions, {'map_id': this.map.options.umap_id});
|
||||
},
|
||||
|
||||
getAttachUrl: function () {
|
||||
return L.Util.template(this.map.options.urls.map_attach_owner, {'map_id': this.map.options.umap_id});
|
||||
},
|
||||
|
||||
addOwnerLink: function (element, container) {
|
||||
if (this.options.owner && this.options.owner.name && this.options.owner.url) {
|
||||
var ownerContainer = L.DomUtil.add(element, 'umap-map-owner', container, ' ' + L._('by') + ' '),
|
||||
owner = L.DomUtil.create('a');
|
||||
owner.href = this.options.owner.url;
|
||||
owner.textContent = this.options.owner.name;
|
||||
ownerContainer.appendChild(owner);
|
||||
}
|
||||
},
|
||||
|
||||
commit: function () {
|
||||
L.Util.extend(this.map.options.permissions, this.options);
|
||||
initialize(map) {
|
||||
this.setOptions(map.options.permissions)
|
||||
this.map = map
|
||||
let isDirty = false
|
||||
const self = this
|
||||
try {
|
||||
Object.defineProperty(this, 'isDirty', {
|
||||
get() {
|
||||
return isDirty
|
||||
},
|
||||
set(status) {
|
||||
isDirty = status
|
||||
if (status) self.map.isDirty = status
|
||||
},
|
||||
})
|
||||
} catch (e) {
|
||||
// Certainly IE8, which has a limited version of defineProperty
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
setOptions(options) {
|
||||
this.options = L.Util.setOptions(this, options)
|
||||
},
|
||||
|
||||
isOwner() {
|
||||
return (
|
||||
this.map.options.user &&
|
||||
this.map.options.permissions.owner &&
|
||||
this.map.options.user.id == this.map.options.permissions.owner.id
|
||||
)
|
||||
},
|
||||
|
||||
isAnonymousMap() {
|
||||
return !this.map.options.permissions.owner
|
||||
},
|
||||
|
||||
getMap() {
|
||||
return this.map
|
||||
},
|
||||
|
||||
edit() {
|
||||
if (!this.map.options.umap_id)
|
||||
return this.map.ui.alert({
|
||||
content: L._('Please save the map first'),
|
||||
level: 'info',
|
||||
})
|
||||
const container = L.DomUtil.create('div', 'permissions-panel')
|
||||
const fields = []
|
||||
const title = L.DomUtil.create('h4', '', container)
|
||||
if (this.isAnonymousMap()) {
|
||||
if (this.options.anonymous_edit_url) {
|
||||
const helpText = L._('Secret edit link is:<br>{link}', {
|
||||
link: this.options.anonymous_edit_url,
|
||||
})
|
||||
fields.push([
|
||||
'options.edit_status',
|
||||
{
|
||||
handler: 'IntSelect',
|
||||
label: L._('Who can edit'),
|
||||
selectOptions: this.map.options.anonymous_edit_statuses,
|
||||
helpText,
|
||||
},
|
||||
])
|
||||
}
|
||||
} else {
|
||||
if (this.isOwner()) {
|
||||
fields.push([
|
||||
'options.edit_status',
|
||||
{
|
||||
handler: 'IntSelect',
|
||||
label: L._('Who can edit'),
|
||||
selectOptions: this.map.options.edit_statuses,
|
||||
},
|
||||
])
|
||||
fields.push([
|
||||
'options.share_status',
|
||||
{
|
||||
handler: 'IntSelect',
|
||||
label: L._('Who can view'),
|
||||
selectOptions: this.map.options.share_statuses,
|
||||
},
|
||||
])
|
||||
fields.push([
|
||||
'options.owner',
|
||||
{ handler: 'ManageOwner', label: L._("Map's owner") },
|
||||
])
|
||||
}
|
||||
fields.push([
|
||||
'options.editors',
|
||||
{ handler: 'ManageEditors', label: L._("Map's editors") },
|
||||
])
|
||||
}
|
||||
title.textContent = L._('Update permissions')
|
||||
const builder = new L.U.FormBuilder(this, fields)
|
||||
const form = builder.build()
|
||||
container.appendChild(form)
|
||||
if (this.isAnonymousMap() && this.map.options.user) {
|
||||
// We have a user, and this user has come through here, so they can edit the map, so let's allow to own the map.
|
||||
// Note: real check is made on the back office anyway.
|
||||
const advancedActions = L.DomUtil.createFieldset(
|
||||
container,
|
||||
L._('Advanced actions')
|
||||
)
|
||||
const advancedButtons = L.DomUtil.create('div', 'button-bar', advancedActions)
|
||||
const download = L.DomUtil.create('a', 'button', advancedButtons)
|
||||
download.href = '#'
|
||||
download.textContent = L._('Attach the map to my account')
|
||||
L.DomEvent.on(download, 'click', L.DomEvent.stop).on(
|
||||
download,
|
||||
'click',
|
||||
this.attach,
|
||||
this
|
||||
)
|
||||
}
|
||||
this.map.ui.openPanel({ data: { html: container }, className: 'dark' })
|
||||
},
|
||||
|
||||
attach() {
|
||||
this.map.post(this.getAttachUrl(), {
|
||||
callback() {
|
||||
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,
|
||||
})
|
||||
},
|
||||
|
||||
save() {
|
||||
if (!this.isDirty) return this.map.continueSaving()
|
||||
const formData = new FormData()
|
||||
if (!this.isAnonymousMap() && this.options.editors) {
|
||||
const editors = this.options.editors.map(({ id }) => id)
|
||||
for (let i = 0; i < this.options.editors.length; i++)
|
||||
formData.append('editors', this.options.editors[i].id)
|
||||
}
|
||||
if (this.isOwner() || this.isAnonymousMap())
|
||||
formData.append('edit_status', this.options.edit_status)
|
||||
if (this.isOwner()) {
|
||||
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(data) {
|
||||
this.commit()
|
||||
this.isDirty = false
|
||||
this.map.continueSaving()
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
getUrl() {
|
||||
return L.Util.template(this.map.options.urls.map_update_permissions, {
|
||||
map_id: this.map.options.umap_id,
|
||||
})
|
||||
},
|
||||
|
||||
getAttachUrl() {
|
||||
return L.Util.template(this.map.options.urls.map_attach_owner, {
|
||||
map_id: this.map.options.umap_id,
|
||||
})
|
||||
},
|
||||
|
||||
addOwnerLink(element, container) {
|
||||
if (this.options.owner && this.options.owner.name && this.options.owner.url) {
|
||||
const ownerContainer = L.DomUtil.add(
|
||||
element,
|
||||
'umap-map-owner',
|
||||
container,
|
||||
` ${L._('by')} `
|
||||
)
|
||||
const owner = L.DomUtil.create('a')
|
||||
owner.href = this.options.owner.url
|
||||
owner.textContent = this.options.owner.name
|
||||
ownerContainer.appendChild(owner)
|
||||
}
|
||||
},
|
||||
|
||||
commit() {
|
||||
L.Util.extend(this.map.options.permissions, this.options)
|
||||
},
|
||||
})
|
||||
|
|
|
@ -1,224 +1,239 @@
|
|||
/* Shapes */
|
||||
|
||||
L.U.Popup = L.Popup.extend({
|
||||
options: {
|
||||
parseTemplate: true,
|
||||
},
|
||||
|
||||
options: {
|
||||
parseTemplate: true
|
||||
},
|
||||
initialize(feature) {
|
||||
this.feature = feature
|
||||
this.container = L.DomUtil.create('div', 'umap-popup')
|
||||
this.format()
|
||||
L.Popup.prototype.initialize.call(this, {}, feature)
|
||||
this.setContent(this.container)
|
||||
},
|
||||
|
||||
initialize: function (feature) {
|
||||
this.feature = feature;
|
||||
this.container = L.DomUtil.create('div', 'umap-popup');
|
||||
this.format();
|
||||
L.Popup.prototype.initialize.call(this, {}, feature);
|
||||
this.setContent(this.container);
|
||||
},
|
||||
|
||||
format: function () {
|
||||
var mode = this.feature.getOption('popupTemplate') || 'Default',
|
||||
klass = L.U.PopupTemplate[mode] || L.U.PopupTemplate.Default;
|
||||
this.content = new klass(this.feature, this.container);
|
||||
this.content.render();
|
||||
var els = this.container.querySelectorAll('img,iframe');
|
||||
for (var i = 0; i < els.length; i++) {
|
||||
this.onElementLoaded(els[i]);
|
||||
}
|
||||
if (!els.length && this.container.textContent.replace('\n', '') === '') {
|
||||
this.container.innerHTML = '';
|
||||
L.DomUtil.add('h3', '', this.container, this.feature.getDisplayName());
|
||||
}
|
||||
},
|
||||
|
||||
onElementLoaded: function (el) {
|
||||
L.DomEvent.on(el, 'load', function () {
|
||||
this._updateLayout();
|
||||
this._updatePosition();
|
||||
this._adjustPan();
|
||||
}, this);
|
||||
format() {
|
||||
const mode = this.feature.getOption('popupTemplate') || 'Default'
|
||||
const klass = L.U.PopupTemplate[mode] || L.U.PopupTemplate.Default
|
||||
this.content = new klass(this.feature, this.container)
|
||||
this.content.render()
|
||||
const els = this.container.querySelectorAll('img,iframe')
|
||||
for (let i = 0; i < els.length; i++) {
|
||||
this.onElementLoaded(els[i])
|
||||
}
|
||||
if (!els.length && this.container.textContent.replace('\n', '') === '') {
|
||||
this.container.innerHTML = ''
|
||||
L.DomUtil.add('h3', '', this.container, this.feature.getDisplayName())
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
onElementLoaded(el) {
|
||||
L.DomEvent.on(
|
||||
el,
|
||||
'load',
|
||||
function () {
|
||||
this._updateLayout()
|
||||
this._updatePosition()
|
||||
this._adjustPan()
|
||||
},
|
||||
this
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
L.U.Popup.Large = L.U.Popup.extend({
|
||||
options: {
|
||||
maxWidth: 500,
|
||||
className: 'umap-popup-large'
|
||||
}
|
||||
});
|
||||
|
||||
options: {
|
||||
maxWidth: 500,
|
||||
className: 'umap-popup-large',
|
||||
},
|
||||
})
|
||||
|
||||
L.U.Popup.Panel = L.U.Popup.extend({
|
||||
options: {
|
||||
zoomAnimation: false,
|
||||
},
|
||||
|
||||
options: {
|
||||
zoomAnimation: false
|
||||
},
|
||||
allButton() {
|
||||
const button = L.DomUtil.create('li', '')
|
||||
L.DomUtil.create('i', 'umap-icon-16 umap-list', button)
|
||||
const label = L.DomUtil.create('span', '', button)
|
||||
label.textContent = label.title = L._('See all')
|
||||
L.DomEvent.on(button, 'click', this.feature.map.openBrowser, this.feature.map)
|
||||
return button
|
||||
},
|
||||
|
||||
allButton: function () {
|
||||
var button = L.DomUtil.create('li', '');
|
||||
L.DomUtil.create('i', 'umap-icon-16 umap-list', button);
|
||||
var label = L.DomUtil.create('span', '', button);
|
||||
label.textContent = label.title = L._('See all');
|
||||
L.DomEvent.on(button, 'click', this.feature.map.openBrowser, this.feature.map);
|
||||
return button;
|
||||
},
|
||||
update() {
|
||||
this.feature.map.ui.openPanel({
|
||||
data: { html: this._content },
|
||||
actions: [this.allButton()],
|
||||
})
|
||||
},
|
||||
|
||||
update: function () {
|
||||
this.feature.map.ui.openPanel({data: {html: this._content}, actions: [this.allButton()]});
|
||||
},
|
||||
onRemove(map) {
|
||||
map.ui.closePanel()
|
||||
L.U.Popup.prototype.onRemove.call(this, map)
|
||||
},
|
||||
|
||||
onRemove: function (map) {
|
||||
map.ui.closePanel();
|
||||
L.U.Popup.prototype.onRemove.call(this, map);
|
||||
},
|
||||
|
||||
_initLayout: function () {this._container = L.DomUtil.create('span');},
|
||||
_updateLayout: function () {},
|
||||
_updatePosition: function () {},
|
||||
_adjustPan: function () {}
|
||||
|
||||
});
|
||||
L.U.Popup.SimplePanel = L.U.Popup.Panel; // Retrocompat.
|
||||
_initLayout() {
|
||||
this._container = L.DomUtil.create('span')
|
||||
},
|
||||
_updateLayout() {},
|
||||
_updatePosition() {},
|
||||
_adjustPan() {},
|
||||
})
|
||||
L.U.Popup.SimplePanel = L.U.Popup.Panel // Retrocompat.
|
||||
|
||||
/* Content templates */
|
||||
|
||||
L.U.PopupTemplate = {};
|
||||
L.U.PopupTemplate = {}
|
||||
|
||||
L.U.PopupTemplate.Default = L.Class.extend({
|
||||
initialize(feature, container) {
|
||||
this.feature = feature
|
||||
this.container = container
|
||||
},
|
||||
|
||||
initialize: function (feature, container) {
|
||||
this.feature = feature;
|
||||
this.container = container;
|
||||
},
|
||||
renderTitle() {},
|
||||
|
||||
renderTitle: function () {},
|
||||
renderBody() {
|
||||
const template = this.feature.getOption('popupContentTemplate')
|
||||
const container = L.DomUtil.create('div', 'umap-popup-container')
|
||||
let content = ''
|
||||
let properties
|
||||
let center
|
||||
properties = this.feature.extendedProperties()
|
||||
// Resolve properties inside description
|
||||
properties.description = L.Util.greedyTemplate(
|
||||
this.feature.properties.description || '',
|
||||
properties
|
||||
)
|
||||
content = L.Util.greedyTemplate(template, properties)
|
||||
content = L.Util.toHTML(content)
|
||||
container.innerHTML = content
|
||||
return container
|
||||
},
|
||||
|
||||
renderBody: function () {
|
||||
var template = this.feature.getOption('popupContentTemplate'),
|
||||
container = L.DomUtil.create('div', 'umap-popup-container'),
|
||||
content = '', properties, center;
|
||||
properties = this.feature.extendedProperties();
|
||||
// Resolve properties inside description
|
||||
properties.description = L.Util.greedyTemplate(this.feature.properties.description || '', properties);
|
||||
content = L.Util.greedyTemplate(template, properties);
|
||||
content = L.Util.toHTML(content);
|
||||
container.innerHTML = content;
|
||||
return container;
|
||||
},
|
||||
|
||||
renderFooter: function () {
|
||||
if (this.feature.hasPopupFooter()) {
|
||||
var footerContainer = L.DomUtil.create('div', 'umap-footer-container', this.container),
|
||||
footer = L.DomUtil.create('ul', 'umap-popup-footer', footerContainer),
|
||||
previousLi = L.DomUtil.create('li', 'previous', footer),
|
||||
zoomLi = L.DomUtil.create('li', 'zoom', footer),
|
||||
nextLi = L.DomUtil.create('li', 'next', footer),
|
||||
next = this.feature.getNext(),
|
||||
prev = this.feature.getPrevious();
|
||||
if (next) nextLi.title = L._('Go to «{feature}»', {feature: next.properties.name || L._('next')});
|
||||
if (prev) previousLi.title = L._('Go to «{feature}»', {feature: prev.properties.name || L._('previous')});
|
||||
zoomLi.title = L._('Zoom to this feature');
|
||||
L.DomEvent.on(nextLi, 'click', function () {
|
||||
if (next) next.zoomTo({callback: next.view});
|
||||
});
|
||||
L.DomEvent.on(previousLi, 'click', function () {
|
||||
if (prev) prev.zoomTo({callback: prev.view});
|
||||
});
|
||||
L.DomEvent.on(zoomLi, 'click', function () {
|
||||
this.zoomTo();
|
||||
}, this.feature);
|
||||
}
|
||||
},
|
||||
|
||||
render: function () {
|
||||
var title = this.renderTitle();
|
||||
if (title) this.container.appendChild(title);
|
||||
var body = this.renderBody();
|
||||
if (body) L.DomUtil.add('div', 'umap-popup-content', this.container, body);
|
||||
this.renderFooter();
|
||||
renderFooter() {
|
||||
if (this.feature.hasPopupFooter()) {
|
||||
const footerContainer = L.DomUtil.create(
|
||||
'div',
|
||||
'umap-footer-container',
|
||||
this.container
|
||||
)
|
||||
const footer = L.DomUtil.create('ul', 'umap-popup-footer', footerContainer)
|
||||
const previousLi = L.DomUtil.create('li', 'previous', footer)
|
||||
const zoomLi = L.DomUtil.create('li', 'zoom', footer)
|
||||
const nextLi = L.DomUtil.create('li', 'next', footer)
|
||||
const next = this.feature.getNext()
|
||||
const prev = this.feature.getPrevious()
|
||||
if (next)
|
||||
nextLi.title = L._('Go to «{feature}»', {
|
||||
feature: next.properties.name || L._('next'),
|
||||
})
|
||||
if (prev)
|
||||
previousLi.title = L._('Go to «{feature}»', {
|
||||
feature: prev.properties.name || L._('previous'),
|
||||
})
|
||||
zoomLi.title = L._('Zoom to this feature')
|
||||
L.DomEvent.on(nextLi, 'click', () => {
|
||||
if (next) next.zoomTo({ callback: next.view })
|
||||
})
|
||||
L.DomEvent.on(previousLi, 'click', () => {
|
||||
if (prev) prev.zoomTo({ callback: prev.view })
|
||||
})
|
||||
L.DomEvent.on(
|
||||
zoomLi,
|
||||
'click',
|
||||
function () {
|
||||
this.zoomTo()
|
||||
},
|
||||
this.feature
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
render() {
|
||||
const title = this.renderTitle()
|
||||
if (title) this.container.appendChild(title)
|
||||
const body = this.renderBody()
|
||||
if (body) L.DomUtil.add('div', 'umap-popup-content', this.container, body)
|
||||
this.renderFooter()
|
||||
},
|
||||
})
|
||||
|
||||
L.U.PopupTemplate.BaseWithTitle = L.U.PopupTemplate.Default.extend({
|
||||
|
||||
renderTitle: function () {
|
||||
var title;
|
||||
if (this.feature.getDisplayName()) {
|
||||
title = L.DomUtil.create('h3', 'popup-title');
|
||||
title.textContent = this.feature.getDisplayName();
|
||||
}
|
||||
return title;
|
||||
renderTitle() {
|
||||
let title
|
||||
if (this.feature.getDisplayName()) {
|
||||
title = L.DomUtil.create('h3', 'popup-title')
|
||||
title.textContent = this.feature.getDisplayName()
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return title
|
||||
},
|
||||
})
|
||||
|
||||
L.U.PopupTemplate.Table = L.U.PopupTemplate.BaseWithTitle.extend({
|
||||
|
||||
formatRow: function (key, value) {
|
||||
if (value.indexOf('http') === 0) {
|
||||
value = '<a href="' + value + '" target="_blank">' + value + '</a>';
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
||||
addRow: function (container, key, value) {
|
||||
var tr = L.DomUtil.create('tr', '', container);
|
||||
L.DomUtil.add('th', '', tr, key);
|
||||
L.DomUtil.add('td', '', tr, this.formatRow(key, value));
|
||||
},
|
||||
|
||||
renderBody: function () {
|
||||
var table = L.DomUtil.create('table');
|
||||
|
||||
for (var key in this.feature.properties) {
|
||||
if (typeof this.feature.properties[key] === 'object' || key === 'name') continue;
|
||||
// TODO, manage links (url, mailto, wikipedia...)
|
||||
this.addRow(table, key, L.Util.escapeHTML(this.feature.properties[key]).trim());
|
||||
}
|
||||
return table;
|
||||
formatRow(key, value) {
|
||||
if (value.indexOf('http') === 0) {
|
||||
value = `<a href="${value}" target="_blank">${value}</a>`
|
||||
}
|
||||
return value
|
||||
},
|
||||
|
||||
});
|
||||
addRow(container, key, value) {
|
||||
const tr = L.DomUtil.create('tr', '', container)
|
||||
L.DomUtil.add('th', '', tr, key)
|
||||
L.DomUtil.add('td', '', tr, this.formatRow(key, value))
|
||||
},
|
||||
|
||||
renderBody() {
|
||||
const table = L.DomUtil.create('table')
|
||||
|
||||
for (const key in this.feature.properties) {
|
||||
if (typeof this.feature.properties[key] === 'object' || key === 'name') continue
|
||||
// TODO, manage links (url, mailto, wikipedia...)
|
||||
this.addRow(table, key, L.Util.escapeHTML(this.feature.properties[key]).trim())
|
||||
}
|
||||
return table
|
||||
},
|
||||
})
|
||||
|
||||
L.U.PopupTemplate.GeoRSSImage = L.U.PopupTemplate.BaseWithTitle.extend({
|
||||
options: {
|
||||
minWidth: 300,
|
||||
maxWidth: 500,
|
||||
className: 'umap-popup-large umap-georss-image',
|
||||
},
|
||||
|
||||
options: {
|
||||
minWidth: 300,
|
||||
maxWidth: 500,
|
||||
className: 'umap-popup-large umap-georss-image'
|
||||
},
|
||||
|
||||
renderBody: function () {
|
||||
var container = L.DomUtil.create('a');
|
||||
container.href = this.feature.properties.link;
|
||||
container.target = '_blank';
|
||||
if (this.feature.properties.img) {
|
||||
var img = L.DomUtil.create('img', '', container);
|
||||
img.src = this.feature.properties.img;
|
||||
// Sadly, we are unable to override this from JS the clean way
|
||||
// See https://github.com/Leaflet/Leaflet/commit/61d746818b99d362108545c151a27f09d60960ee#commitcomment-6061847
|
||||
img.style.maxWidth = this.options.maxWidth + 'px';
|
||||
img.style.maxHeight = this.options.maxWidth + 'px';
|
||||
this.onElementLoaded(img);
|
||||
}
|
||||
return container;
|
||||
renderBody() {
|
||||
const container = L.DomUtil.create('a')
|
||||
container.href = this.feature.properties.link
|
||||
container.target = '_blank'
|
||||
if (this.feature.properties.img) {
|
||||
const img = L.DomUtil.create('img', '', container)
|
||||
img.src = this.feature.properties.img
|
||||
// Sadly, we are unable to override this from JS the clean way
|
||||
// See https://github.com/Leaflet/Leaflet/commit/61d746818b99d362108545c151a27f09d60960ee#commitcomment-6061847
|
||||
img.style.maxWidth = `${this.options.maxWidth}px`
|
||||
img.style.maxHeight = `${this.options.maxWidth}px`
|
||||
this.onElementLoaded(img)
|
||||
}
|
||||
|
||||
});
|
||||
return container
|
||||
},
|
||||
})
|
||||
|
||||
L.U.PopupTemplate.GeoRSSLink = L.U.PopupTemplate.Default.extend({
|
||||
options: {
|
||||
className: 'umap-georss-link',
|
||||
},
|
||||
|
||||
options: {
|
||||
className: 'umap-georss-link'
|
||||
},
|
||||
|
||||
renderBody: function () {
|
||||
var title = this.renderTitle(this),
|
||||
a = L.DomUtil.add('a');
|
||||
a.href = this.feature.properties.link;
|
||||
a.target = '_blank';
|
||||
a.appendChild(title);
|
||||
return a;
|
||||
}
|
||||
});
|
||||
renderBody() {
|
||||
const title = this.renderTitle(this)
|
||||
const a = L.DomUtil.add('a')
|
||||
a.href = this.feature.properties.link
|
||||
a.target = '_blank'
|
||||
a.appendChild(title)
|
||||
return a
|
||||
},
|
||||
})
|
||||
|
|
|
@ -1,164 +1,165 @@
|
|||
L.U.Slideshow = L.Class.extend({
|
||||
statics: {
|
||||
CLASSNAME: 'umap-slideshow-active',
|
||||
},
|
||||
|
||||
statics: {
|
||||
CLASSNAME: 'umap-slideshow-active'
|
||||
},
|
||||
options: {
|
||||
delay: 5000,
|
||||
autoplay: false,
|
||||
},
|
||||
|
||||
options: {
|
||||
delay: 5000,
|
||||
autoplay: false
|
||||
},
|
||||
initialize(map, options) {
|
||||
this.setOptions(options)
|
||||
this.map = map
|
||||
this._id = null
|
||||
|
||||
initialize: function (map, options) {
|
||||
this.setOptions(options);
|
||||
this.map = map;
|
||||
this._id = null;
|
||||
var current = null, // current feature
|
||||
self = this;
|
||||
try {
|
||||
Object.defineProperty(this, 'current', {
|
||||
get: function () {
|
||||
if (!current) {
|
||||
var datalayer = this.defaultDatalayer();
|
||||
if (datalayer) current = datalayer.getFeatureByIndex(0);
|
||||
}
|
||||
return current;
|
||||
},
|
||||
set: function (feature) {
|
||||
current = feature;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
// Certainly IE8, which has a limited version of defineProperty
|
||||
}
|
||||
try {
|
||||
Object.defineProperty(this, 'next', {
|
||||
get: function () {
|
||||
if (!current) {
|
||||
return self.current;
|
||||
}
|
||||
return current.getNext();
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
// Certainly IE8, which has a limited version of defineProperty
|
||||
}
|
||||
if (this.options.autoplay) {
|
||||
this.map.onceDataLoaded(function () {
|
||||
this.play();
|
||||
}, this);
|
||||
}
|
||||
this.map.on('edit:enabled', function () {
|
||||
this.stop();
|
||||
}, this);
|
||||
},
|
||||
let // current feature
|
||||
current = null
|
||||
|
||||
setOptions: function (options) {
|
||||
L.setOptions(this, options);
|
||||
this.timeSpinner();
|
||||
},
|
||||
|
||||
defaultDatalayer: function () {
|
||||
return this.map.findDataLayer(function (d) { return d.allowBrowse() && d.hasData(); });
|
||||
},
|
||||
|
||||
timeSpinner: function () {
|
||||
var time = parseInt(this.options.delay, 10);
|
||||
if (!time) return;
|
||||
var css = 'rotation ' + time / 1000 + 's infinite linear',
|
||||
spinners = document.querySelectorAll('.umap-slideshow-toolbox .play .spinner');
|
||||
for (var i = 0; i < spinners.length; i++) {
|
||||
spinners[i].style.animation = css;
|
||||
spinners[i].style['-webkit-animation'] = css;
|
||||
spinners[i].style['-moz-animation'] = css;
|
||||
spinners[i].style['-o-animation'] = css;
|
||||
}
|
||||
},
|
||||
|
||||
resetSpinners: function () {
|
||||
// Make that animnation is coordinated with user actions
|
||||
var spinners = document.querySelectorAll('.umap-slideshow-toolbox .play .spinner'),
|
||||
el, newOne;
|
||||
for (var i = 0; i < spinners.length; i++) {
|
||||
el = spinners[i];
|
||||
newOne = el.cloneNode(true);
|
||||
el.parentNode.replaceChild(newOne, el);
|
||||
}
|
||||
},
|
||||
|
||||
play: function () {
|
||||
if (this._id) return;
|
||||
if (this.map.editEnabled || !this.map.options.slideshow.active) return;
|
||||
L.DomUtil.addClass(document.body, L.U.Slideshow.CLASSNAME);
|
||||
this._id = window.setInterval(L.bind(this.loop, this), this.options.delay);
|
||||
this.resetSpinners();
|
||||
this.loop();
|
||||
},
|
||||
|
||||
loop: function () {
|
||||
this.current = this.next;
|
||||
this.step();
|
||||
},
|
||||
|
||||
pause: function () {
|
||||
if (this._id) {
|
||||
L.DomUtil.removeClass(document.body, L.U.Slideshow.CLASSNAME);
|
||||
window.clearInterval(this._id);
|
||||
this._id = null;
|
||||
}
|
||||
},
|
||||
|
||||
stop: function () {
|
||||
this.pause();
|
||||
this.current = null;
|
||||
},
|
||||
|
||||
forward: function () {
|
||||
this.pause();
|
||||
this.current = this.next;
|
||||
this.step();
|
||||
},
|
||||
|
||||
backward: function () {
|
||||
this.pause();
|
||||
if (this.current) this.current = this.current.getPrevious();
|
||||
this.step();
|
||||
},
|
||||
|
||||
step: function () {
|
||||
if(!this.current) return this.stop();
|
||||
this.current.zoomTo({easing: this.options.easing});
|
||||
this.current.view();
|
||||
},
|
||||
|
||||
renderToolbox: function (container) {
|
||||
var box = L.DomUtil.create('ul', 'umap-slideshow-toolbox'),
|
||||
play = L.DomUtil.create('li', 'play', box),
|
||||
stop = L.DomUtil.create('li', 'stop', box),
|
||||
prev = L.DomUtil.create('li', 'prev', box),
|
||||
next = L.DomUtil.create('li', 'next', box);
|
||||
L.DomUtil.create('div', 'spinner', play);
|
||||
play.title = L._('Start slideshow');
|
||||
stop.title = L._('Stop slideshow');
|
||||
next.title = L._('Zoom to the next');
|
||||
prev.title = L._('Zoom to the previous');
|
||||
var toggle = function () {
|
||||
if (this._id) this.pause();
|
||||
else this.play();
|
||||
};
|
||||
L.DomEvent.on(play, 'click', L.DomEvent.stop)
|
||||
.on(play, 'click', toggle, this);
|
||||
L.DomEvent.on(stop, 'click', L.DomEvent.stop)
|
||||
.on(stop, 'click', this.stop, this);
|
||||
L.DomEvent.on(prev, 'click', L.DomEvent.stop)
|
||||
.on(prev, 'click', this.backward, this);
|
||||
L.DomEvent.on(next, 'click', L.DomEvent.stop)
|
||||
.on(next, 'click', this.forward, this);
|
||||
container.appendChild(box);
|
||||
this.timeSpinner();
|
||||
return box;
|
||||
const self = this
|
||||
try {
|
||||
Object.defineProperty(this, 'current', {
|
||||
get() {
|
||||
if (!current) {
|
||||
const datalayer = this.defaultDatalayer()
|
||||
if (datalayer) current = datalayer.getFeatureByIndex(0)
|
||||
}
|
||||
return current
|
||||
},
|
||||
set(feature) {
|
||||
current = feature
|
||||
},
|
||||
})
|
||||
} catch (e) {
|
||||
// Certainly IE8, which has a limited version of defineProperty
|
||||
}
|
||||
try {
|
||||
Object.defineProperty(this, 'next', {
|
||||
get() {
|
||||
if (!current) {
|
||||
return self.current
|
||||
}
|
||||
return current.getNext()
|
||||
},
|
||||
})
|
||||
} catch (e) {
|
||||
// Certainly IE8, which has a limited version of defineProperty
|
||||
}
|
||||
if (this.options.autoplay) {
|
||||
this.map.onceDataLoaded(function () {
|
||||
this.play()
|
||||
}, this)
|
||||
}
|
||||
this.map.on(
|
||||
'edit:enabled',
|
||||
function () {
|
||||
this.stop()
|
||||
},
|
||||
this
|
||||
)
|
||||
},
|
||||
|
||||
});
|
||||
setOptions(options) {
|
||||
L.setOptions(this, options)
|
||||
this.timeSpinner()
|
||||
},
|
||||
|
||||
defaultDatalayer() {
|
||||
return this.map.findDataLayer((d) => d.allowBrowse() && d.hasData())
|
||||
},
|
||||
|
||||
timeSpinner() {
|
||||
const time = parseInt(this.options.delay, 10)
|
||||
if (!time) return
|
||||
const css = `rotation ${time / 1000}s infinite linear`
|
||||
const spinners = document.querySelectorAll('.umap-slideshow-toolbox .play .spinner')
|
||||
for (let i = 0; i < spinners.length; i++) {
|
||||
spinners[i].style.animation = css
|
||||
spinners[i].style['-webkit-animation'] = css
|
||||
spinners[i].style['-moz-animation'] = css
|
||||
spinners[i].style['-o-animation'] = css
|
||||
}
|
||||
},
|
||||
|
||||
resetSpinners() {
|
||||
// Make that animnation is coordinated with user actions
|
||||
const spinners = document.querySelectorAll('.umap-slideshow-toolbox .play .spinner')
|
||||
|
||||
let el
|
||||
let newOne
|
||||
for (let i = 0; i < spinners.length; i++) {
|
||||
el = spinners[i]
|
||||
newOne = el.cloneNode(true)
|
||||
el.parentNode.replaceChild(newOne, el)
|
||||
}
|
||||
},
|
||||
|
||||
play() {
|
||||
if (this._id) return
|
||||
if (this.map.editEnabled || !this.map.options.slideshow.active) return
|
||||
L.DomUtil.addClass(document.body, L.U.Slideshow.CLASSNAME)
|
||||
this._id = window.setInterval(L.bind(this.loop, this), this.options.delay)
|
||||
this.resetSpinners()
|
||||
this.loop()
|
||||
},
|
||||
|
||||
loop() {
|
||||
this.current = this.next
|
||||
this.step()
|
||||
},
|
||||
|
||||
pause() {
|
||||
if (this._id) {
|
||||
L.DomUtil.removeClass(document.body, L.U.Slideshow.CLASSNAME)
|
||||
window.clearInterval(this._id)
|
||||
this._id = null
|
||||
}
|
||||
},
|
||||
|
||||
stop() {
|
||||
this.pause()
|
||||
this.current = null
|
||||
},
|
||||
|
||||
forward() {
|
||||
this.pause()
|
||||
this.current = this.next
|
||||
this.step()
|
||||
},
|
||||
|
||||
backward() {
|
||||
this.pause()
|
||||
if (this.current) this.current = this.current.getPrevious()
|
||||
this.step()
|
||||
},
|
||||
|
||||
step() {
|
||||
if (!this.current) return this.stop()
|
||||
this.current.zoomTo({ easing: this.options.easing })
|
||||
this.current.view()
|
||||
},
|
||||
|
||||
renderToolbox(container) {
|
||||
const box = L.DomUtil.create('ul', 'umap-slideshow-toolbox')
|
||||
const play = L.DomUtil.create('li', 'play', box)
|
||||
const stop = L.DomUtil.create('li', 'stop', box)
|
||||
const prev = L.DomUtil.create('li', 'prev', box)
|
||||
const next = L.DomUtil.create('li', 'next', box)
|
||||
L.DomUtil.create('div', 'spinner', play)
|
||||
play.title = L._('Start slideshow')
|
||||
stop.title = L._('Stop slideshow')
|
||||
next.title = L._('Zoom to the next')
|
||||
prev.title = L._('Zoom to the previous')
|
||||
const toggle = function () {
|
||||
if (this._id) this.pause()
|
||||
else this.play()
|
||||
}
|
||||
L.DomEvent.on(play, 'click', L.DomEvent.stop).on(play, 'click', toggle, this)
|
||||
L.DomEvent.on(stop, 'click', L.DomEvent.stop).on(stop, 'click', this.stop, this)
|
||||
L.DomEvent.on(prev, 'click', L.DomEvent.stop).on(prev, 'click', this.backward, this)
|
||||
L.DomEvent.on(next, 'click', L.DomEvent.stop).on(next, 'click', this.forward, this)
|
||||
container.appendChild(box)
|
||||
this.timeSpinner()
|
||||
return box
|
||||
},
|
||||
})
|
||||
|
|
|
@ -1,107 +1,124 @@
|
|||
L.U.TableEditor = L.Class.extend({
|
||||
initialize(datalayer) {
|
||||
this.datalayer = datalayer
|
||||
this.table = L.DomUtil.create('div', 'table')
|
||||
this.header = L.DomUtil.create('div', 'thead', this.table)
|
||||
this.body = L.DomUtil.create('div', 'tbody', this.table)
|
||||
this.resetProperties()
|
||||
},
|
||||
|
||||
initialize: function (datalayer) {
|
||||
this.datalayer = datalayer;
|
||||
this.table = L.DomUtil.create('div', 'table');
|
||||
this.header = L.DomUtil.create('div', 'thead', this.table);
|
||||
this.body = L.DomUtil.create('div', 'tbody', this.table);
|
||||
this.resetProperties();
|
||||
},
|
||||
|
||||
renderHeaders: function () {
|
||||
this.header.innerHTML = '';
|
||||
for (var i = 0; i < this.properties.length; i++) {
|
||||
this.renderHeader(this.properties[i]);
|
||||
}
|
||||
},
|
||||
|
||||
renderHeader: function (property) {
|
||||
var container = L.DomUtil.create('div', 'tcell', this.header),
|
||||
title = L.DomUtil.add('span', '', container, property),
|
||||
del = L.DomUtil.create('i', 'umap-delete', container),
|
||||
rename = L.DomUtil.create('i', 'umap-edit', container);
|
||||
del.title = L._('Delete this property on all the features');
|
||||
rename.title = L._('Rename this property on all the features');
|
||||
var doDelete = function () {
|
||||
if (confirm(L._('Are you sure you want to delete this property on all the features?'))) {
|
||||
this.datalayer.eachLayer(function (feature) {
|
||||
feature.deleteProperty(property);
|
||||
});
|
||||
this.datalayer.deindexProperty(property);
|
||||
this.resetProperties();
|
||||
this.edit();
|
||||
}
|
||||
};
|
||||
var doRename = function () {
|
||||
var newName = prompt(L._('Please enter the new name of this property'), property);
|
||||
if (!newName || !this.validateName(newName)) return;
|
||||
this.datalayer.eachLayer(function (feature) {
|
||||
feature.renameProperty(property, newName);
|
||||
});
|
||||
this.datalayer.deindexProperty(property);
|
||||
this.datalayer.indexProperty(newName);
|
||||
this.resetProperties();
|
||||
this.edit();
|
||||
};
|
||||
L.DomEvent.on(del, 'click', doDelete, this);
|
||||
L.DomEvent.on(rename, 'click', doRename, this);
|
||||
},
|
||||
|
||||
renderRow: function (feature) {
|
||||
var builder = new L.U.FormBuilder(feature, this.field_properties,
|
||||
{
|
||||
id: 'umap-feature-properties_' + L.stamp(feature),
|
||||
className: 'trow',
|
||||
callback: feature.resetTooltip
|
||||
}
|
||||
);
|
||||
this.body.appendChild(builder.build());
|
||||
},
|
||||
|
||||
compileProperties: function () {
|
||||
if (this.properties.length === 0) this.properties = ['name'];
|
||||
// description is a forced textarea, don't edit it in a text input, or you lose cariage returns
|
||||
if (this.properties.indexOf('description') !== -1) this.properties.splice(this.properties.indexOf('description'), 1);
|
||||
this.properties.sort();
|
||||
this.field_properties = [];
|
||||
for (var i = 0; i < this.properties.length; i++) {
|
||||
this.field_properties.push(['properties.' + this.properties[i], {wrapper: 'div', wrapperClass: 'tcell'}]);
|
||||
}
|
||||
},
|
||||
|
||||
resetProperties: function () {
|
||||
this.properties = this.datalayer._propertiesIndex;
|
||||
},
|
||||
|
||||
validateName: function (name) {
|
||||
if (name.indexOf(".") !== -1) {
|
||||
this.datalayer.map.ui.alert({content: L._('Invalide property name: {name}', {name: name}), level: 'error'});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
edit: function () {
|
||||
var id = 'tableeditor:edit';
|
||||
this.datalayer.map.fire('dataloading', {id: id});
|
||||
this.compileProperties();
|
||||
this.renderHeaders();
|
||||
this.body.innerHTML = '';
|
||||
this.datalayer.eachLayer(this.renderRow, this);
|
||||
var addButton = L.DomUtil.create('li', 'add-property');
|
||||
L.DomUtil.create('i', 'umap-icon-16 umap-add', addButton);
|
||||
var label = L.DomUtil.create('span', '', addButton);
|
||||
label.textContent = label.title = L._('Add a new property');
|
||||
var addProperty = function () {
|
||||
var newName = prompt(L._('Please enter the name of the property'));
|
||||
if (!newName || !this.validateName(newName)) return;
|
||||
this.datalayer.indexProperty(newName);
|
||||
this.edit();
|
||||
};
|
||||
L.DomEvent.on(addButton, 'click', addProperty, this);
|
||||
var className = (this.properties.length > 2) ? 'umap-table-editor fullwidth dark' : 'umap-table-editor dark';
|
||||
this.datalayer.map.ui.openPanel({data: {html: this.table}, className: className, actions: [addButton]});
|
||||
this.datalayer.map.fire('dataload', {id: id});
|
||||
renderHeaders() {
|
||||
this.header.innerHTML = ''
|
||||
for (let i = 0; i < this.properties.length; i++) {
|
||||
this.renderHeader(this.properties[i])
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
renderHeader(property) {
|
||||
const container = L.DomUtil.create('div', 'tcell', this.header)
|
||||
const title = L.DomUtil.add('span', '', container, property)
|
||||
const del = L.DomUtil.create('i', 'umap-delete', container)
|
||||
const rename = L.DomUtil.create('i', 'umap-edit', container)
|
||||
del.title = L._('Delete this property on all the features')
|
||||
rename.title = L._('Rename this property on all the features')
|
||||
const doDelete = function () {
|
||||
if (
|
||||
confirm(
|
||||
L._('Are you sure you want to delete this property on all the features?')
|
||||
)
|
||||
) {
|
||||
this.datalayer.eachLayer((feature) => {
|
||||
feature.deleteProperty(property)
|
||||
})
|
||||
this.datalayer.deindexProperty(property)
|
||||
this.resetProperties()
|
||||
this.edit()
|
||||
}
|
||||
}
|
||||
const doRename = function () {
|
||||
const newName = prompt(
|
||||
L._('Please enter the new name of this property'),
|
||||
property
|
||||
)
|
||||
if (!newName || !this.validateName(newName)) return
|
||||
this.datalayer.eachLayer((feature) => {
|
||||
feature.renameProperty(property, newName)
|
||||
})
|
||||
this.datalayer.deindexProperty(property)
|
||||
this.datalayer.indexProperty(newName)
|
||||
this.resetProperties()
|
||||
this.edit()
|
||||
}
|
||||
L.DomEvent.on(del, 'click', doDelete, this)
|
||||
L.DomEvent.on(rename, 'click', doRename, this)
|
||||
},
|
||||
|
||||
renderRow(feature) {
|
||||
const builder = new L.U.FormBuilder(feature, this.field_properties, {
|
||||
id: `umap-feature-properties_${L.stamp(feature)}`,
|
||||
className: 'trow',
|
||||
callback: feature.resetTooltip,
|
||||
})
|
||||
this.body.appendChild(builder.build())
|
||||
},
|
||||
|
||||
compileProperties() {
|
||||
if (this.properties.length === 0) this.properties = ['name']
|
||||
// description is a forced textarea, don't edit it in a text input, or you lose cariage returns
|
||||
if (this.properties.includes('description'))
|
||||
this.properties.splice(this.properties.indexOf('description'), 1)
|
||||
this.properties.sort()
|
||||
this.field_properties = []
|
||||
for (let i = 0; i < this.properties.length; i++) {
|
||||
this.field_properties.push([
|
||||
`properties.${this.properties[i]}`,
|
||||
{ wrapper: 'div', wrapperClass: 'tcell' },
|
||||
])
|
||||
}
|
||||
},
|
||||
|
||||
resetProperties() {
|
||||
this.properties = this.datalayer._propertiesIndex
|
||||
},
|
||||
|
||||
validateName(name) {
|
||||
if (name.includes('.')) {
|
||||
this.datalayer.map.ui.alert({
|
||||
content: L._('Invalide property name: {name}', { name }),
|
||||
level: 'error',
|
||||
})
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
|
||||
edit() {
|
||||
const id = 'tableeditor:edit'
|
||||
this.datalayer.map.fire('dataloading', { id })
|
||||
this.compileProperties()
|
||||
this.renderHeaders()
|
||||
this.body.innerHTML = ''
|
||||
this.datalayer.eachLayer(this.renderRow, this)
|
||||
const addButton = L.DomUtil.create('li', 'add-property')
|
||||
L.DomUtil.create('i', 'umap-icon-16 umap-add', addButton)
|
||||
const label = L.DomUtil.create('span', '', addButton)
|
||||
label.textContent = label.title = L._('Add a new property')
|
||||
const addProperty = function () {
|
||||
const newName = prompt(L._('Please enter the name of the property'))
|
||||
if (!newName || !this.validateName(newName)) return
|
||||
this.datalayer.indexProperty(newName)
|
||||
this.edit()
|
||||
}
|
||||
L.DomEvent.on(addButton, 'click', addProperty, this)
|
||||
const className =
|
||||
this.properties.length > 2
|
||||
? 'umap-table-editor fullwidth dark'
|
||||
: 'umap-table-editor dark'
|
||||
this.datalayer.map.ui.openPanel({
|
||||
data: { html: this.table },
|
||||
className,
|
||||
actions: [addButton],
|
||||
})
|
||||
this.datalayer.map.fire('dataload', { id })
|
||||
},
|
||||
})
|
||||
|
|
|
@ -1,176 +1,209 @@
|
|||
/*
|
||||
* Modals
|
||||
*/
|
||||
* Modals
|
||||
*/
|
||||
L.U.UI = L.Evented.extend({
|
||||
ALERTS: Array(),
|
||||
ALERT_ID: null,
|
||||
TOOLTIP_ID: null,
|
||||
|
||||
ALERTS: Array(),
|
||||
ALERT_ID: null,
|
||||
TOOLTIP_ID: null,
|
||||
initialize(parent) {
|
||||
this.parent = parent
|
||||
this.container = L.DomUtil.create('div', 'leaflet-ui-container', this.parent)
|
||||
L.DomEvent.disableClickPropagation(this.container)
|
||||
L.DomEvent.on(this.container, 'contextmenu', L.DomEvent.stopPropagation) // Do not activate our custom context menu.
|
||||
L.DomEvent.on(this.container, 'mousewheel', L.DomEvent.stopPropagation)
|
||||
L.DomEvent.on(this.container, 'MozMousePixelScroll', L.DomEvent.stopPropagation)
|
||||
this._panel = L.DomUtil.create('div', '', this.container)
|
||||
this._panel.id = 'umap-ui-container'
|
||||
this._alert = L.DomUtil.create('div', 'with-transition', this.container)
|
||||
this._alert.id = 'umap-alert-container'
|
||||
this._tooltip = L.DomUtil.create('div', '', this.container)
|
||||
this._tooltip.id = 'umap-tooltip-container'
|
||||
},
|
||||
|
||||
initialize: function (parent) {
|
||||
this.parent = parent;
|
||||
this.container = L.DomUtil.create('div', 'leaflet-ui-container', this.parent);
|
||||
L.DomEvent.disableClickPropagation(this.container);
|
||||
L.DomEvent.on(this.container, 'contextmenu', L.DomEvent.stopPropagation); // Do not activate our custom context menu.
|
||||
L.DomEvent.on(this.container, 'mousewheel', L.DomEvent.stopPropagation);
|
||||
L.DomEvent.on(this.container, 'MozMousePixelScroll', L.DomEvent.stopPropagation);
|
||||
this._panel = L.DomUtil.create('div', '', this.container);
|
||||
this._panel.id = 'umap-ui-container';
|
||||
this._alert = L.DomUtil.create('div', 'with-transition', this.container);
|
||||
this._alert.id = 'umap-alert-container';
|
||||
this._tooltip = L.DomUtil.create('div', '', this.container);
|
||||
this._tooltip.id = 'umap-tooltip-container';
|
||||
},
|
||||
resetPanelClassName() {
|
||||
this._panel.className = 'with-transition'
|
||||
},
|
||||
|
||||
resetPanelClassName: function () {
|
||||
this._panel.className = 'with-transition';
|
||||
},
|
||||
openPanel({ data, actions, className }) {
|
||||
this.fire('panel:open')
|
||||
// We reset all because we can't know which class has been added
|
||||
// by previous ui processes...
|
||||
this.resetPanelClassName()
|
||||
this._panel.innerHTML = ''
|
||||
const actionsContainer = L.DomUtil.create('ul', 'toolbox', this._panel)
|
||||
const body = L.DomUtil.create('div', 'body', this._panel)
|
||||
if (data.html.nodeType && data.html.nodeType === 1) body.appendChild(data.html)
|
||||
else body.innerHTML = data.html
|
||||
const closeLink = L.DomUtil.create('li', 'umap-close-link', actionsContainer)
|
||||
L.DomUtil.add('i', 'umap-close-icon', closeLink)
|
||||
const label = L.DomUtil.create('span', '', closeLink)
|
||||
label.title = label.textContent = L._('Close')
|
||||
if (actions) {
|
||||
for (let i = 0; i < actions.length; i++) {
|
||||
actionsContainer.appendChild(actions[i])
|
||||
}
|
||||
}
|
||||
if (className) L.DomUtil.addClass(this._panel, className)
|
||||
if (L.DomUtil.hasClass(this.parent, 'umap-ui')) {
|
||||
// Already open.
|
||||
this.fire('panel:ready')
|
||||
} else {
|
||||
L.DomEvent.once(
|
||||
this._panel,
|
||||
'transitionend',
|
||||
function (e) {
|
||||
this.fire('panel:ready')
|
||||
},
|
||||
this
|
||||
)
|
||||
L.DomUtil.addClass(this.parent, 'umap-ui')
|
||||
}
|
||||
L.DomEvent.on(closeLink, 'click', this.closePanel, this)
|
||||
},
|
||||
|
||||
openPanel: function (e) {
|
||||
this.fire('panel:open');
|
||||
// We reset all because we can't know which class has been added
|
||||
// by previous ui processes...
|
||||
this.resetPanelClassName();
|
||||
this._panel.innerHTML = '';
|
||||
var actionsContainer = L.DomUtil.create('ul', 'toolbox', this._panel);
|
||||
var body = L.DomUtil.create('div', 'body', this._panel);
|
||||
if (e.data.html.nodeType && e.data.html.nodeType === 1) body.appendChild(e.data.html);
|
||||
else body.innerHTML = e.data.html;
|
||||
var closeLink = L.DomUtil.create('li', 'umap-close-link', actionsContainer);
|
||||
L.DomUtil.add('i', 'umap-close-icon', closeLink);
|
||||
var label = L.DomUtil.create('span', '', closeLink);
|
||||
label.title = label.textContent = L._('Close');
|
||||
if (e.actions) {
|
||||
for (var i = 0; i < e.actions.length; i++) {
|
||||
actionsContainer.appendChild(e.actions[i]);
|
||||
}
|
||||
}
|
||||
if (e.className) L.DomUtil.addClass(this._panel, e.className);
|
||||
if (L.DomUtil.hasClass(this.parent, 'umap-ui')) {
|
||||
// Already open.
|
||||
this.fire('panel:ready');
|
||||
} else {
|
||||
L.DomEvent.once(this._panel, 'transitionend', function (e) {
|
||||
this.fire('panel:ready');
|
||||
}, this);
|
||||
L.DomUtil.addClass(this.parent, 'umap-ui');
|
||||
}
|
||||
L.DomEvent.on(closeLink, 'click', this.closePanel, this);
|
||||
},
|
||||
closePanel() {
|
||||
this.resetPanelClassName()
|
||||
L.DomUtil.removeClass(this.parent, 'umap-ui')
|
||||
this.fire('panel:closed')
|
||||
},
|
||||
|
||||
closePanel: function () {
|
||||
this.resetPanelClassName();
|
||||
L.DomUtil.removeClass(this.parent, 'umap-ui');
|
||||
this.fire('panel:closed');
|
||||
},
|
||||
alert(e) {
|
||||
if (L.DomUtil.hasClass(this.parent, 'umap-alert')) this.ALERTS.push(e)
|
||||
else this.popAlert(e)
|
||||
},
|
||||
|
||||
alert: function (e) {
|
||||
if (L.DomUtil.hasClass(this.parent, 'umap-alert')) this.ALERTS.push(e);
|
||||
else this.popAlert(e);
|
||||
},
|
||||
popAlert(e) {
|
||||
const self = this
|
||||
if (!e) {
|
||||
if (this.ALERTS.length) e = this.ALERTS.pop()
|
||||
else return
|
||||
}
|
||||
let timeoutID
|
||||
const level_class = e.level && e.level == 'info' ? 'info' : 'error'
|
||||
this._alert.innerHTML = ''
|
||||
L.DomUtil.addClass(this.parent, 'umap-alert')
|
||||
L.DomUtil.addClass(this._alert, level_class)
|
||||
const close = function () {
|
||||
if (timeoutID !== this.ALERT_ID) {
|
||||
return
|
||||
} // Another alert has been forced
|
||||
this._alert.innerHTML = ''
|
||||
L.DomUtil.removeClass(this.parent, 'umap-alert')
|
||||
L.DomUtil.removeClass(this._alert, level_class)
|
||||
if (timeoutID) window.clearTimeout(timeoutID)
|
||||
this.popAlert()
|
||||
}
|
||||
const closeLink = L.DomUtil.create('a', 'umap-close-link', this._alert)
|
||||
closeLink.href = '#'
|
||||
L.DomUtil.add('i', 'umap-close-icon', closeLink)
|
||||
const label = L.DomUtil.create('span', '', closeLink)
|
||||
label.title = label.textContent = L._('Close')
|
||||
L.DomEvent.on(closeLink, 'click', L.DomEvent.stop).on(
|
||||
closeLink,
|
||||
'click',
|
||||
close,
|
||||
this
|
||||
)
|
||||
L.DomUtil.add('div', '', this._alert, e.content)
|
||||
if (e.actions) {
|
||||
let action
|
||||
let el
|
||||
for (let i = 0; i < e.actions.length; i++) {
|
||||
action = e.actions[i]
|
||||
el = L.DomUtil.element('a', { className: 'umap-action' }, this._alert)
|
||||
el.href = '#'
|
||||
el.textContent = action.label
|
||||
L.DomEvent.on(el, 'click', L.DomEvent.stop).on(el, 'click', close, this)
|
||||
if (action.callback)
|
||||
L.DomEvent.on(
|
||||
el,
|
||||
'click',
|
||||
action.callback,
|
||||
action.callbackContext || this.map
|
||||
)
|
||||
}
|
||||
}
|
||||
self.ALERT_ID = timeoutID = window.setTimeout(
|
||||
L.bind(close, this),
|
||||
e.duration || 3000
|
||||
)
|
||||
},
|
||||
|
||||
popAlert: function (e) {
|
||||
var self = this;
|
||||
if(!e) {
|
||||
if (this.ALERTS.length) e = this.ALERTS.pop();
|
||||
else return;
|
||||
}
|
||||
var timeoutID,
|
||||
level_class = e.level && e.level == 'info'? 'info': 'error';
|
||||
this._alert.innerHTML = '';
|
||||
L.DomUtil.addClass(this.parent, 'umap-alert');
|
||||
L.DomUtil.addClass(this._alert, level_class);
|
||||
var close = function () {
|
||||
if (timeoutID !== this.ALERT_ID) { return;} // Another alert has been forced
|
||||
this._alert.innerHTML = '';
|
||||
L.DomUtil.removeClass(this.parent, 'umap-alert');
|
||||
L.DomUtil.removeClass(this._alert, level_class);
|
||||
if (timeoutID) window.clearTimeout(timeoutID);
|
||||
this.popAlert();
|
||||
};
|
||||
var closeLink = L.DomUtil.create('a', 'umap-close-link', this._alert);
|
||||
closeLink.href = '#';
|
||||
L.DomUtil.add('i', 'umap-close-icon', closeLink);
|
||||
var label = L.DomUtil.create('span', '', closeLink);
|
||||
label.title = label.textContent = L._('Close');
|
||||
L.DomEvent.on(closeLink, 'click', L.DomEvent.stop)
|
||||
.on(closeLink, 'click', close, this);
|
||||
L.DomUtil.add('div', '', this._alert, e.content);
|
||||
if (e.actions) {
|
||||
var action, el;
|
||||
for (var i = 0; i < e.actions.length; i++) {
|
||||
action = e.actions[i];
|
||||
el = L.DomUtil.element('a', {'className': 'umap-action'}, this._alert);
|
||||
el.href = '#';
|
||||
el.textContent = action.label;
|
||||
L.DomEvent.on(el, 'click', L.DomEvent.stop)
|
||||
.on(el, 'click', close, this);
|
||||
if (action.callback) L.DomEvent.on(el, 'click', action.callback, action.callbackContext || this.map);
|
||||
}
|
||||
}
|
||||
self.ALERT_ID = timeoutID = window.setTimeout(L.bind(close, this), e.duration || 3000);
|
||||
},
|
||||
tooltip({ anchor, position, content, duration }) {
|
||||
this.TOOLTIP_ID = Math.random()
|
||||
const id = this.TOOLTIP_ID
|
||||
L.DomUtil.addClass(this.parent, 'umap-tooltip')
|
||||
if (anchor && position === 'top') this.anchorTooltipTop(anchor)
|
||||
else if (anchor && position === 'left') this.anchorTooltipLeft(anchor)
|
||||
else this.anchorTooltipAbsolute()
|
||||
this._tooltip.innerHTML = content
|
||||
function closeIt() {
|
||||
this.closeTooltip(id)
|
||||
}
|
||||
if (anchor) L.DomEvent.once(anchor, 'mouseout', closeIt, this)
|
||||
if (duration !== Infinity)
|
||||
window.setTimeout(L.bind(closeIt, this), duration || 3000)
|
||||
},
|
||||
|
||||
tooltip: function (e) {
|
||||
this.TOOLTIP_ID = Math.random();
|
||||
var id = this.TOOLTIP_ID;
|
||||
L.DomUtil.addClass(this.parent, 'umap-tooltip');
|
||||
if (e.anchor && e.position === 'top') this.anchorTooltipTop(e.anchor);
|
||||
else if (e.anchor && e.position === 'left') this.anchorTooltipLeft(e.anchor);
|
||||
else this.anchorTooltipAbsolute();
|
||||
this._tooltip.innerHTML = e.content;
|
||||
function closeIt () { this.closeTooltip(id); }
|
||||
if (e.anchor) L.DomEvent.once(e.anchor, 'mouseout', closeIt, this);
|
||||
if (e.duration !== Infinity) window.setTimeout(L.bind(closeIt, this), e.duration || 3000);
|
||||
},
|
||||
anchorTooltipAbsolute() {
|
||||
this._tooltip.className = ''
|
||||
const left =
|
||||
this.parent.offsetLeft +
|
||||
this.parent.clientWidth / 2 -
|
||||
this._tooltip.clientWidth / 2
|
||||
const top = this.parent.offsetTop + 75
|
||||
this.setTooltipPosition({ top, left })
|
||||
},
|
||||
|
||||
anchorTooltipAbsolute: function () {
|
||||
this._tooltip.className = '';
|
||||
var left = this.parent.offsetLeft + (this.parent.clientWidth / 2) - (this._tooltip.clientWidth / 2),
|
||||
top = this.parent.offsetTop + 75;
|
||||
this.setTooltipPosition({top: top, left: left});
|
||||
},
|
||||
anchorTooltipTop(el) {
|
||||
this._tooltip.className = 'tooltip-top'
|
||||
const coords = this.getPosition(el)
|
||||
this.setTooltipPosition({
|
||||
left: coords.left - 10,
|
||||
bottom: this.getDocHeight() - coords.top + 11,
|
||||
})
|
||||
},
|
||||
|
||||
anchorTooltipTop: function (el) {
|
||||
this._tooltip.className = 'tooltip-top';
|
||||
var coords = this.getPosition(el);
|
||||
this.setTooltipPosition({left: coords.left - 10, bottom: this.getDocHeight() - coords.top + 11});
|
||||
},
|
||||
anchorTooltipLeft(el) {
|
||||
this._tooltip.className = 'tooltip-left'
|
||||
const coords = this.getPosition(el)
|
||||
this.setTooltipPosition({
|
||||
top: coords.top,
|
||||
right: document.documentElement.offsetWidth - coords.left + 11,
|
||||
})
|
||||
},
|
||||
|
||||
anchorTooltipLeft: function (el) {
|
||||
this._tooltip.className = 'tooltip-left';
|
||||
var coords = this.getPosition(el);
|
||||
this.setTooltipPosition({top: coords.top, right: document.documentElement.offsetWidth - coords.left + 11});
|
||||
},
|
||||
closeTooltip(id) {
|
||||
if (id && id !== this.TOOLTIP_ID) return
|
||||
this._tooltip.innerHTML = ''
|
||||
L.DomUtil.removeClass(this.parent, 'umap-tooltip')
|
||||
},
|
||||
|
||||
closeTooltip: function (id) {
|
||||
if (id && id !== this.TOOLTIP_ID) return;
|
||||
this._tooltip.innerHTML = '';
|
||||
L.DomUtil.removeClass(this.parent, 'umap-tooltip');
|
||||
},
|
||||
getPosition(el) {
|
||||
return el.getBoundingClientRect()
|
||||
},
|
||||
|
||||
getPosition: function (el) {
|
||||
return el.getBoundingClientRect();
|
||||
},
|
||||
setTooltipPosition({ left, right, top, bottom }) {
|
||||
if (left) this._tooltip.style.left = `${left}px`
|
||||
else this._tooltip.style.left = 'initial'
|
||||
if (right) this._tooltip.style.right = `${right}px`
|
||||
else this._tooltip.style.right = 'initial'
|
||||
if (top) this._tooltip.style.top = `${top}px`
|
||||
else this._tooltip.style.top = 'initial'
|
||||
if (bottom) this._tooltip.style.bottom = `${bottom}px`
|
||||
else this._tooltip.style.bottom = 'initial'
|
||||
},
|
||||
|
||||
setTooltipPosition: function (coords) {
|
||||
if (coords.left) this._tooltip.style.left = coords.left + 'px';
|
||||
else this._tooltip.style.left = 'initial';
|
||||
if (coords.right) this._tooltip.style.right = coords.right + 'px';
|
||||
else this._tooltip.style.right = 'initial';
|
||||
if (coords.top) this._tooltip.style.top = coords.top + 'px';
|
||||
else this._tooltip.style.top = 'initial';
|
||||
if (coords.bottom) this._tooltip.style.bottom = coords.bottom + 'px';
|
||||
else this._tooltip.style.bottom = 'initial';
|
||||
},
|
||||
|
||||
getDocHeight: function () {
|
||||
var D = document;
|
||||
return Math.max(
|
||||
D.body.scrollHeight, D.documentElement.scrollHeight,
|
||||
D.body.offsetHeight, D.documentElement.offsetHeight,
|
||||
D.body.clientHeight, D.documentElement.clientHeight
|
||||
);
|
||||
},
|
||||
|
||||
});
|
||||
getDocHeight() {
|
||||
const D = document
|
||||
return Math.max(
|
||||
D.body.scrollHeight,
|
||||
D.documentElement.scrollHeight,
|
||||
D.body.offsetHeight,
|
||||
D.documentElement.offsetHeight,
|
||||
D.body.clientHeight,
|
||||
D.documentElement.clientHeight
|
||||
)
|
||||
},
|
||||
})
|
||||
|
|
|
@ -1,285 +1,291 @@
|
|||
L.U.Xhr = L.Evented.extend({
|
||||
initialize(ui) {
|
||||
this.ui = ui
|
||||
},
|
||||
|
||||
initialize: function (ui) {
|
||||
this.ui = ui;
|
||||
},
|
||||
|
||||
_wrapper: function () {
|
||||
var wrapper;
|
||||
if (window.XMLHttpRequest === undefined) {
|
||||
wrapper = function() {
|
||||
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) {
|
||||
var xhr = this._wrapper(), id = Math.random(), self = this;
|
||||
this.fire('dataloading', {id: id});
|
||||
var loaded = function () {self.fire('dataload', {id: id});};
|
||||
|
||||
_wrapper() {
|
||||
let wrapper
|
||||
if (window.XMLHttpRequest === undefined) {
|
||||
wrapper = () => {
|
||||
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
|
||||
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()
|
||||
},
|
||||
|
||||
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 (var name in settings.headers) {
|
||||
xhr.setRequestHeader(name, settings.headers[name]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
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) {
|
||||
var msg = L._('Woops! Someone else seems to have edited the data. You can save anyway, but this will erase the changes made by others.');
|
||||
var 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
|
||||
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) {
|
||||
var args = arguments,
|
||||
self = this;
|
||||
var default_options = {
|
||||
'async': true,
|
||||
'callback': null,
|
||||
'responseType': 'text',
|
||||
'data': null,
|
||||
'listen_form': null // optional form to listen in default callback
|
||||
};
|
||||
var settings = L.Util.extend({}, default_options, options);
|
||||
|
||||
if (verb === 'POST') {
|
||||
// find a way not to make this django specific
|
||||
var token = document.cookie.replace(/(?:(?:^|.*;\s*)csrftoken\s*\=\s*([^;]*).*$)|^.*$/, '$1');
|
||||
if (token) {
|
||||
settings.headers = settings.headers || {};
|
||||
settings.headers['X-CSRFToken'] = token;
|
||||
}
|
||||
}
|
||||
|
||||
var callback = function(responseText, response) {
|
||||
var 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 = {};
|
||||
var form = L.DomUtil.get(form_id);
|
||||
var 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) {
|
||||
var 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', function () {
|
||||
self.submit_form(form_id, options);
|
||||
});
|
||||
},
|
||||
|
||||
listen_link: function (link_id, options) {
|
||||
var link = L.DomUtil.get(link_id), self = this;
|
||||
if (link) {
|
||||
L.DomEvent
|
||||
.on(link, 'click', L.DomEvent.stop)
|
||||
.on(link, 'click', function () {
|
||||
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) {
|
||||
var 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) {
|
||||
var ui_options = {'data': data},
|
||||
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 (var 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
|
||||
var self = this;
|
||||
var proceed = function () {
|
||||
self.ui.closePanel();
|
||||
if (typeof args !== 'undefined') self._json.apply(self, args);
|
||||
else self.default_callback(data, {});
|
||||
};
|
||||
var ask_for_login = function (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
|
||||
var links = document.getElementsByClassName('umap-login-popup');
|
||||
Object.keys(links).forEach(function (el) {
|
||||
var link = links[el];
|
||||
L.DomEvent
|
||||
.on(link, 'click', L.DomEvent.stop)
|
||||
.on(link, 'click', function () {
|
||||
self.ui.closePanel();
|
||||
var win = window.open(link.href);
|
||||
window.umap_proceed = function () {
|
||||
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);
|
||||
_ajax(settings) {
|
||||
const xhr = this._wrapper()
|
||||
const id = Math.random()
|
||||
const self = this
|
||||
this.fire('dataloading', { id })
|
||||
const loaded = () => {
|
||||
self.fire('dataload', { 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() {
|
||||
delete settings.headers['If-Match']
|
||||
self._ajax(settings)
|
||||
},
|
||||
callbackContext: self,
|
||||
},
|
||||
{
|
||||
label: L._('Cancel'),
|
||||
},
|
||||
]
|
||||
self.ui.alert({ content: msg, level: 'error', duration: 100000, actions })
|
||||
} else {
|
||||
if (xhr.status !== 0) {
|
||||
// 0 === request cut by user
|
||||
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(verb, uri, options) {
|
||||
const args = arguments
|
||||
const 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,
|
||||
uri,
|
||||
data: settings.data,
|
||||
callback,
|
||||
headers: settings.headers,
|
||||
listener: settings.listener,
|
||||
})
|
||||
},
|
||||
|
||||
get(uri, options) {
|
||||
this._json('GET', uri, options)
|
||||
},
|
||||
|
||||
post(uri, options) {
|
||||
this._json('POST', uri, options)
|
||||
},
|
||||
|
||||
submit_form(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(form_id, options) {
|
||||
const form = L.DomUtil.get(form_id)
|
||||
const 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(link_id, options) {
|
||||
const link = L.DomUtil.get(link_id)
|
||||
const 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(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(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(...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(url) {
|
||||
this.get(url)
|
||||
},
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue