diff --git a/.jshintrc b/.jshintrc index 09913a4a5..fcba8f725 100644 --- a/.jshintrc +++ b/.jshintrc @@ -1,4 +1,7 @@ { + "predef": [ + "document" + ], "node" : true, "esnext": true, "boss" : false, diff --git a/compiler/CompileContext.js b/compiler/CompileContext.js index 737f5f599..7a1ad5fbf 100644 --- a/compiler/CompileContext.js +++ b/compiler/CompileContext.js @@ -55,6 +55,7 @@ const helpers = { 'attrs': 'as', 'classAttr': 'ca', 'classList': 'cl', + 'const': 'const', 'createElement': 'e', 'escapeXml': 'x', 'escapeXmlAttr': 'xa', @@ -516,7 +517,7 @@ class CompileContext extends EventEmitter { get helpersIdentifier() { if (!this._helpersIdentifier) { if (this.inline) { - this._helpersIdentifier = this.importModule('__markoHelpers', 'marko/runtime/helpers'); + this._helpersIdentifier = this.importModule('__markoHelpers', 'marko/runtime/html/helpers'); } else { // The helpers variable is a parameter of the outer create function this._helpersIdentifier = this.builder.identifier('__markoHelpers'); diff --git a/compiler/HtmlJsParser.js b/compiler/HtmlJsParser.js index 406d1c08e..777eb1b9a 100644 --- a/compiler/HtmlJsParser.js +++ b/compiler/HtmlJsParser.js @@ -9,7 +9,7 @@ class HtmlJsParser { parse(src, handlers) { var listeners = { onText(event) { - handlers.handleCharacters(event.value); + handlers.handleCharacters(event.value, event.parseMode); }, onPlaceholder(event) { @@ -32,7 +32,7 @@ class HtmlJsParser { }, onCDATA(event) { - handlers.handleCharacters(event.value); + handlers.handleCharacters(event.value, 'static-text'); }, onOpenTag(event, parser) { diff --git a/compiler/Parser.js b/compiler/Parser.js index ba8b93fff..2b4458042 100644 --- a/compiler/Parser.js +++ b/compiler/Parser.js @@ -110,13 +110,17 @@ class Parser { return rootNode; } - handleCharacters(text) { + handleCharacters(text, parseMode) { var builder = this.context.builder; - if (this.prevTextNode && this.prevTextNode.isLiteral()) { + var escape = parseMode !== 'html'; + // NOTE: If parseMode is 'static-text' or 'parsed-text' then that means that special + // HTML characters may not have been escaped on the way in so we need to escape + // them on the way out + + if (this.prevTextNode && this.prevTextNode.isLiteral() && this.prevTextNode.escape === escape) { this.prevTextNode.argument.value += text; } else { - var escape = false; this.prevTextNode = builder.text(builder.literal(text), escape); this.parentNode.appendChild(this.prevTextNode); } diff --git a/compiler/ast/HtmlAttribute/vdom/generateCode.js b/compiler/ast/HtmlAttribute/vdom/generateCode.js index d56d79aa2..bd8e17c6d 100644 --- a/compiler/ast/HtmlAttribute/vdom/generateCode.js +++ b/compiler/ast/HtmlAttribute/vdom/generateCode.js @@ -1,6 +1,22 @@ +'use strict'; + module.exports = function generateCode(node, codegen, vdomUtil) { - node.name = codegen.generateCode(node.name); + var context = codegen.context; + var builder = codegen.builder; + + // node.name = codegen.generateCode(node.name); node.value = codegen.generateCode(node.value); node.isStatic = vdomUtil.isStaticValue(node.value); + + var name = node.name; + + if (node.value && node.value.type !== 'Literal') { + if (name === 'class') { + node.value = builder.functionCall(context.helper('classAttr'), [node.value]); + } else if (name === 'style') { + node.value = builder.functionCall(context.helper('styleAttr'), [node.value]); + } + } + return node; }; \ No newline at end of file diff --git a/compiler/ast/HtmlComment.js b/compiler/ast/HtmlComment.js index 1c4a8295b..50084c511 100644 --- a/compiler/ast/HtmlComment.js +++ b/compiler/ast/HtmlComment.js @@ -19,6 +19,19 @@ class HtmlComment extends Node { ]; } + generateVDOMCode(codegen) { + var comment = this.comment; + var builder = codegen.builder; + + return builder.functionCall( + builder.memberExpression( + builder.identifierOut(), + builder.identifier('comment')), + [ + comment + ]); + } + walk(walker) { this.comment = walker.walk(this.comment); } diff --git a/compiler/ast/HtmlElement/html/generateCode.js b/compiler/ast/HtmlElement/html/generateCode.js index a7e41e55d..5938f1f36 100644 --- a/compiler/ast/HtmlElement/html/generateCode.js +++ b/compiler/ast/HtmlElement/html/generateCode.js @@ -13,15 +13,6 @@ module.exports = function generateCode(node, codegen) { tagName = node.tagNameExpression; } - var context = codegen.context; - - if (context.isMacro(node.tagName)) { - // At code generation time, if node tag corresponds to a registered macro - // then invoke the macro based on node HTML element instead of generating - // the code to render an HTML element. - return codegen.builder.invokeMacroFromEl(node); - } - var attributes = node._attributes && node._attributes.all; var body = node.body; var argument = node.argument; diff --git a/compiler/ast/HtmlElement/index.js b/compiler/ast/HtmlElement/index.js index e2c4059fb..450b5bcd4 100644 --- a/compiler/ast/HtmlElement/index.js +++ b/compiler/ast/HtmlElement/index.js @@ -43,10 +43,24 @@ class HtmlElement extends Node { } generateHTMLCode(codegen) { + if (codegen.context.isMacro(this.tagName)) { + // At code generation time, if node tag corresponds to a registered macro + // then invoke the macro based on node HTML element instead of generating + // the code to render an HTML element. + return codegen.builder.invokeMacroFromEl(this); + } + return generateHTMLCode(this, codegen); } generateVDOMCode(codegen) { + if (codegen.context.isMacro(this.tagName)) { + // At code generation time, if node tag corresponds to a registered macro + // then invoke the macro based on node HTML element instead of generating + // the code to render an HTML element. + return codegen.builder.invokeMacroFromEl(this); + } + return generateVDOMCode(this, codegen, vdomUtil); } diff --git a/compiler/ast/HtmlElement/vdom/HtmlElementVDOM.js b/compiler/ast/HtmlElement/vdom/HtmlElementVDOM.js index a818ca1cc..032c4940c 100644 --- a/compiler/ast/HtmlElement/vdom/HtmlElementVDOM.js +++ b/compiler/ast/HtmlElement/vdom/HtmlElementVDOM.js @@ -73,6 +73,10 @@ class HtmlElementVDOM extends Node { attributes.forEach((attr) => { let value = attr.value; + if (value == null) { + value = builder.literal(true); + } + if (!attr.name) { return; } @@ -154,7 +158,6 @@ class HtmlElementVDOM extends Node { } else if (this.isHtmlOnly) { writer.write('out.'); funcCall = builder.functionCall( - builder.identifier('e'), createArgs); } else { diff --git a/compiler/ast/HtmlElement/vdom/generateCode.js b/compiler/ast/HtmlElement/vdom/generateCode.js index 3e3631426..34b0ac8b6 100644 --- a/compiler/ast/HtmlElement/vdom/generateCode.js +++ b/compiler/ast/HtmlElement/vdom/generateCode.js @@ -21,6 +21,7 @@ module.exports = function(node, codegen, vdomUtil) { var tagName = codegen.generateCode(node.tagNameExpression); var attributes = codegen.generateCode(node.getAttributes()); var dynamicAttributes = codegen.generateCode(node.dynamicAttributes); + var builder = codegen.builder; var isAttrsStatic = checkAttributesStatic(attributes); var isStatic = isAttrsStatic && node.isLiteralTagName(); @@ -30,6 +31,9 @@ module.exports = function(node, codegen, vdomUtil) { for (var i=0; i