'use strict'; const Node = require('../../Node'); const vdomUtil = require('../../../util/vdom'); function finalizeCreateArgs(createArgs, builder) { var length = createArgs.length; var lastArg; for (var i=length-1; i>=0; i--) { var arg = createArgs[i]; if (arg) { lastArg = arg; } else { if (lastArg != null) { createArgs[i] = builder.literalNull(); } else { length--; } } } createArgs.length = length; return createArgs; } class HtmlElementVDOM extends Node { constructor(def) { super('HtmlElementVDOM'); this.tagName = def.tagName; this.isStatic = def.isStatic; this.isAttrsStatic = def.isAttrsStatic; this.isHtmlOnly = def.isHtmlOnly; this.attributes = def.attributes; this.body = def.body; this.dynamicAttributes = def.dynamicAttributes; this.isChild = false; this.createElementId = undefined; this.attributesArg = undefined; this.nextConstId = undefined; } generateCode(codegen) { let context = codegen.context; let builder = codegen.builder; // When there are any VDOM nodes in the AST then we need to optimize the intermediate AST // before the final AST is returned. We use the "afterTemplateRootBodyGenerated" event // to finalize the VDOM AST nodes. vdomUtil.attachEventListeners(context); let attributes = this.attributes; let dynamicAttributes = this.dynamicAttributes; let attributesArg = null; if (attributes && attributes.length) { let addAttr = function(name, value) { if (!attributesArg) { attributesArg = {}; } if (value.type === 'Literal') { let literalValue = value.value; if (literalValue == null || literalValue === false) { return; } else if (typeof literalValue === 'number') { value.value = literalValue.toString(); } } attributesArg[name] = value; }; attributes.forEach((attr) => { let value = attr.value; if (!attr.name) { return; } addAttr(attr.name, value); }); if (attributesArg) { attributesArg = builder.literal(attributesArg); } } if (dynamicAttributes && dynamicAttributes.length) { dynamicAttributes.forEach((attrs) => { if (attributesArg) { let mergeVar = context.helper('merge'); attributesArg = builder.functionCall(mergeVar, [ attributesArg, // Input props from the attributes take precedence attrs ]); } else { attributesArg = attrs; } }); } this.attributesArg = attributesArg; return this; } walk(walker) { this.tagName = walker.walk(this.tagName); this.attributes = walker.walk(this.attributes); this.body = walker.walk(this.body); } writeCode(writer) { let builder = writer.builder; let body = this.body; let attributesArg = this.attributesArg; let nextConstId = this.nextConstId; let childCount = body && body.length; let createArgs = new Array(4); // tagName, attributes, childCount, const ID createArgs[0] = this.tagName; if (attributesArg) { createArgs[1] = attributesArg; } if (childCount != null) { createArgs[2] = builder.literal(childCount); } if (nextConstId) { createArgs[3] = nextConstId; } // Remove trailing undefined arguments and convert non-trailing // undefined elements to a literal null node createArgs = finalizeCreateArgs(createArgs, builder); let funcCall; if (this.isChild) { writer.write('.'); funcCall = builder.functionCall( builder.identifier('e'), createArgs); } else if (this.isStatic) { funcCall = builder.functionCall( this.createElementId, createArgs); } else if (this.isHtmlOnly) { writer.write('out.'); funcCall = builder.functionCall( builder.identifier('e'), createArgs); } else { writer.write('out.'); funcCall = builder.functionCall( builder.identifier('be'), createArgs); } writer.write(funcCall); if (body && body.length) { writer.incIndent(); for(let i=0; i