UNPKG

mframejs

Version:
206 lines (159 loc) 6.12 kB
import { customAttribute } from '../decorator/exported'; import { IAttribute, IListener, IBindingContext } from '../interface/exported'; import { ViewController, View, AttributeController } from '../view/exported'; import { BindingEngine } from '../binding/exported'; import { DOM } from '../utils/exported'; /** * removes dom when expression is undefined/null''0 * */ @customAttribute('if.bind') export class IfAttribute implements IAttribute { public $element: HTMLElement; public $attribute: Attr; public $bindingContext: IBindingContext; public $controller: AttributeController; private value: string | null | undefined; private elementClone: Node; private anchor: Node; private added: boolean; private subscribeCall: IListener; private $view: ViewController; private templateElement: boolean; private childNodes: Node[]; private $templateView: ViewController; /** * created * */ public created() { // get current value; this.value = this.$attribute.value; // remove the if.bind attribute this.$element.attributes.removeNamedItem('if.bind'); this.$view = this.$controller.getView(); // clone node, we need this clone later when we add it this.elementClone = this.$element.cloneNode(true); this.templateElement = (this.elementClone as any).tagName === 'TEMPLATE' ? true : false; // hide it for now, we will remove it when we are attached to parent this.$element.style.display = 'None'; // set variable for later this.added = false; } /** * attached * */ public attached() { // create anchor so where know where to inject it // this needs to be after we attched it since we need parentNode to do this this.anchor = DOM.document.createComment('mf-if-bind'); // add anchor this.$element.parentNode.insertBefore(this.anchor, this.$element); // remove main element this.remove(); this.subscribeCall = { name: 'ifAttribute', value: this.value, call: (newValue: any) => { switch (true) { case newValue && !this.added: this.added = true; this.add(); break; case !newValue && this.added: this.remove(); break; } } } as IListener; BindingEngine.subscribeClassProperty(this.$bindingContext, this.value, this.subscribeCall); } /** * detached * */ public detached(): void { BindingEngine.unSubscribeClassProperty(this.$bindingContext, this.subscribeCall); this.remove(); if (this.anchor) { this.anchor.parentNode.removeChild(this.anchor); this.anchor = null; } } /** * shows element/content * */ public add() { // create clone const template = this.elementClone.cloneNode(true); if (this.templateElement) { // IE11 if (!(<any>template).content) { (<any>template).content = DOM.document.createDocumentFragment(); while (template.childNodes[0]) { (<any>template).content.appendChild(template.childNodes[0]); } } } // set clone as current element this.$element = (template as any); let temp: any; this.$templateView = new ViewController(template, this.$view); if (this.templateElement) { temp = DOM.document.createElement('div'); temp.appendChild((template as any).content); this.childNodes = []; let anchor = DOM.document.createComment('ifbind-template-anchor-start'); this.childNodes.push(anchor); for (let i = 0, ii = temp.childNodes.length; i < ii; i++) { this.childNodes.push(temp.childNodes[i]); } anchor = DOM.document.createComment('ifbind-template-anchor-end'); this.childNodes.push(anchor); } // get attach event for elements let controllers = View.parseTemplate(this.templateElement ? temp : this.$element, this.$bindingContext, this.$templateView); if (this.templateElement) { this.anchor.parentNode.insertBefore(this.childNodes[0], this.anchor); for (let i = 1, ii = this.childNodes.length; i < ii; i++) { this.anchor.parentNode.insertBefore(this.childNodes[i], this.childNodes[i - 1].nextSibling); } } else { this.anchor.parentNode.insertBefore(this.$element, this.anchor); } // if this even used after last rebuild? controllers.forEach((x) => { if (x.attached) { x.attached(); } }); controllers = null; } /** * removes content * */ private remove() { if (this.added) { this.added = false; this.$templateView.clearView(); this.$templateView = null; } if (this.$element) { if (this.templateElement && this.childNodes) { for (let i = 0, ii = this.childNodes.length; i < ii; i++) { if (this.childNodes[i].parentNode === this.anchor.parentNode) { this.anchor.parentNode.removeChild(this.childNodes[i]); } } } else { if (this.anchor.parentNode === this.$element.parentNode) { this.anchor.parentNode.removeChild(this.$element); } } this.$element = null; } } }