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