dist/ember-template-compiler.js in ember-source-1.10.0.beta.3 vs dist/ember-template-compiler.js in ember-source-1.10.0.beta.4

- old
+ new

@@ -3,11 +3,11 @@ * @copyright Copyright 2011-2014 Tilde Inc. and contributors * Portions Copyright 2006-2011 Strobe Inc. * Portions Copyright 2008-2011 Apple Inc. All rights reserved. * @license Licensed under MIT license * See https://raw.github.com/emberjs/ember.js/master/LICENSE - * @version 1.10.0-beta.3 + * @version 1.10.0-beta.4 */ (function() { var define, requireModule, require, requirejs, Ember; @@ -112,11 +112,11 @@ The core Runtime framework is based on the jQuery API with a number of performance optimizations. @class Ember @static - @version 1.10.0-beta.3 + @version 1.10.0-beta.4 */ if ('undefined' === typeof Ember) { // Create core object. Make it act like an instance of Ember.Namespace so that // objects assigned to it are given a sane string representation. @@ -139,14 +139,14 @@ /** @property VERSION @type String - @default '1.10.0-beta.3' + @default '1.10.0-beta.4' @static */ - Ember.VERSION = '1.10.0-beta.3'; + Ember.VERSION = '1.10.0-beta.4'; /** Standard environmental variables. You can define these in a global `EmberENV` variable before loading Ember to control various configuration settings. @@ -399,10 +399,15 @@ var walker = new pluginContext.syntax.Walker(); var b = pluginContext.syntax.builders; walker.visit(ast, function(node) { if (pluginContext.validate(node)) { + + if (node.program && node.program.blockParams.length) { + throw new Error('You cannot use keyword (`{{each foo in bar}}`) and block params (`{{each bar as |foo|}}`) at the same time.'); + } + var removedParams = node.sexpr.params.splice(0, 2); var keyword = removedParams[0].original; // TODO: This may not be necessary. if (!node.sexpr.hash) { @@ -470,10 +475,15 @@ var pluginContext = this; var walker = new pluginContext.syntax.Walker(); walker.visit(ast, function(node) { if (pluginContext.validate(node)) { + + if (node.program && node.program.blockParams.length) { + throw new Error('You cannot use keyword (`{{with foo as bar}}`) and block params (`{{with foo as |bar|}}`) at the same time.'); + } + var removedParams = node.sexpr.params.splice(1, 2); var keyword = removedParams[1].original; node.program.blockParams = [ keyword ]; } }); @@ -737,13 +747,17 @@ FragmentJavaScriptCompiler.prototype.returnNode = function() { var el = 'el'+this.depth; this.source.push(this.indent+' return '+el+';\n'); }; - FragmentJavaScriptCompiler.prototype.setAttribute = function(name, value) { + FragmentJavaScriptCompiler.prototype.setAttribute = function(name, value, namespace) { var el = 'el'+this.depth; - this.source.push(this.indent+' dom.setProperty('+el+','+string(name)+','+string(value)+');\n'); + if (namespace) { + this.source.push(this.indent+' dom.setAttributeNS('+el+','+string(namespace)+','+string(name)+','+string(value)+');\n'); + } else { + this.source.push(this.indent+' dom.setAttribute('+el+','+string(name)+','+string(value)+');\n'); + } }; FragmentJavaScriptCompiler.prototype.appendChild = function() { if (this.depth === this.getCurrentNamespaceFrame().depth) { this.popNamespaceFrame(); @@ -777,10 +791,11 @@ ["./template-visitor","./utils","../htmlbars-util/array-utils","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; var TemplateVisitor = __dependency1__["default"]; var processOpcodes = __dependency2__.processOpcodes; + var getNamespace = __dependency2__.getNamespace; var forEach = __dependency3__.forEach; function FragmentOpcodeCompiler() { this.opcodes = []; } @@ -836,11 +851,14 @@ FragmentOpcodeCompiler.prototype.block = function () {}; FragmentOpcodeCompiler.prototype.attribute = function(attr) { if (attr.value.type === 'TextNode') { - this.opcode('setAttribute', [attr.name, attr.value.chars]); + + var namespace = getNamespace(attr.name) || null; + + this.opcode('setAttribute', [attr.name, attr.value.chars, namespace]); } }; FragmentOpcodeCompiler.prototype.setNamespace = function(namespace) { this.opcode('setNamespace', [namespace]); @@ -1056,22 +1074,22 @@ (isRoot ? ",contextualElement)" : ")"); this.morphs.push(['morph' + morphNum, morph]); }; - prototype.createAttrMorph = function(attrMorphNum, elementNum, name, escaped) { + prototype.createAttrMorph = function(attrMorphNum, elementNum, name, escaped, namespace) { var morphMethod = escaped ? 'createAttrMorph' : 'createUnsafeAttrMorph'; - var morph = "dom."+morphMethod+"(element"+elementNum+", '"+name+"')"; + var morph = "dom."+morphMethod+"(element"+elementNum+", '"+name+(namespace ? "', '"+namespace : '')+"')"; this.morphs.push(['attrMorph' + attrMorphNum, morph]); }; prototype.repairClonedNode = function(blankChildTextNodes, isElementChecked) { var parent = this.getParent(), - processing = 'dom.repairClonedNode('+parent+','+ + processing = 'if (this.cachedFragment) { dom.repairClonedNode('+parent+','+ array(blankChildTextNodes)+ ( isElementChecked ? ',true' : '' )+ - ');'; + '); }'; this.fragmentProcessing.push( processing ); }; @@ -1111,10 +1129,11 @@ ["./template-visitor","./utils","../htmlbars-util/array-utils","../htmlbars-syntax/utils","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { "use strict"; var TemplateVisitor = __dependency1__["default"]; var processOpcodes = __dependency2__.processOpcodes; + var getNamespace = __dependency2__.getNamespace; var forEach = __dependency3__.forEach; var isHelper = __dependency4__.isHelper; function unwrapMustache(mustache) { if (isHelper(mustache.sexpr)) { @@ -1284,10 +1303,11 @@ }; HydrationOpcodeCompiler.prototype.attribute = function(attr) { var value = attr.value; var escaped = true; + var namespace = getNamespace(attr.name) || null; // TODO: Introduce context specific AST nodes to avoid switching here. if (value.type === 'TextNode') { return; } else if (value.type === 'MustacheStatement') { @@ -1304,11 +1324,11 @@ this.opcode('shareElement', ++this.elementNum); this.element = null; } var attrMorphNum = this.attrMorphNum++; - this.opcode('createAttrMorph', attrMorphNum, this.elementNum, attr.name, escaped); + this.opcode('createAttrMorph', attrMorphNum, this.elementNum, attr.name, escaped, namespace); this.opcode('printAttributeHook', attrMorphNum, this.elementNum); }; HydrationOpcodeCompiler.prototype.elementHelper = function(sexpr) { prepareSexpr(this, sexpr); @@ -1840,11 +1860,27 @@ compiler[method].call(compiler); } } } - __exports__.processOpcodes = processOpcodes; + __exports__.processOpcodes = processOpcodes;// ref http://dev.w3.org/html5/spec-LC/namespaces.html + var defaultNamespaces = { + html: 'http://www.w3.org/1999/xhtml', + mathml: 'http://www.w3.org/1998/Math/MathML', + svg: 'http://www.w3.org/2000/svg', + xlink: 'http://www.w3.org/1999/xlink', + xml: 'http://www.w3.org/XML/1998/namespace' + }; + + function getNamespace(attrName) { + var parts = attrName.split(':'); + if (parts.length > 1) { + return defaultNamespaces[parts[0]]; + } + } + + __exports__.getNamespace = getNamespace; }); define("htmlbars-syntax", ["./htmlbars-syntax/walker","./htmlbars-syntax/builders","./htmlbars-syntax/parser","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; @@ -3668,18 +3704,22 @@ } __exports__["default"] = tokenHandlers; }); define("htmlbars-syntax/tokenizer", - ["../simple-html-tokenizer","./utils","./builders","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + ["../simple-html-tokenizer","./utils","../htmlbars-util/array-utils","./builders","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { "use strict"; var Tokenizer = __dependency1__.Tokenizer; var isHelper = __dependency2__.isHelper; - var builders = __dependency3__["default"]; + var map = __dependency3__.map; + var builders = __dependency4__["default"]; Tokenizer.prototype.createAttribute = function(char) { + if (this.token.type === 'EndTag') { + throw new Error('Invalid end tag: closing tag must not have attributes, in ' + formatTokenInfo(this) + '.'); + } this.currentAttribute = builders.attr(char.toLowerCase(), [], null); this.token.attributes.push(this.currentAttribute); this.state = 'attributeName'; }; @@ -3692,16 +3732,17 @@ }; Tokenizer.prototype.addToAttributeValue = function(char) { var value = this.currentAttribute.value; + if (!this.currentAttribute.quoted && char === '/') { + throw new Error("A space is required between an unquoted attribute value and `/`, in " + formatTokenInfo(this) + + '.'); + } if (!this.currentAttribute.quoted && value.length > 0 && (char.type === 'MustacheStatement' || value[0].type === 'MustacheStatement')) { - // Get the line number from a mustache, whether it's the one to add or the one already added - var mustache = char.type === 'MustacheStatement' ? char : value[0], - line = mustache.loc.start.line; - throw new Error("Unquoted attribute value must be a single string or mustache (line " + line + ")"); + throw new Error("Unquoted attribute value must be a single string or mustache (on line " + this.line + ")"); } if (typeof char === 'object') { if (char.type === 'MustacheStatement') { value.push(char); @@ -3730,18 +3771,20 @@ helpers.push(helper); }; function prepareAttributeValue(attr) { var parts = attr.value; - if (parts.length === 0) { + var length = parts.length; + + if (length === 0) { return builders.text(''); - } else if (parts.length === 1 && parts[0].type === "TextNode") { + } else if (length === 1 && parts[0].type === "TextNode") { return parts[0]; } else if (!attr.quoted) { return parts[0]; } else { - return builders.concat(parts.map(prepareConcatPart)); + return builders.concat(map(parts, prepareConcatPart)); } } function prepareConcatPart(node) { switch (node.type) { @@ -3750,10 +3793,14 @@ default: throw new Error("Unsupported node in quoted attribute value: " + node.type); } } + function formatTokenInfo(tokenizer) { + return '`' + tokenizer.token.tagName + '` (on line ' + tokenizer.line + ')'; + } + function unwrapMustache(mustache) { if (isHelper(mustache.sexpr)) { return mustache.sexpr; } else { return mustache.sexpr.path; @@ -3955,10 +4002,20 @@ __exports__.equalHTML = equalHTML;// detect weird IE8 html strings var ie8InnerHTMLTestElement = document.createElement('div'); ie8InnerHTMLTestElement.setAttribute('id', 'womp'); var ie8InnerHTML = (ie8InnerHTMLTestElement.outerHTML.indexOf('id=womp') > -1); + + // detect side-effects of cloning svg elements in IE9-11 + var ieSVGInnerHTML = (function () { + var div = document.createElement('div'); + var node = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + div.appendChild(node); + var clone = div.cloneNode(true); + return clone.innerHTML === '<svg xmlns="http://www.w3.org/2000/svg" />'; + })(); + function normalizeInnerHTML(actualHTML) { if (ie8InnerHTML) { // drop newlines in IE8 actualHTML = actualHTML.replace(/\r\n/gm, ''); // downcase ALLCAPS tags in IE8 @@ -3968,10 +4025,20 @@ // quote ids in IE8 actualHTML = actualHTML.replace(/id=([^ >]+)/gi, function(match, id){ return 'id="'+id+'"'; }); } + if (ieSVGInnerHTML) { + // Replace `<svg xmlns="http://www.w3.org/2000/svg" height="50%" />` with `<svg height="50%"></svg>`, etc. + // drop namespace attribute + actualHTML = actualHTML.replace(/ xmlns="[^"]+"/, ''); + // replace self-closing elements + actualHTML = actualHTML.replace(/<([A-Z]+) [^\/>]*\/>/gi, function(tag, tagName) { + return tag.slice(0, tag.length - 3) + '></' + tagName + '>'; + }); + } + return actualHTML; } __exports__.normalizeInnerHTML = normalizeInnerHTML;// detect weird IE8 checked element string var checkedInput = document.createElement('input'); @@ -3996,22 +4063,33 @@ define("htmlbars-util/array-utils", ["exports"], function(__exports__) { "use strict"; function forEach(array, callback, binding) { - var i; + var i, l; if (binding === undefined) { - for (i = 0; i < array.length; i++) { + for (i = 0, l = array.length; i < l; i++) { callback(array[i], i, array); } } else { - for (i = 0; i < array.length; i++) { + for (i = 0, l = array.length; i < l; i++) { callback.call(binding, array[i], i, array); } } } - __exports__.forEach = forEach; + __exports__.forEach = forEach;function map(array, callback) { + var output = []; + var i, l; + + for (i = 0, l = array.length; i < l; i++) { + output.push(callback(array[i], i, array)); + } + + return output; + } + + __exports__.map = map; }); define("htmlbars-util/handlebars/safe-string", ["exports"], function(__exports__) { "use strict"; \ No newline at end of file