UNPKG

mframejs

Version:
425 lines 18.1 kB
import * as tslib_1 from "tslib"; import { customAttribute } from '../decorator/exported'; import { View } from '../view/exported'; import { ViewController } from '../view/exported'; import { BindingEngine } from '../binding/exported'; import { ArrayMethodCallHandler, ArrayPropertyChange, PropertyChangeSimple } from './repeatAttributeSubscriberHelpers'; import { DOM } from '../utils/exported'; import { createBindingContext } from '../binding/createBindingContext'; let RepeatAttribute = class RepeatAttribute { constructor() { this.templateArray = []; this.arrayType = 'object'; } setArrayLocalVariables(ctx, i) { ctx.$index = i; ctx.$even = i % 2 === 0 ? true : false; ctx.$odd = i % 2 === 0 ? false : true; ctx.$last = i === this.templateArray.length - 1 ? true : false; ctx.$first = i === 0 ? true : false; } created() { this.value = this.$attribute.value; this.loopBinded = this.loopArray.bind(this); this.$view = this.$controller.getView(); this.$element.attributes.removeNamedItem('repeat.for'); this.elementClone = this.$element.cloneNode(true); this.templateElement = this.elementClone.tagName === 'TEMPLATE' ? true : false; if (this.elementClone.getAttribute('if.bind') && this.templateElement) { this.templateElement = false; } this.$element.style.display = 'None'; const x = DOM.document.createElement('div'); const template = this.elementClone.cloneNode(true); if (this.templateElement) { if (!template.content) { template.content = DOM.document.createDocumentFragment(); while (template.childNodes[0]) { template.content.appendChild(template.childNodes[0]); } } } x.appendChild(this.templateElement ? template.content : template); this.anchor = DOM.document.createComment('mf-repeat-for'); this.repeatForArray = this.value.split(' of '); this.repeatForArray = this.repeatForArray.map(x => x.trim()); if (this.repeatForArray.length !== 2) { console.error('unknown expression in repeat:' + this.value); } else { this.rowInstanceName = this.repeatForArray[0]; this.arrayVariableName = this.repeatForArray[1]; this.arrayExpression = this.repeatForArray[1]; if (this.arrayVariableName.indexOf('|')) { const split = this.arrayVariableName.split('|').map(x => x.trim()); this.arrayVariableName = split[0]; } this.$array = BindingEngine.evaluateExpression(this.arrayExpression, this.$bindingContext); const propertyType = this.$array; if (!Array.isArray(propertyType)) { if (typeof propertyType === 'number') { this.arrayType = 'number'; this.subscribePropSimple(); } else { if (typeof propertyType === 'string') { this.arrayType = 'string'; this.subscribePropSimple(); } else { this.subscribeArray(); this.subscribePropArray(); } } } else { this.subscribeArray(); this.subscribePropArray(); } } } loopArray(changed, remove, add) { const array = this.$array; if (array) { if (changed) { if (remove) { const syncLength = this.templateArray.length - remove; for (let i = 0; i < this.templateArray.length; i++) { if (i < syncLength) { if (this.templateArray[i].ctx.$context[this.rowInstanceName] !== array[i]) { this.templateArray[i].ctx.$context[this.rowInstanceName] = array[i]; } } else { const temp = this.templateArray.pop(); i--; this.clearInRow(temp); } } } if (add) { const syncLength = array.length - add; for (let i = 0; i < array.length; i++) { if (i < syncLength) { if (this.templateArray[i].ctx.$context[this.rowInstanceName] !== this.$array[i]) { this.templateArray[i].ctx.$context[this.rowInstanceName] = this.$array[i]; } } else { this.push(array[i]); } } } } else { for (let i = 0; i < this.$array.length; i++) { if (this.templateArray[i].ctx.$context[this.rowInstanceName] !== array[i]) { this.templateArray[i].ctx.$context[this.rowInstanceName] = array[i]; } } } this.updateInternals(); } } loopArrayNumber(changed, remove, add) { const num = this.templateArray.length + 1; if (num) { if (changed) { if (remove) { const syncLength = this.templateArray.length - remove; for (let i = 0; i < this.templateArray.length; i++) { if (i >= syncLength) { const temp = this.templateArray.pop(); i--; this.clearInRow(temp); } } } if (add) { const syncLength = num; for (let i = 0; i < num + add; i++) { if (i >= syncLength) { this.push(i); } } } } else { for (let i = 0; i < this.$array; i++) { if (this.templateArray[i].ctx.$context[this.rowInstanceName] !== i) { this.templateArray[i].ctx.$context[this.rowInstanceName] = i; } } } this.updateInternals(); } } detached() { this.clearTemplateArray(); if (this.arrayMethodCallHandler) { BindingEngine.unSubscribeClassArray(this.$bindingContext, this.arrayMethodCallHandler); } if (this.arrayPropertyChangeHandler) { BindingEngine.unSubscribeClassProperty(this.$bindingContext, this.arrayPropertyChangeHandler); } if (this.arrayPropertyChangeHandlerLocal) { BindingEngine.unSubscribeClassProperty(this.$bindingContext, this.arrayPropertyChangeHandlerLocal); } if (this.propertyChangeHandlerSimple) { BindingEngine.unSubscribeClassProperty(this.$bindingContext, this.propertyChangeHandlerSimple); } if (this.anchor) { this.anchor.parentNode.removeChild(this.anchor); this.anchor = null; } this.$view = null; this.$array = null; this.arrayMethodCallHandler = null; this.arrayPropertyChangeHandler = null; this.arrayPropertyChangeHandlerLocal = null; this.propertyChangeHandlerSimple = null; } attached() { this.remove(); this.isAttached = true; this.$array = BindingEngine.evaluateExpression(this.arrayExpression, this.$bindingContext); const array = this.$array; if (Array.isArray(array)) { array.forEach((ctx) => { this.push(ctx); }); } else { if (this.arrayType === 'number') { if (this.templateArray.length !== array) { this.clearTemplateArray(); for (let i = 0; i < array; i++) { this.push(i + 1); } } } if (this.arrayType === 'string') { const stringLength = typeof array === 'string' ? array.length : 0; if (this.templateArray.length !== stringLength) { this.clearTemplateArray(); for (let i = 0; i < stringLength; i++) { this.push(array[i]); } } } } this.updateInternals(); } subscribeArray() { if (!this.arrayMethodCallHandler) { this.arrayMethodCallHandler = new ArrayMethodCallHandler(this); } BindingEngine.subscribeClassArray(this.$bindingContext, this.arrayVariableName, this.arrayMethodCallHandler); } subscribePropArray() { if (!this.arrayPropertyChangeHandler) { this.arrayPropertyChangeHandler = new ArrayPropertyChange(this); } else { console.error('subscribePropArray fail, called when set', this.arrayExpression, this.arrayVariableName); } BindingEngine.subscribeClassProperty(this.$bindingContext, this.arrayVariableName, this.arrayPropertyChangeHandler); if (this.arrayVariableName !== this.arrayExpression) { if (!this.arrayPropertyChangeHandlerLocal) { this.arrayPropertyChangeHandlerLocal = new ArrayPropertyChange(this); } const classKey = this.arrayExpression.replace(this.arrayVariableName, '$array'); BindingEngine.subscribeClassProperty(createBindingContext(this), classKey, this.arrayPropertyChangeHandlerLocal); } } subscribePropSimple() { if (!this.propertyChangeHandlerSimple) { this.propertyChangeHandlerSimple = new PropertyChangeSimple(this); } BindingEngine.subscribeClassProperty(this.$bindingContext, this.arrayVariableName, this.propertyChangeHandlerSimple); } push(ctx, i) { const template = this.elementClone.cloneNode(true); if (this.templateElement) { if (!template.content) { template.content = DOM.document.createDocumentFragment(); while (template.childNodes[0]) { template.content.appendChild(template.childNodes[0]); } } } const context = createBindingContext({ [this.rowInstanceName]: ctx }, createBindingContext(this.$bindingContext, this.$bindingContext)); const temp = DOM.document.createElement('div'); temp.appendChild(this.templateElement ? template.content : template); const $view = new ViewController(template, this.$view); if (!this.cache) { this.cache = View.createTemplateCache(temp); } const controllers = View.parseTemplateCache(temp, context, $view, this.cache); let childNodes; if (this.templateElement) { childNodes = []; let anchor = DOM.document.createComment('repeat-template-row-anchor-start'); childNodes.push(anchor); for (let i = 0, ii = temp.childNodes.length; i < ii; i++) { childNodes.push(temp.childNodes[i]); } anchor = DOM.document.createComment('repeat-template-row-anchor-end'); childNodes.push(anchor); } if (i === undefined) { const length = this.templateArray.length; this.templateArray.push({ ctx: context, template: this.templateElement ? childNodes : template, $view: $view }); this.setArrayLocalVariables(context.$context, this.templateArray.length - 1); if (this.templateElement) { if (length) { const u = this.templateArray[length - 1].template.length - 1; this.anchor.parentNode.insertBefore(childNodes[0], this.templateArray[length - 1].template[u].nextSibling); for (let i = 1, ii = childNodes.length; i < ii; i++) { this.anchor.parentNode.insertBefore(childNodes[i], childNodes[i - 1].nextSibling); } } else { this.anchor.parentNode.insertBefore(childNodes[0], this.anchor.nextSibling); for (let i = 1, ii = childNodes.length; i < ii; i++) { this.anchor.parentNode.insertBefore(childNodes[i], childNodes[i - 1].nextSibling); } } } else { if (length) { this.anchor.parentNode.insertBefore(template, this.templateArray[length - 1].template.nextSibling); } else { this.anchor.parentNode.insertBefore(template, this.anchor.nextSibling); } } } else { this.templateArray.splice(i, 0, { ctx: context, template: this.templateElement ? childNodes : template, $view: $view }); if (this.templateElement) { if (this.templateArray[i + 1]) { const u = this.templateArray[length - 1].template.length - 1; this.anchor.parentNode.insertBefore(childNodes[0], this.templateArray[length - 1].template[u].nextSibling); for (let i = 1, ii = childNodes.length; i < ii; i++) { this.anchor.parentNode.insertBefore(childNodes[i], childNodes[i - 1].nextSibling); } } else { this.anchor.parentNode.insertBefore(childNodes[0], this.anchor.nextSibling); for (let i = 1, ii = childNodes.length; i < ii; i++) { this.anchor.parentNode.insertBefore(childNodes[i], childNodes[i - 1].nextSibling); } } } else { if (this.templateArray[i + 1]) { this.anchor.parentNode.insertBefore(template, this.templateArray[i + 1].template); } else { this.anchor.parentNode.appendChild(template); } } } controllers.forEach((contr) => { if (contr.attached) { contr.attached(); } }); } pop() { if (this.templateArray.length > 0) { const temp = this.templateArray.pop(); this.clearInRow(temp); this.updateInternals(); } } updateInternals() { this.templateArray.forEach((context, i) => { this.setArrayLocalVariables(context.ctx.$context, i); }); } shift() { if (this.templateArray.length > 0) { const temp = this.templateArray.shift(); this.clearInRow(temp); this.updateInternals(); } } splice(args) { if (this.templateArray.length > 0) { const index = args[0]; const deleted = args[0] === 0 && args[1] === undefined ? this.templateArray.length : args[1]; const added = []; for (let i = 2; i < args.length; i++) { if (args[i]) { added.push(args[i]); } } if (deleted) { const newIndex = index + deleted - 1; for (let i = newIndex; i > index - 1; i--) { const temp = this.templateArray.splice(i, 1)[0]; this.clearInRow(temp); } } added.forEach((ctx) => { this.push(ctx, index); }); this.updateInternals(); } } clearTemplateArray() { let x = DOM.document.createElement('div'); this.templateArray.forEach((temp) => { if (this.templateElement) { for (let i = 0, ii = temp.template.length; i < ii; i++) { x.appendChild(temp.template[i]); } } else { x.appendChild(temp.template); } }); this.templateArray.forEach((temp) => { temp.$view.clearView(); }); x = null; this.templateArray = []; } remove() { this.clearTemplateArray(); this.$element.parentNode.replaceChild(this.anchor, this.$element); } clearInRow(rowData) { if (rowData) { if (this.templateElement) { for (let i = 0, ii = rowData.template.length; i < ii; i++) { rowData.$view.clearView(); if (rowData.template[i].parentNode) { rowData.template[i].parentNode.removeChild(rowData.template[i]); } } } else { if (rowData.template.parentNode) { rowData.template.parentNode.removeChild(rowData.template); } rowData.$view.clearView(); } } } }; RepeatAttribute = tslib_1.__decorate([ customAttribute('repeat.for') ], RepeatAttribute); export { RepeatAttribute }; //# sourceMappingURL=repeatAttribute.js.map