import { isPlainObject, DojoNodePosition, Rendition, isDocumentFragmentNode, placeAt, collectNodes, isMounted, startupWidgets } from "./traits"; export abstract class RenditionBase implements Rendition { private _attrs = {}; private _children = new Array(); private _created: boolean = false; visitNext(v: any) { if (this._created) throw new Error("The Element is already created"); if (v === null || v === undefined || typeof v === "boolean") // skip null, undefined, booleans ( this will work: {value && {value}} ) return; if (isPlainObject(v)) { this._attrs = {... this._attrs, ...v}; } else if (v instanceof Array) { v.forEach(x => this.visitNext(x)); } else { this._children.push(v); } } ensureCreated() { if (!this._created) { this._create(this._attrs, this._children); this._children = []; this._attrs = {}; this._created = true; } } /** Is rendition was instantiated to the DOM node */ isCreated() { return this._created; } /** Creates DOM node if not created. No additional actions are taken. */ getDomNode() { this.ensureCreated(); return this._getDomNode(); } /** Creates DOM node if not created, places it to the specified position * and calls startup() method for all widgets contained by this node. * * @param {string | Node} refNode The reference node where the created * DOM should be placed. * @param {DojoNodePosition} position Optional parameter, specifies the * position relative to refNode. Default is "last" (i.e. last child). */ placeAt(refNode: string | Node, position: DojoNodePosition = "last") { const domNode = this.getDomNode(); const startupPending = isDocumentFragmentNode(domNode) ? collectNodes(domNode.childNodes) : [domNode]; placeAt(domNode, refNode, position); if (isMounted(startupPending[0])) startupPending.forEach(n => startupWidgets(n)); } protected abstract _create(attrs: object, children: unknown[]): void; protected abstract _getDomNode(): TNode; }