UNPKG

pragma-views2

Version:

385 lines (329 loc) 10.3 kB
import {selectionMode} from './../lib/selection-mode.js' import {BaseElement} from '../../baremetal/lib/base-element.js'; export class VisualizationBase extends BaseElement { constructor() { super(); this.dataSourceChangedHandler = this.dataSourceChanged.bind(this); } get batchSize() { return this._batchSize; } set batchSize(value) { this._batchSize = value; } get datasource() { return this._datasource; } set datasource(newValue) { if (newValue != undefined) { this._datasource = newValue; this._datasource.addRootItemsLoadedCallback(this.dataSourceChangedHandler); this.dataSourceChanged(newValue); } } get idField() { return this.getAttribute("id-field") || this._idField; } set idField(value) { this._idField = value; } get perspective() { return this.getAttribute("perspective") || this._perspective; } set perspective(newValue) { this._perspective = newValue; if (newValue != null) { this.getData({perspective: newValue}); } } get selectedId() { return this.getAttribute("selected-id") || this._selectedId; } set selectedId(newValue) { this._selectedId = newValue; this.notifyPropertyChanged("selectedId", newValue); } get selection() { return this.getAttribute("selection") || this._selection; } set selection(value) { this._selection = value; } /** * * @param event * @private */ _workerMessage(event) { const data = event.data; if (data.items.length > 0) { this.updateUI(data); } else { this.disposeWorker(data.id); } } /** * Called when the datasource is being processed * Sets the initial data collection that the derived class will use * Sets if the data structure is hierarchical */ async checkDatasourceStructure(data) { if (data == null) { return; } if (Array.isArray(data) && data.length > 0) { this.isHierarchical = data[0].constructor != undefined && data[0].constructor.name === "HierarchicalItem"; if (this.isHierarchical === true) { // NOTE JN: For Hierarchical data, when the root's child items are empty, perform a fetch if (data[0].depth === 0 && data[0].items == undefined) { await this._datasource.load(null, data[0]); } this.data = data[0].items; } else { this.data = data; } } else { if (data.hasOwnProperty("items")) { this.data = data.items; } } } /** * Override in derived class to provide functionality */ clear() { } /** * Reset the value of selected id based on the selection mode */ clearSelectedId() { if (this.selection === selectionMode.multiple) { this.selectedId = []; } else { this.selectedId = null; } } /** * Click event handler * @param event */ click(event) { } async connectedCallback() { this.initTemplate(); this.workers = new Map(); this.clickHandler = this.click.bind(this); this.doubleClickHandler = this.doubleClick.bind(this); this.keyUpHandler = this.keyUp.bind(this); this._workerMessageHandler = this._workerMessage.bind(this); this.addEventListener("click", this.clickHandler); this.addEventListener("dblclick", this.doubleClickHandler); this.addEventListener("keyup", this.keyUpHandler); } async dataSourceChanged(ds) { if (this._datasource == undefined) { return; } if (this._datasource.ready == true) { if (this.data != undefined) { this.clear(); } if (ds.definition.perspective == undefined) { return this.getData(null); } if (this.perspective != undefined) { this.getData({perspective: this.perspective}); } } } disconnectedCallback() { this.removeEventListener("click", this.clickHandler); this.removeEventListener("dblclick", this.doubleClickHandler); this.removeEventListener("keyup", this.keyUpHandler); this.clickHandler = null; this.doubleClickHandler = null; this.keyUpHandler = null; this.data = null; this.workers = null; this.isHierarchical = null; this._idField = null; this._datasource = null; this._batchSize = null; this._perspective = null; this._selectedId = null; this._selection = null; } /** * Raise custom events that can be consumed by callers * @param eventName * @param target */ dispatchCustomEvent(eventName, target) { const event = new CustomEvent(eventName, { detail: { selectedId: this.selectedId, target: target } }); this.dispatchEvent(event); } /** * Terminates a worker and removes it from the map * @param id */ disposeWorker(id) { if (this.workers.has(id)) { const composite = this.workers.get(id); composite.worker.terminate(); this.workers.delete(id); } } /** * Double click event handler * @param event */ doubleClick(event) { } async getData(perspective) { const data = await this._datasource.data(perspective); if (data != null) { this.data = data; this.update(data); } } /** * Get a instance of the template you want to load * Override this in the inherited component */ getTemplateInstance() { } /** * * @param id * @returns {*} */ getWorker(id) { if (this.workers.has(id)) { return this.workers.get(id); } const composite = { page: 0, worker: new Worker("./batch-worker.js") }; composite.worker.addEventListener("message", this._workerMessageHandler); this.workers.set(id, composite); return composite; } /** * Initialises the selection mode on the component * Selection mode can either be single or multi-select */ initSelectionMode() { const mode = this.selection == null ? selectionMode.multiple : selectionMode[this.selection]; const isArray = Array.isArray(this.selectedId) === true; this.classList.add(mode); if (mode === selectionMode.multiple) { if (this.selectedId != null && isArray === false) { console.error(`Incorrect component usage. Selected id should be an array when selection mode is ${mode}.`); } else { if (this.selectedId == null) { this.selectedId = []; } } } else if (this.selectedId != null && isArray) { console.error(`Incorrect component usage. Selected id cannot be an array when selection mode is ${mode}.`); } } /** * Load the component template */ initTemplate() { } /** * Checks if a value is selected * @param value: value to check * @returns {boolean} */ isSelected(value) { return Array.isArray(this.selectedId) === true ? this.selectedId.find(t => t == value) != null : this.selectedId == value; } /** * Keyup event handler * @param event */ keyUp(event) { } /** * Removes the child elements from a node in the DOM * @param parentElement */ removeChildren(parentElement) { while (parentElement.firstChild) { parentElement.removeChild(parentElement.firstChild); } } /** * Requests a batch of data from the batch-worker * for a specific id * @param data: Request data */ requestBatch(data) { const composite = this.getWorker(data.id); data.page = composite.page; composite.worker.postMessage(data); composite.page++; } /** * Sets the id value on selectedId. * If the selection state is multiselect the id is added * to the array otherwise selectedId is the id value * @param id: id to set * @param selected: selected status */ setSelectedId(id, selected) { if (this.selection === selectionMode.multiple) { if (selected === true) { const array = this.selectedId; array.push(id); this.selectedId = array; } else { const index = this.selectedId.indexOf(id); const array = this.selectedId; array.splice(index, 1); this.selectedId = array; } } else { this.selectedId = id; } } /** * Called when the data is ready on the datasource. * Handles the data based on the type * @param data */ async update(data) { await this.checkDatasourceStructure(data); const requestData = { dataset: this.data, id: "root", page: 0, size: this.batchSize }; this.requestBatch(requestData); } /** * Override in derived class to provide functionality */ updateUI() { } }