RenditionBase.ts
116 lines
| 3.9 KiB
| video/mp2t
|
TypeScriptLexer
|
|
r65 | import { isNull, mixin } from "@implab/core-amd/safe"; | ||
| import { isPlainObject, isNode, isRendition, DojoNodePosition, Rendition, isInPage, isWidget, isDocumentFragmentNode, startupWidgets } from "./traits"; | ||||
| import dom = require("dojo/dom-construct"); | ||||
| import registry = require("dijit/registry"); | ||||
| export abstract class RenditionBase<TNode extends Node> implements Rendition<TNode> { | ||||
| 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 (isNull(v) || typeof v === "boolean") | ||||
| // skip null, undefined, booleans ( this will work: {value && <span>{value}</span>} ) | ||||
| return; | ||||
| if (isPlainObject(v)) { | ||||
| mixin(this._attrs, v); | ||||
| } else if (v instanceof Array) { | ||||
| v.forEach(x => this.visitNext(x)); | ||||
| } else { | ||||
| this._children.push(v); | ||||
| } | ||||
| } | ||||
| protected getItemDom(v: any) { | ||||
| const tv = typeof v; | ||||
| if (tv === "string" || tv === "number" || v instanceof RegExp || v instanceof Date) { | ||||
| // primitive types converted to the text nodes | ||||
| return document.createTextNode(v.toString()); | ||||
| } else if (isNode(v)) { | ||||
| // nodes are kept as is | ||||
| return v; | ||||
| } else if (isRendition(v)) { | ||||
| // renditions as instantinated | ||||
| return v.getDomNode(); | ||||
| } else if (isWidget(v)) { | ||||
| // widgets are converted to it's markup | ||||
| return v.domNode; | ||||
| } else if (tv === "boolean" || v === null || v === undefined) { | ||||
| // null | undefined | boolean are removed, converted to comments | ||||
| return document.createComment(`[${tv} ${String(v)}]`); | ||||
| } else { | ||||
| // bug: explicit error otherwise | ||||
| throw new Error("Invalid parameter: " + v); | ||||
| } | ||||
| } | ||||
| ensureCreated() { | ||||
| if (!this._created) { | ||||
| this._create(this._attrs, this._children); | ||||
| this._children = []; | ||||
| this._attrs = {}; | ||||
| this._created = true; | ||||
| } | ||||
| } | ||||
| /** @deprecated will be removed in 1.0.0, use getDomNode() */ | ||||
| getDomElement() { | ||||
| return this.getDomNode(); | ||||
| } | ||||
| /** 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) { | ||||
| const domNode = this.getDomNode(); | ||||
| const collect = (collection: HTMLCollection) => { | ||||
| const items = []; | ||||
| for (let i = 0, n = items.length; i < length; i++) { | ||||
| items.push(collection[i]); | ||||
| } | ||||
| return items; | ||||
| } | ||||
| const startup = (node: Node) => { | ||||
| if (node.parentNode) { | ||||
| const parentWidget = registry.getEnclosingWidget(node.parentNode); | ||||
| if (parentWidget && parentWidget._started) | ||||
| return startupWidgets(node); | ||||
| } | ||||
| if (isInPage(node)) | ||||
| startupWidgets(node); | ||||
| } | ||||
| const startupPending = isDocumentFragmentNode(domNode) ? collect(domNode.children) : [domNode] | ||||
| dom.place(domNode, refNode, position); | ||||
| startupPending.forEach(startup); | ||||
| } | ||||
| protected abstract _create(attrs: object, children: any[]): void; | ||||
| protected abstract _getDomNode(): TNode; | ||||
| } | ||||
