mframejs
Version:
simple framework
206 lines (159 loc) • 6.12 kB
text/typescript
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
*
*/
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;
}
}
}