pragma-views2
Version:
385 lines (329 loc) • 10.3 kB
JavaScript
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() {
}
}