Comparing version 0.18.1 to 0.19.0
94
bkb.d.ts
@@ -18,3 +18,3 @@ export function createApplication<A>(Class: { new (dash: ApplicationDash<A>, ...args: any[]): A }, ...args: any[]): A | ||
disable(): void | ||
isDisabled(): boolean | ||
readonly isDisabled: boolean | ||
} | ||
@@ -26,5 +26,8 @@ | ||
export interface ChildFilter { | ||
export interface FindChildOptions { | ||
group?: string | string[] | ||
filter?: (child: any) => boolean | ||
} | ||
export interface ListenChildOptions extends FindChildOptions { | ||
/** | ||
@@ -36,13 +39,2 @@ * Default value is <code>false</code> | ||
export interface CreateComponentProperties<A = any, C = any> { | ||
Class: { new(dash: Dash<A>, ...args: any[]): C }, | ||
arguments?: any[] | ||
argument?: any | ||
group?: string | string[] | ||
} | ||
export interface AsComponentProperties { | ||
group?: string | string[] | ||
} | ||
export interface EmitterOptions { | ||
@@ -55,24 +47,41 @@ /** | ||
export interface Bkb { | ||
onEvent<D = any>(eventName: string, callback: (ev: ComponentEvent<D>) => void, thisArg?: any): this | ||
onData<D = any>(eventName: string, callback: (data: D, ev: ComponentEvent<D>) => void, thisArg?: any): this | ||
listen<D = any>(eventName: string): Transmitter<D> | ||
interface ApplicationMembers { | ||
/** | ||
* This method is inherited from the application. | ||
*/ | ||
isComponent(obj: object): boolean | ||
/** | ||
* This method is inherited from the application. | ||
*/ | ||
getPublicDashOf(component: object): PublicDash | ||
/** | ||
* This member is inherited from the application. | ||
*/ | ||
readonly log: Log | ||
} | ||
export interface PublicDash extends ApplicationMembers { | ||
onEvent<D = any>(eventName: string | string[], callback: (ev: ComponentEvent<D>) => void, thisArg?: any): this | ||
onData<D = any>(eventName: string | string[], callback: (data: D, ev: ComponentEvent<D>) => void, thisArg?: any): this | ||
listen<D = any>(eventName: string | string[]): Transmitter<D> | ||
/** | ||
* Find children | ||
*/ | ||
find<C = any>(filter?: ChildFilter): C[] | ||
children<C = any>(filter?: FindChildOptions): C[] | ||
/** | ||
* Find a single child (an Error is thrown if there isn't one result) | ||
* Find a single child (or throws an Error if there isn't one result) | ||
*/ | ||
findSingle<C = any>(filter?: ChildFilter): C | ||
getChild<C = any>(filter?: FindChildOptions): C | ||
/** | ||
* @returns The count of children that validate the filter | ||
*/ | ||
count(filter?: ChildFilter): number | ||
countChildren(filter?: FindChildOptions): number | ||
/** | ||
* @returns true if there is one or more children that validate the filter | ||
*/ | ||
has(filter?: ChildFilter): boolean | ||
hasChildren(filter?: FindChildOptions): boolean | ||
isChild(obj: object): boolean | ||
destroy(): void | ||
@@ -92,9 +101,9 @@ | ||
getParent(filter?: ParentFilter): object | undefined | ||
/** | ||
* This method is available only when the targeted parent instances are defined: after the initialisation, or after a call of `setInstance()` from their dash. | ||
*/ | ||
getAllParents(filter?: ParentFilter): object[] | ||
} | ||
export interface ApplicationBkb extends Bkb { | ||
readonly log: Log | ||
} | ||
export interface BasicDash<A = any> extends Bkb { | ||
export interface BasicDash<A = any> extends PublicDash { | ||
/** | ||
@@ -105,9 +114,11 @@ * Call this method if the instance must be available during the execution of the constructor | ||
exposeEvents(...eventNames: string[]): this | ||
exposeEvents(eventNames: string[]): this | ||
exposeEvent(...eventNames: string[]): this | ||
exposeEvent(eventNames: string[]): this | ||
create<C>(Class: { new(dash: Dash<A>, ...args: any[]): C }, ...args: any[]): C | ||
customCreate<C>(properties: CreateComponentProperties<A, C>): C | ||
asComponent(obj: object, properties?: AsComponentProperties): Dash<A> | ||
asComponent(obj: object): Dash<A> | ||
addToGroup(child: object, group: string, ...groups: string[]): this | ||
isInGroup(child: object, group: string, ...groups: string[]): boolean | ||
/** | ||
@@ -132,4 +143,6 @@ * If the option `sync` is activated, the method is allowed only when the component instance is defined: after the initialisation, or after a call of `setInstance()`. | ||
*/ | ||
listenToParent<D = any>(eventName: string, filter?: ParentFilter): Transmitter<D> | ||
listenToParent<D = any>(eventName: string | string[], filter?: ParentFilter): Transmitter<D> | ||
listenToAllParents<D = any>(eventName: string | string[], filter?: ParentFilter): Transmitter<D> | ||
/** | ||
@@ -139,19 +152,18 @@ * Listen the children and descendants. If the parameter <code>filter<code> is defined, listen only the children or | ||
*/ | ||
listenToChildren<D = any>(eventName: string, filter?: ChildFilter): Transmitter<D> | ||
listenToChildren<D = any>(eventName: string | string[], filter?: ListenChildOptions): Transmitter<D> | ||
listenTo<D = any>(component: object, eventName: string): Transmitter<D> | ||
listenTo<D = any>(component: object, eventName: string | string[]): Transmitter<D> | ||
readonly log: Log | ||
getBkbOf(component: object): Bkb | ||
destroyChildren(filter?: FindChildOptions): this | ||
readonly publicDash: PublicDash | ||
} | ||
export interface ApplicationDash<A = any> extends BasicDash<A> { | ||
} | ||
export interface Dash<A = any> extends BasicDash<A> { | ||
readonly app: A | ||
readonly bkb: Bkb | ||
} | ||
export interface ApplicationDash<A = any> extends BasicDash<A>, ApplicationBkb { | ||
readonly bkb: ApplicationBkb | ||
} | ||
/** | ||
@@ -158,0 +170,0 @@ * The type of data for log event |
@@ -1,1 +0,1 @@ | ||
function call(t,e){switch(t.mode){case"data":t.thisArg?t.cb.call(t.thisArg,e.data,e):t.cb(e.data,e);break;case"event":default:t.thisArg?t.cb.call(t.thisArg,e):t.cb(e)}}function makeBkb(t,e){let n={get instance(){return t.getInstance()},get parent(){return this.getParent()},getParent:function(e){let n=t.getParent(e);return n?n.getInstance():void 0},onData:function(e,n,s){return t.emitter.listen(e).onData(n,s),this},onEvent:function(e,n,s){return t.emitter.listen(e).onEvent(n,s),this},listen:e=>t.emitter.listen(e),destroy:()=>t.destroy(),find:(e={})=>t.find(e),findSingle:(e={})=>t.findSingle(e),count:(e={})=>t.count(e),has:(e={})=>t.has(e)};return e&&Object.assign(n,e),Object.freeze(n),n}function makeDash(t,e){let n={setInstance:e=>{t.setInstance(e)},exposeEvents:function(...e){let n=1===e.length&&Array.isArray(e[0])?e[0]:e;return t.emitter.exposeEvents(n,!0),this},create:(e,...n)=>t.createChild({asObj:!1,props:{Class:e,arguments:n}}).getInstance(),customCreate:e=>t.createChild({asObj:!1,props:e}).getInstance(),asComponent:(e,n={})=>t.createChild({asObj:!0,props:n,obj:e}).dash,emit:function(e,n,s){let i=Array.isArray(e)?e:[e];for(let e of i)t.emit(e,n,s);return this},broadcast:function(e,n){return t.broadcast(e,n),this},listenToParent:(e,n)=>t.listenToParent(e,n),listenToChildren:(e,n)=>t.childEmitter.listen(e,n),listenTo:(e,n)=>t.listenTo(e,n),getBkbOf:e=>t.app.getContainerByInst(e).bkb,bkb:e};e.log||(n.log=t.app.log);let s=Object.assign(Object.create(e),n);return t.app.root&&t.app.root!==t&&Object.defineProperties(s,{app:{get:()=>t.app.root.getInstance()}}),Object.freeze(s),s}function createApplication(t,...e){return new ApplicationContainer(t,!1,e).root.getInstance()}function asApplication(t){return new ApplicationContainer(t,!0).root.dash}class Emitter{constructor(t,e){this.app=t,this.strictEvents=!1,this.destroyed=!1,this.fromEolCancelers=[],e&&this.exposeEvents(e,!1)}static empty(){let t={onData:()=>t,onEvent:()=>t,disable:()=>{},isDisabled:()=>!1};return t}exposeEvents(t,e){if(this.destroyed)throw new Error(`Cannot call exposeEvents in a destroyed transmitter`);this.eventNames||(this.eventNames=new Set);for(let e of t)this.eventNames.add(e);e&&(this.strictEvents=!0)}emit(t){if(!this.callbacks)return;if(this.strictEvents&&this.eventNames&&!this.eventNames.has(t.eventName))throw new Error(`Unexposed event: ${t.eventName}`);let e=this.callbacks.get(t.eventName);e&&this.callCbList(e,t)}listen(t,e){if(this.destroyed||!this.fromEolCancelers)throw new Error(`Cannot call listen in a destroyed emitter`);if(e&&!e.bkb)throw new Error(`Cannot call listen from a destroyed component`);this.callbacks||(this.callbacks=new Map);let n=[],s=()=>this.destroyed||!n;const i=(e,s,i)=>{if(this.destroyed||!n||!this.callbacks)return o;let r=this.callbacks.get(t);r||this.callbacks.set(t,r=[]);let a=r.length;n.push(a),r[a]={mode:e,cb:s,thisArg:i}};let r,o={onEvent:(t,e)=>(i("event",t,e),o),onData:(t,e)=>(i("data",t,e),o),disable:()=>{if(s()||!this.callbacks)return;let e=this.callbacks.get(t);if(e)for(let t of n)delete e[t];n=null,r&&(r(),r=null)},isDisabled:s};if(e){let t=e.bkb.listen("destroy").onEvent(()=>o.disable()),n=this.fromEolCancelers.length;this.fromEolCancelers[n]=t,r=(()=>{t.disable(),this.fromEolCancelers&&delete this.fromEolCancelers[n]})}else r=null;return o}destroy(){if(this.fromEolCancelers)for(let t in this.fromEolCancelers)this.fromEolCancelers.hasOwnProperty(t)&&this.fromEolCancelers[t].disable();this.fromEolCancelers=null,this.callbacks=null,this.eventNames=null,this.destroyed=!0}callCbList(t,e){for(let n in t)if(t.hasOwnProperty(n))try{call(t[n],e)}catch(t){this.app.errorHandler(t)}}}class ChildEmitter{constructor(t){this.app=t,this.destroyed=!1}emit(t,e,n){if(!this.callbacks)return;let s=this.callbacks.get(t.eventName);if(!s)return;let i=[];for(let r of s)r.filter.filter&&r.filter.filter(t.source)||!r.filter.deep&&e||r.filter.group&&!ChildEmitter.hasGroup(r.filter.group,n)||i.push(r);this.callCbList(i,t)}listen(t,e={}){if(this.destroyed)throw new Error("Cannot call 'listen' in a destroyed child-emitter");this.callbacks||(this.callbacks=new Map);let n=[],s=()=>this.destroyed||!n;const i=(s,i,o)=>{if(this.destroyed||!n||!this.callbacks)return r;let a=this.callbacks.get(t);a||this.callbacks.set(t,a=[]);let l=a.length;n.push(l),a[l]={mode:s,cb:i,thisArg:o,filter:e}};let r={onEvent:(t,e)=>(i("event",t,e),r),onData:(t,e)=>(i("data",t,e),r),disable:()=>{if(s()||!this.callbacks)return;let e=this.callbacks.get(t);if(e)for(let t of n)delete e[t];n=null},isDisabled:s};return r}destroy(){this.callbacks=null,this.destroyed=!0}static hasGroup(t,e){let n="string"==typeof t?[t]:t;for(let t of n)if(e.has(t))return!0;return!1}callCbList(t,e){for(let n of t)try{call(n,e)}catch(t){this.app.errorHandler(t)}}}class Container{constructor(t,e,n){this.app=t,this.componentId=e,this.emitter=new Emitter(t,["destroy"]),this.childEmitter=new ChildEmitter(t),this.bkb=makeBkb(this,n),this.dash=makeDash(this,this.bkb)}makeInstance(t,e){return this.inst?this.inst:this.setInstance(new t(this.dash,...e))}setInstance(t){if(this.inst)return this.inst;if(!this.bkb)throw new Error(`Destroyed component`);return this.inst=t,t}getInstance(){if(!this.inst){if(this.bkb)throw new Error(`The component instance is still not initialized`);throw new Error("Destroyed component")}return this.inst}destroy(){this.emit("destroy",void 0,{sync:!0}),this.app.removeComponent(this,this.inst),this.childGroups&&this.childGroups.clear(),this.emitter.destroy(),this.childEmitter.destroy(),this.bkb=void 0,this.dash=void 0,this.inst=void 0}forgetChild(t){if(this.childGroups)for(let e of this.childGroups.values())e.delete(t)}createChild(t){let e=this.app.createComponent(t,this);if(t.props.group){this.childGroups||(this.childGroups=new Map);let n="string"==typeof t.props.group?[t.props.group]:t.props.group;for(let t of n){let n=this.childGroups.get(t);n||this.childGroups.set(t,n=new Set),n.add(e.componentId)}}return e}broadcast(t,e){e&&e.sync?this.emitter.emit(t):this.app.asyncCall(()=>this.emitter.emit(t))}emit(t,e,n){n&&n.sync?this.emitSync(this.createEvent(t,e)):this.app.asyncCall(()=>this.emitSync(this.createEvent(t,e)))}createEvent(t,e){let n=this,s=!0;return Object.freeze({eventName:t,get source(){return n.getInstance()},data:e,stopPropagation:()=>{s=!1},[Container.canPropagateSymb]:()=>s})}emitSync(t){this.emitter.emit(t);let e=this.app.getParentOf(this.componentId);e&&e.bubbleUpEvent(t,!1,this.componentId)}bubbleUpEvent(t,e,n){if(t[Container.canPropagateSymb]&&!t[Container.canPropagateSymb]())return;this.childEmitter.emit(t,e,this.getGroupsOf(n));let s=this.app.getParentOf(this.componentId);s&&s.bubbleUpEvent(t,!0,this.componentId)}listenToParent(t,e){let n=this.getParent(e);if(n)return n.emitter.listen(t,this);if(e)throw new Error(`Cannot find the filtered parent`);return Emitter.empty()}listenTo(t,e){return this.app.getContainerByInst(t).emitter.listen(e,this)}getGroupsOf(t){let e=new Set;if(this.childGroups)for(let[n,s]of Array.from(this.childGroups.entries()))s.has(t)&&e.add(n);return e}getParent(t){let e=this;for(;e=this.app.getParentOf(e.componentId);)if(!t||t(e))return e}find(t){if(t.deep)throw new Error(`Cannot call "find" with filter deep`);let e=this.getChildContainers(t.group),n=[];for(let s of e)t.filter&&!t.filter(s)||n.push(s.getInstance());return n}findSingle(t){let e=this.find(t);if(1!==e.length)throw new Error(`Cannot find single ${JSON.stringify(t)} in component ${this.componentId}`);return e[0]}count(t){return this.find(t).length}has(t){return this.count(t)>0}getChildContainers(t){if(!t)return this.app.getChildrenOf(this.componentId);if(!this.childGroups)return[];let e="string"==typeof t?[t]:t,n=new Set;for(let t of e){let e=this.childGroups.get(t);if(e)for(let t of e.values())n.add(t)}let s=[];for(let t of n.values())s.push(this.app.getContainer(t));return s}}Container.canPropagateSymb=Symbol("canPropagate");class ApplicationContainer{constructor(t,e,n){this.compCount=0,this.nodesByInst=new WeakMap,this.nodes=new Map,this.tickList=null,this.insideRmComp=!1;let s=["error","warn","info","debug","trace"],i=this.newId();this.log=this.createLog(s),this.root=new Container(this,i,{log:this.log});let r={container:this.root};this.nodes.set(i,r),this.root.emitter.exposeEvents(["log",...s,"addComponent","removeComponent","changeComponent"],!1);let o=e?this.root.setInstance(t):this.root.makeInstance(t,n||[]);this.nodesByInst.set(o,r)}getParentOf(t){let e=this.findNode(t);return e.parent?e.parent.container:void 0}getChildrenOf(t){let e=[],n=this.findNode(t).children;if(n)for(let t of Array.from(n.values()))e.push(t.container);return e}getContainer(t){return this.findNode(t).container}getContainerByInst(t){return this.findNodeByInst(t).container}createComponent(t,e){if(!this.root.dash)throw new Error("Destroyed root component");let n=this.newId(),s=new Container(this,n),i=this.findNode(e.componentId),r={container:s,parent:i};this.nodes.set(n,r),i.children||(i.children=new Map),i.children.set(n,r);let o;if(t.asObj)o=s.setInstance(t.obj);else{let e=t.props.arguments||(t.props.argument?[t.props.argument]:[]);o=s.makeInstance(t.props.Class,e)}return this.nodesByInst.set(o,r),this.root.dash.emit("addComponent",{component:s.getInstance()}),this.root.dash.emit("changeComponent",{component:s.getInstance(),type:"add"}),s}removeComponent(t,e){if(!this.root.dash)throw new Error("Destroyed root component");let n=!this.insideRmComp;try{n&&(this.insideRmComp=!0,this.root.dash.emit("removeComponent",{component:t.getInstance()},{sync:!0}),this.root.dash.emit("changeComponent",{component:t.getInstance(),type:"remove"},{sync:!0}));let s=t.componentId,i=this.findNode(s);if(i.children){for(let t of Array.from(i.children.values()))t.parent=null,t.container.destroy();i.children.clear()}i.parent&&(i.parent.container.forgetChild(s),i.parent.children.delete(s)),this.nodes.delete(s),e&&this.nodesByInst.delete(e)}finally{n&&(this.insideRmComp=!1)}}errorHandler(t){if(!this.root.dash)throw new Error("Destroyed root component");this.root.dash.emit("log",{type:"error",messages:[t]},{sync:!0})}asyncCall(t){this.tickList?this.tickList.push(t):(this.tickList=[t],setTimeout(()=>{if(this.tickList){for(let t of this.tickList)try{t()}catch(t){this.errorHandler(t)}this.tickList=null}},0))}findNode(t){let e=this.nodes.get(t);if(!e)throw new Error(`Missing node of component "${t}"`);return e}findNodeByInst(t){let e=this.nodesByInst.get(t);if(!e)throw new Error(`Cannot find a component for the instance: ${t}`);return e}newId(){return this.compCount++}createLog(t){let e={};for(let n of t)e[n]=((...t)=>{if(!this.root.dash)throw new Error("Destroyed root component");this.root.dash.emit("log",{type:n,messages:t},{sync:!0})});return Object.freeze(e)}}export{createApplication,asApplication}; | ||
function call(t,e){switch(t.mode){case"data":t.thisArg?t.cb.call(t.thisArg,e.data,e):t.cb(e.data,e);break;case"event":default:t.thisArg?t.cb.call(t.thisArg,e):t.cb(e)}}function createMultiTransmitter(t){let e=!1;return{onData(e,n){return t.forEach(t=>t.onData(e,n)),this},onEvent(e,n){return t.forEach(t=>t.onEvent(e,n)),this},disable(){e=!0,t.forEach(t=>t.disable())},get isDisabled(){return e}}}function makePublicDash(t){let e={get instance(){return t.getInstance()},get parent(){return e.getParent()},getParent:function(e){let n=t.getParent(e);return n?n.getInstance():void 0},getAllParents:e=>t.getAllParents(e).map(t=>t.getInstance()),onData:function(n,r,i){return t.emitter.listen(n).onData(r,i),e},onEvent:function(n,r,i){return t.emitter.listen(n).onEvent(r,i),e},listen:e=>t.emitter.listen(e),destroy:()=>t.destroy(),children:(e={})=>t.getChildren(e),getChild:(e={})=>t.getChild(e),countChildren:(e={})=>t.countChildren(e),hasChildren:(e={})=>t.hasChildren(e),isChild:e=>t.isChild(e),isComponent:e=>t.app.isComponent(e),getPublicDashOf:e=>t.app.getContainerByInst(e).pub,log:t.app.log};return Object.freeze(e),e}function makeDash(t,e){let n={setInstance:e=>{t.setInstance(e)},exposeEvent:function(...e){let n=1===e.length&&Array.isArray(e[0])?e[0]:e;return t.emitter.exposeEvent(n,!0),r},create:(e,...n)=>t.createChild({asObj:!1,Class:e,args:n}).getInstance(),asComponent:e=>t.createChild({asObj:!0,obj:e}).dash,addToGroup:(e,...n)=>(t.addToGroup(e,...n),r),isInGroup:(e,...n)=>t.isInGroup(e,...n),emit:function(e,n,i){let s=Array.isArray(e)?e:[e];for(let e of s)t.emit(e,n,i);return r},broadcast:function(e,n){return t.broadcast(e,n),r},listenToParent:(e,n)=>t.listenToParent(e,n),listenToAllParents:(e,n)=>t.listenToAllParents(e,n),listenToChildren:(e,n)=>t.childEmitter.listen(e,n),listenTo:(e,n)=>t.listenTo(e,n),destroyChildren:(e={})=>(t.destroyChildren(e),r),publicDash:e},r=Object.assign(Object.create(e),n);return t.app.root&&t.app.root!==t&&Object.defineProperties(r,{app:{get:()=>t.app.root.getInstance()}}),Object.freeze(r),r}function createApplication(t,...e){return new ApplicationContainer(t,!1,e).root.getInstance()}function asApplication(t){return new ApplicationContainer(t,!0).root.dash}class Emitter{constructor(t,e){this.app=t,this.strictEvents=!1,this.destroyed=!1,this.fromEolCancelers=[],e&&this.exposeEvent(e,!1)}static empty(){let t={onData:()=>t,onEvent:()=>t,disable:()=>{},get isDisabled(){return!1}};return t}exposeEvent(t,e){if(this.destroyed)throw new Error(`Cannot call exposeEvent in a destroyed transmitter`);this.eventNames||(this.eventNames=new Set);for(let e of t)this.eventNames.add(e);e&&(this.strictEvents=!0)}emit(t){if(!this.callbacks)return;if(this.strictEvents&&this.eventNames&&!this.eventNames.has(t.eventName))throw new Error(`Unexposed event: ${t.eventName}`);let e=this.callbacks.get(t.eventName);e&&this.callCbList(e,t)}listen(t,e){if(this.destroyed||!this.fromEolCancelers)throw new Error(`Cannot call listen in a destroyed emitter`);if(e&&!e.pub)throw new Error(`Cannot call listen from a destroyed component`);"string"==typeof t&&(t=[t]),this.callbacks||(this.callbacks=new Map);let n=[],r=()=>this.destroyed||!n;const i=(e,r,i)=>{if(this.destroyed||!n||!this.callbacks)return o;for(let s of t){let t=this.callbacks.get(s);t||this.callbacks.set(s,t=[]);let o=t.length;n.push(o),t[o]={mode:e,cb:r,thisArg:i}}};let s,o={onEvent:(t,e)=>(i("event",t,e),o),onData:(t,e)=>(i("data",t,e),o),disable:()=>{if(!r()&&this.callbacks){for(let e of t){let t=this.callbacks.get(e);if(t)for(let e of n)delete t[e]}n=null,s&&(s(),s=null)}},get isDisabled(){return r()}};if(e){let t=e.pub.listen("destroy").onEvent(()=>o.disable()),n=this.fromEolCancelers.length;this.fromEolCancelers[n]=t,s=(()=>{t.disable(),this.fromEolCancelers&&delete this.fromEolCancelers[n]})}else s=null;return o}destroy(){if(this.fromEolCancelers)for(let t in this.fromEolCancelers)this.fromEolCancelers.hasOwnProperty(t)&&this.fromEolCancelers[t].disable();this.fromEolCancelers=null,this.callbacks=null,this.eventNames=null,this.destroyed=!0}callCbList(t,e){for(let n in t)if(t.hasOwnProperty(n))try{call(t[n],e)}catch(t){this.app.errorHandler(t)}}}class ChildEmitter{constructor(t){this.app=t,this.destroyed=!1}emit(t,e,n){if(!this.callbacks)return;let r=this.callbacks.get(t.eventName);if(!r)return;let i=[];for(let s of r)s.filter.filter&&s.filter.filter(t.source)||!s.filter.deep&&e||s.filter.group&&!ChildEmitter.hasGroup(s.filter.group,n)||i.push(s);this.callCbList(i,t)}listen(t,e={}){if(this.destroyed)throw new Error("Cannot call 'listen' in a destroyed child-emitter");"string"==typeof t&&(t=[t]),this.callbacks||(this.callbacks=new Map);let n=[],r=()=>this.destroyed||!n;const i=(r,i,o)=>{if(this.destroyed||!n||!this.callbacks)return s;for(let s of t){let t=this.callbacks.get(s);t||this.callbacks.set(s,t=[]);let a=t.length;n.push(a),t[a]={mode:r,cb:i,thisArg:o,filter:e}}};let s={onEvent:(t,e)=>(i("event",t,e),s),onData:(t,e)=>(i("data",t,e),s),disable:()=>{if(!r()&&this.callbacks){for(let e of t){let t=this.callbacks.get(e);if(t)for(let e of n)delete t[e]}n=null}},get isDisabled(){return r()}};return s}destroy(){this.callbacks=null,this.destroyed=!0}static hasGroup(t,e){let n="string"==typeof t?[t]:t;for(let t of n)if(e.has(t))return!0;return!1}callCbList(t,e){for(let n of t)try{call(n,e)}catch(t){this.app.errorHandler(t)}}}class Container{constructor(t,e){this.app=t,this.componentId=e,this.emitter=new Emitter(t,["destroy"]),this.childEmitter=new ChildEmitter(t),this.pub=makePublicDash(this),this.dash=makeDash(this,this.pub)}makeInstance(t,e){return this.inst?this.inst:this.setInstance(new t(this.dash,...e))}setInstance(t){if(this.inst)return this.inst;if(!this.pub)throw new Error(`Destroyed component`);return this.inst=t,t}getInstance(){if(!this.inst){if(this.pub)throw new Error(`The component instance is still not initialized`);throw new Error("Destroyed component")}return this.inst}destroy(){this.emit("destroy",void 0,{sync:!0}),this.app.removeComponent(this,this.inst),this.childGroups&&this.childGroups.clear(),this.emitter.destroy(),this.childEmitter.destroy(),this.pub=void 0,this.dash=void 0,this.inst=void 0}forgetChild(t){if(this.childGroups)for(let e of this.childGroups.values())e.delete(t)}createChild(t){return this.app.createComponent(t,this)}addToGroup(t,...e){let n=this.app.getContainerByInst(t).componentId;if(this!==this.app.getParentOf(n))throw new Error(`The component ${n} is not a child of ${this.componentId}`);this.childGroups||(this.childGroups=new Map);for(let t of e){let e=this.childGroups.get(t);e||this.childGroups.set(t,e=new Set),e.add(n)}}isInGroup(t,...e){if(!this.childGroups)return!1;let n=this.app.getContainerByInst(t).componentId;for(let t of e){let e=this.childGroups.get(t);if(e&&e.has(n))return!0}return!1}broadcast(t,e){e&&e.sync?this.emitter.emit(t):this.app.asyncCall(()=>this.emitter.emit(t))}emit(t,e,n){n&&n.sync?this.emitSync(this.createEvent(t,e)):this.app.asyncCall(()=>this.emitSync(this.createEvent(t,e)))}createEvent(t,e){let n=this,r=!0;return Object.freeze({eventName:t,get source(){return n.getInstance()},data:e,stopPropagation:()=>{r=!1},[Container.canPropagateSymb]:()=>r})}emitSync(t){this.emitter.emit(t);let e=this.app.getParentOf(this.componentId);e&&e.bubbleUpEvent(t,!1,this.componentId)}bubbleUpEvent(t,e,n){if(t[Container.canPropagateSymb]&&!t[Container.canPropagateSymb]())return;this.childEmitter.emit(t,e,this.getGroupsOf(n));let r=this.app.getParentOf(this.componentId);r&&r.bubbleUpEvent(t,!0,this.componentId)}listenToParent(t,e){let n=this.getParent(e);if(n)return n.emitter.listen(t,this);if(e)throw new Error(`Cannot find the filtered parent`);return Emitter.empty()}listenToAllParents(t,e){return createMultiTransmitter(this.getAllParents(e).map(e=>e.emitter.listen(t,this)))}listenTo(t,e){return this.app.getContainerByInst(t).emitter.listen(e,this)}getGroupsOf(t){let e=new Set;if(this.childGroups)for(let[n,r]of Array.from(this.childGroups.entries()))r.has(t)&&e.add(n);return e}getParent(t){let e=this;for(;e=this.app.getParentOf(e.componentId);)if(!t||t(e))return e}getAllParents(t){let e=this,n=[];for(;e=this.app.getParentOf(e.componentId);)t&&!t(e)||n.push(e);return n}getChildren(t){let e=this.getChildContainers(t.group),n=[];for(let r of e)t.filter&&!t.filter(r)||n.push(r.getInstance());return n}getChild(t){let e=this.getChildren(t);if(1!==e.length)throw new Error(`Cannot find single ${JSON.stringify(t)} in component ${this.componentId}`);return e[0]}countChildren(t){return this.getChildren(t).length}hasChildren(t){return this.countChildren(t)>0}isChild(t){let e=this.app.getContainerByInst(t).componentId;return this===this.app.getParentOf(e)}destroyChildren(t){let e=this.getChildContainers(t.group);for(let n of e)t.filter&&!t.filter(n)||n.destroy()}getChildContainers(t){if(!t)return this.app.getChildrenOf(this.componentId);if(!this.childGroups)return[];let e="string"==typeof t?[t]:t,n=new Set;for(let t of e){let e=this.childGroups.get(t);if(e)for(let t of e.values())n.add(t)}let r=[];for(let t of n.values())r.push(this.app.getContainer(t));return r}}Container.canPropagateSymb=Symbol("canPropagate");class ApplicationContainer{constructor(t,e,n){this.compCount=0,this.nodesByInst=new WeakMap,this.nodes=new Map,this.tickList=null,this.insideRmComp=!1;let r=["error","warn","info","debug","trace"],i=this.newId();this.log=this.createLog(r),this.root=new Container(this,i);let s={container:this.root};this.nodes.set(i,s),this.root.emitter.exposeEvent(["log",...r,"addComponent","removeComponent","changeComponent"],!1);let o=e?this.root.setInstance(t):this.root.makeInstance(t,n||[]);this.nodesByInst.set(o,s)}getParentOf(t){let e=this.findNode(t);return e.parent?e.parent.container:void 0}getChildrenOf(t){let e=[],n=this.findNode(t).children;if(n)for(let t of Array.from(n.values()))e.push(t.container);return e}getContainer(t){return this.findNode(t).container}getContainerByInst(t){return this.findNodeByInst(t).container}isComponent(t){return!!this.nodesByInst.get(t)}createComponent(t,e){if(!this.root.dash)throw new Error("Destroyed root component");let n=this.newId(),r=new Container(this,n),i=this.findNode(e.componentId),s={container:r,parent:i};this.nodes.set(n,s),i.children||(i.children=new Map),i.children.set(n,s);let o;return o=t.asObj?r.setInstance(t.obj):r.makeInstance(t.Class,t.args),this.nodesByInst.set(o,s),this.root.dash.emit("addComponent",{component:r.getInstance()}),this.root.dash.emit("changeComponent",{component:r.getInstance(),type:"add"}),r}removeComponent(t,e){if(!this.root.dash)throw new Error("Destroyed root component");let n=!this.insideRmComp;try{n&&(this.insideRmComp=!0,this.root.dash.emit("removeComponent",{component:t.getInstance()},{sync:!0}),this.root.dash.emit("changeComponent",{component:t.getInstance(),type:"remove"},{sync:!0}));let r=t.componentId,i=this.findNode(r);if(i.children){for(let t of Array.from(i.children.values()))t.parent=null,t.container.destroy();i.children.clear()}i.parent&&(i.parent.container.forgetChild(r),i.parent.children.delete(r)),this.nodes.delete(r),e&&this.nodesByInst.delete(e)}finally{n&&(this.insideRmComp=!1)}}errorHandler(t){if(!this.root.dash)throw new Error("Destroyed root component");this.root.dash.emit("log",{type:"error",messages:[t]},{sync:!0})}asyncCall(t){this.tickList?this.tickList.push(t):(this.tickList=[t],setTimeout(()=>{if(this.tickList){for(let t of this.tickList)try{t()}catch(t){this.errorHandler(t)}this.tickList=null}},0))}findNode(t){let e=this.nodes.get(t);if(!e)throw new Error(`Missing node of component "${t}"`);return e}findNodeByInst(t){let e=this.nodesByInst.get(t);if(!e)throw new Error(`Cannot find a component for the instance: ${t}`);return e}newId(){return this.compCount++}createLog(t){let e={};for(let n of t)e[n]=((...t)=>{if(!this.root.dash)throw new Error("Destroyed root component");this.root.dash.emit("log",{type:n,messages:t},{sync:!0})});return Object.freeze(e)}}export{createApplication,asApplication}; |
{ | ||
"name": "bkb", | ||
"version": "0.18.1", | ||
"description": "A JavaScript Framework for Front-end Applications.", | ||
"version": "0.19.0", | ||
"description": "A JavaScript Framework for Front-end Applications", | ||
"main": "bkb.min.js", | ||
@@ -6,0 +6,0 @@ "types": "bkb.d.ts", |
18142
146