216 lines
7.0 KiB
JavaScript
216 lines
7.0 KiB
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 |