const VnObject = require('./object'); const kebabToCamel = require('./string-util').kebabToCamel; let scopeUid = 0; module.exports = new Class({ Extends: VnObject ,initialize: function(builder, doc, objects, exprValues, thisArg, parent) { this.builder = builder; this.objects = objects; this.exprValues = exprValues; this.thisArg = thisArg; this.parent = parent; this.uid = ++scopeUid; this.$ = parent ? Object.create(parent.$) : {}; if (parent) { parent.ref(); // XXX: Keep commented until optimized //parent.on('change', this.onChange, this); if (!thisArg) this.thisArg = parent.thisArg; } const contexts = builder._contexts; for (let i = 0; i < contexts.length; i++) { const context = contexts[i]; objects[i] = context.compiler.instantiate(doc, context, this); } } ,link: function(extraObjects) { var contextMap = this.builder._contextMap; for (var id in extraObjects) this.$[id] = extraObjects[id]; for (var id in contextMap) this.$[id] = this.objects[contextMap[id]]; const builder = this.builder; const contexts = builder._contexts; const objects = this.objects; for (const compiler of builder._compilers) compiler.preLink(this); for (let i = 0; i < contexts.length; i++) { const context = contexts[i]; context.compiler.link(context, objects[i], objects, this); } for (let i = 0; i < contexts.length; i++) { const context = contexts[i]; context.compiler.connect(context, objects[i], objects, this); } for (const compiler of builder._compilers) compiler.postLink(this); this.digest(); for (const object of this.objects) if (object.assignLot) object.on('change', this.onChange, this); } ,digest() { const exprContexts = this.builder._exprContexts; const exprValues = this.exprValues; const objects = this.objects; for (let i = 0; i < exprContexts.length; i++) { const exprContext = exprContexts[i]; let newValue; if (exprContext.template) { const values = []; let isEmpty = false; for (expr of exprContext.exprs) { const value = this.execExpr(expr); if (value == null) { isEmpty = true; break; } values.push(value); } if (!isEmpty) { let k = 0; newValue = exprContext.template.replace(/{{\d+}}/g, function() { return values[k++]; }); } else newValue = ''; } else newValue = this.execExpr(exprContext.expr); if (newValue !== exprValues[i]) { const context = exprContext.context; context.compiler.setProperty(objects[context.id], exprContext.property, newValue); exprValues[i] = newValue; } } } ,execExpr(expr) { try { return expr.call(this.thisArg, this.$); // eslint-disable-next-line no-empty } catch (e) {} } ,onChange() { this.emit('change'); this.digest(); } ,getMain: function() { return this.objects[this.builder._mainContext]; } ,getById: function(objectId) { if (!objectId) return null; return this.$[kebabToCamel(objectId)]; } ,getByTagName: function(tagName) { const tags = this.builder._tags[tagName]; if (tags) { const arr = new Array(tags.length); for (let i = 0; i < tags.length; i++) arr[i] = this.objects[tags[i]]; return arr; } return []; } ,getHtmlId: function(nodeId) { return 'vn-'+ this.uid +'-'+ nodeId; } ,_destroy: function() { for (const object of this.objects) if (object instanceof VnObject) { object.disconnectByInstance(this); object.unref(); } if (this.parent) { this.parent.disconnectByInstance(this); this.parent.unref(); } VnObject.prototype._destroy.call(this); } });