ol-ext
Version:
A set of cool extensions for OpenLayers (ol) in node modules structure
216 lines (213 loc) • 7.34 kB
JavaScript
import ol_Object from 'ol/Object.js';
import ol_ext_element from '../element.js'
/** A list element synchronize with a Collection.
* Element in the list can be reordered interactively and the associated Collection is kept up to date.
* @constructor
* @fires item:select
* @fires item:dblclick
* @fires item:keydown
* @fires item:order
* @extends {ol_Object}
* @param {*} options
* @param {Element} [options.target]
* @param {Collection} [options.collection] the collection to display in the list
* @param {function} [options.getTitle] a function that takes a collection item and returns an Element or a string
*/
var ol_ext_input_Collection = class olextinputCollection extends ol_Object {
constructor(options) {
super();
this.element = ol_ext_element.create('UL', {
className: ('ol-collection-list ' + (options.className || '')).trim(),
parent: options.target
});
this._title = (typeof (options.getTitle) === 'function' ? options.getTitle : function (elt) { return elt.title; });
this.setCollection(options.collection);
}
/** Remove current collection (listeners)
* /!\ remove collection when input list is removed from the DOM
*/
removeCollection() {
if (this.collection) {
this.collection.un('change:length', this._update);
this.collection = null;
}
}
/** Set the collection
* @param {ol_Collection} collection
*/
setCollection(collection) {
this.removeCollection();
this.collection = collection;
this.refresh();
if (this.collection) {
this._update = function () {
if (!this._reorder) {
this.refresh();
var pos = this.getSelectPosition();
if (pos < 0) {
this.dispatchEvent({ type: 'item:select', position: -1, item: null });
} else {
this.dispatchEvent({ type: 'item:order', position: pos, item: this._currentItem });
}
}
}.bind(this);
this.collection.on('change:length', this._update);
}
}
/** Select an item
* @param {*} item
*/
select(item) {
if (item === this._currentItem)
return;
var pos = -1;
this._listElt.forEach(function (l, i) {
if (l.item !== item) {
l.li.classList.remove('ol-select');
} else {
l.li.classList.add('ol-select');
pos = i;
}
});
this._currentItem = (pos >= 0 ? item : null);
this.dispatchEvent({ type: 'item:select', position: pos, item: this._currentItem });
}
/** Select an item at
* @param {number} n
*/
selectAt(n) {
this.select(this.collection.item(n));
}
/** Get current selection
* @returns {*}
*/
getSelect() {
return this._currentItem;
}
/** Get current selection
* @returns {number}
*/
getSelectPosition() {
if (!this.collection)
return -1;
return this.collection.getArray().indexOf(this._currentItem);
}
/** Redraw the list
* @param {*} [focus] item to focus on
*/
refresh(focus) {
this.element.innerHTML = '';
this._listElt = [];
if (!this.collection)
return;
this.collection.forEach((item, pos) => {
var li = ol_ext_element.create('LI', {
html: this._title(item),
className: this._currentItem === item ? 'ol-select' : '',
'data-position': pos,
on: {
click: function () {
this.select(item);
}.bind(this),
dblclick: function () {
this.dispatchEvent({ type: 'item:dblclick', position: pos, item: item });
}.bind(this),
},
parent: this.element
});
// Accessibility
var check = ol_ext_element.create('INPUT', {
'aria-label': this._title(item),
type: 'checkbox',
className: 'ol-input-focus',
on: {
keydown: function(e) {
switch (e.key) {
// Move up dans down
case 'ArrowUp':
case 'ArrowDown': {
if (e.ctrlKey) {
e.preventDefault();
e.stopPropagation();
this.select(item);
var newPos = (e.key === 'ArrowUp' ? pos-1 : pos+1);
if (newPos >= 0 && newPos < this.collection.getLength()) {
this._reorder = true;
this.collection.removeAt(pos);
this.collection.insertAt(newPos, item);
this._reorder = false;
this.dispatchEvent({ type: 'item:order', position: newPos, oldPosition: pos, item: item });
this.refresh(item);
}
}
break;
}
// Select
case ' ':
case 'Space': {
e.preventDefault();
e.stopPropagation();
this.select(item);
break;
}
case 'Tab': {
break;
}
default: {
this.dispatchEvent({ type: 'item:keydown', key: e.key, originalEvent: e, position: pos, item: item })
break;
}
}
}.bind(this)
},
parent: li
})
if (focus === item) {
check.focus();
}
this._listElt.push({ li: li, item: item });
var order = ol_ext_element.create('DIV', {
className: 'ol-noscroll ol-order',
parent: li
});
var current = pos;
var move = function (e) {
// Get target
var target = e.pointerType === 'touch' ? document.elementFromPoint(e.clientX, e.clientY) : e.target;
while (target && target.parentNode !== this.element) {
target = target.parentNode;
}
if (target && target !== li) {
var over = parseInt(target.getAttribute('data-position'));
if (target.getAttribute('data-position') < current) {
target.insertAdjacentElement('beforebegin', li);
current = over;
} else {
target.insertAdjacentElement('afterend', li);
current = over + 1;
}
}
}.bind(this);
var stop = function () {
document.removeEventListener('pointermove', move);
document.removeEventListener('pointerup', stop);
document.removeEventListener('pointercancel', stop);
if (current !== pos) {
this._reorder = true;
this.collection.removeAt(pos);
this.collection.insertAt(current > pos ? current - 1 : current, item);
this._reorder = false;
this.dispatchEvent({ type: 'item:order', position: current > pos ? current - 1 : current, oldPosition: pos, item: item });
this.refresh();
}
}.bind(this);
order.addEventListener('pointerdown', function () {
this.select(item);
document.addEventListener('pointermove', move);
document.addEventListener('pointerup', stop);
document.addEventListener('pointercancel', stop);
}.bind(this));
});
}
}
export default ol_ext_input_Collection