UNPKG

jahmin

Version:

A JavaScript framework to build browser friendly Human Machine Interfaces for automation

144 lines (128 loc) 4.48 kB
import {LitElement} from 'lit-element' import {litStatesMixin} from 'impera-js' import {Manager, ServiceManager} from '../ServiceManager.js' import { systemObject, systemVariable, VarStatusCodes } from '../DataModels/Types.js'; export interface props { [key:string] : { type : String | Number | Object } } export class hmiElement extends litStatesMixin([Manager.dataTree, Manager.errorTray],LitElement) implements systemObject{ name : string system : string engine : string datatree : any _init : boolean service_manager : ServiceManager _local_status : string _local_value : any constructor(){ super(); this.name = ""; this.system = "default"; this.engine = "default"; this._init = false; this.service_manager = Manager; this._local_status = "UNDEFINED"; this._local_value = undefined; } static get properties() : props{ return { name : { type: String }, system : { type: String }, engine : { type: String }, /* this would be nice to have so that one could set status of a child component declaratively from the code of the host, but PROBLEM: lit-Element overrides getter and setter of inherited props in case the "get properties" is redefined in the child class, in short if you want to add props in a child class the status prop will not work. */ // status : { type: String } }; } get value():any { if(!this._init) return undefined; if(this.service_manager.dataTree.ExistVar(this)) return this.datatree[this.system][this.name].value; else return null; } get status():string { if(!this._init) return VarStatusCodes.Pending; if(this.service_manager.dataTree.ExistVar(this)) return this.datatree[this.system][this.name].status; else return VarStatusCodes.Error; } set status(Status:string) { if(typeof Status !== "string") return; if(!this.service_manager.dataTree.ExistVar(this)) return; const old_val = this.getAttribute("status"); if( old_val !== Status || old_val !== this.status ) { this.DataUpdate(null,Status); } } on_datatree_update() { this.setAttribute("status",this.status); if( this.status !== this._local_status ) { let Ev = new CustomEvent("status-changed",{ bubbles:true, composed:true, cancelable:true, detail:{newStatus : this.status , oldStatus : this._local_status} }); this._local_status = this.status; this.dispatchEvent(Ev); } if(this.value !== this._local_value){ let Ev = new CustomEvent("value-changed",{ bubbles:true, composed:true, cancelable:true, detail: { newValue : this.value , oldValue : this._local_value } }); this._local_value = this.value; this.dispatchEvent(Ev); } } connectedCallback() { super.connectedCallback(); this.subscribe() } subscribe() { // maybe here dispatch READY event?? // maybe here resolve a READY promise so one can await it?? Manager.Subscribe(this.engine,this).then(()=>{ this._init = true; this.on_datatree_update(); this.requestUpdate(); }) } disconnectedCallback() { if(super.disconnectedCallback) super.disconnectedCallback(); Manager.Unsubscribe(this.engine, this); } async Write(value:any) { return await this.WriteMultiple([this],[value]); } async WriteMultiple(targets:systemObject[],values:any[]) { return await Manager.Write(this.engine, targets, values); } async Read() { return this.ReadMultiple([this]); } async ReadMultiple(targets:systemObject[]) { return await Manager.Read(this.engine,targets); } DataUpdate(Value:any, Status:string):void { let sysVar = new systemVariable(this); sysVar.status = Status; sysVar.value = Value; this.DataUpdateMultiple(sysVar); } DataUpdateMultiple(sysvar:systemVariable[]|systemVariable):void { Manager.Update(sysvar) } } customElements.define("hmi-element",hmiElement);