From cb2d331dbfdef0887424eee555ab0a66679ef303 Mon Sep 17 00:00:00 2001 From: David Greenspan Date: Mon, 9 Dec 2013 22:52:20 -0800 Subject: [PATCH] seems to work (not fully tested) --- packages/html/parse.js | 4 + packages/html/tags.js | 151 --------------------- packages/htmljs/html.js | 2 +- packages/spacebars/spacebars.js | 17 +-- packages/templating/plugin/html_scanner.js | 2 +- packages/templating/scanner_tests.js | 2 +- packages/ui/render.js | 5 +- 7 files changed, 16 insertions(+), 167 deletions(-) delete mode 100644 packages/html/tags.js diff --git a/packages/html/parse.js b/packages/html/parse.js index 8bdd2364db..1c27e6f898 100644 --- a/packages/html/parse.js +++ b/packages/html/parse.js @@ -1,5 +1,9 @@ HTML.Special = function (value) { + if (! (this instanceof HTML.Special)) + // called without `new` + return new HTML.Special(value); + this.value = value; }; HTML.Special.prototype.toJS = function (options) { diff --git a/packages/html/tags.js b/packages/html/tags.js deleted file mode 100644 index cbc07a5fda..0000000000 --- a/packages/html/tags.js +++ /dev/null @@ -1,151 +0,0 @@ -// A Tag is an array of zero or more content items, with additional properties -// `tagName` (String, required) and `attrs` (Object or `null`). In addition to -// be arrays, Tags are `instanceof HTML.Tag`. -// -// An attribute value may be null, a string, a CharRef tag, or an array of -// strings, CharRef tags, arrays, and nulls. -// -// Tags are created using tag functions, e.g. `DIV(P({id:'foo'}, "Hello"))`. -// If a tag function is given a first argument that is an object and not a -// Tag or an array, that object is used as element attributes (`attrs`). -// The attrs argument may be of the form `{$attrs: function () { ... }}` in -// which case the function becomes the `attrs` attribute of the tag. -// -// Tag functions for all known tags are available as `HTML.Tag.DIV`, -// `HTML.Tag.SPAN`, etc., and you can define new ones with -// `HTML.defineTag("FOO")`, which makes a tag function available at -// `HTML.Tag.FOO` henceforth. You can also use `HTML.getTag("FOO")` to -// define (if necessary) and return a tag function. - -Tag = function (tagName, attrs) { - this.tagName = tagName; - this.attrs = attrs; // may be falsy -}; -Tag.prototype = []; - -makeTagFunc = function (name) { - // Do a little dance so that tags print nicely in the Chrome console. - // First make tag name suitable for insertion into evaluated JS code, - // for security reasons mainly. - var sanitizedName = String(name).replace(/^[^a-zA-Z_]|[^a-zA-Z_0-9]+/g, - '') || 'Tag'; - // Generate a constructor function whose name is the tag name. - // We try to choose generic-sounding variable names in case V8 infers - // them as type names and they show up in the developer console. - // HTMLTag is the constructor function for our specific tag type, - // while Tag is the super constructor. - var HTMLTag = (new Function('return function ' + - sanitizedName + - '(attrs) { this.attrs = attrs; };'))(); - HTMLTag.prototype = new Tag(name); - - return function (optAttrs/*, children*/) { - // see whether first argument is truthy and not an Array or Tag - var attrsGiven = (optAttrs && (typeof optAttrs === 'object') && - (typeof optAttrs.splice !== 'function')); - var attrs = (attrsGiven ? optAttrs : null); - if (attrsGiven && (typeof attrs.$attrs === 'function')) - attrs = attrs.$attrs; - - var tag = new HTMLTag(attrs); - tag.push.apply(tag, (attrsGiven ? - Array.prototype.slice.call(arguments, 1) : - arguments)); - return tag; - }; -}; - -defineTag = function (name) { - // XXX maybe sanity-check name? Like no whitespace. - name = name.toUpperCase(); - Tag[name] = makeTagFunc(name); - return Tag[name]; -}; - -getTag = function (name) { - name = name.toUpperCase(); - return Tag[name] || defineTag(name); -}; - -// checks that a pseudoDOM node with tagName "CharRef" is well-formed. -var checkCharRef = function (charRef) { - if (typeof charRef.attrs === 'function') - throw new Error("Can't have a reactive character reference (CharRef)"); - - var attrs = charRef.attrs; - if ((! attrs) || (typeof attrs.html !== 'string') || - (typeof attrs.str !== 'string') || (! attrs.html) || (! attrs.str)) - throw new Error("CharRef should have simple string attributes " + - "`html` and `str`."); - - if (charRef.length) - throw new Error("CharRef should have no content"); -}; - -// checks that a pseudoDOM node with tagName "Comment" is well-formed. -var checkComment = function (comment) { - if (comment.attrs) - throw new Error("Comment can't have attributes"); - if (comment.length !== 1 || (typeof comment[0] !== 'string')) - throw new Error("Comment should have exactly one content item, a simple string"); -}; - -// checks that a pseudoDOM node with tagName "Raw" is well-formed. -var checkRaw = function (raw) { - if (raw.attrs) - throw new Error("Raw can't have attributes"); - if (raw.length !== 1 || (typeof raw[0] !== 'string')) - throw new Error("Raw should have exactly one content item, a simple string"); -}; - -// checks that a pseudoDOM node with tagName "Comment" is well-formed. -var checkEmitCode = function (node) { - if (node.attrs) - throw new Error("EmitCode can't have attributes"); - if (node.length !== 1 || (typeof node[0] !== 'string')) - throw new Error("EmitCode should have exactly one content item, a simple string"); -}; - -var checkSpecial = function (node) { - if (! node.attrs) - throw new Error("Special tag must have attributes"); - if (node.length > 0) - throw new Error("Special tag must not have content"); -}; - -typeOf = function (node) { - if (node && (typeof node === 'object') && - (typeof node.splice === 'function')) { - // Tag or array - if (node.tagName) { - if (node.tagName === 'CharRef') { - checkCharRef(node); - return 'charref'; - } else if (node.tagName === 'Comment') { - checkComment(node); - return 'comment'; - } else if (node.tagName === 'EmitCode') { - checkEmitCode(node); - return 'emitcode'; - } else if (node.tagName === 'Special') { - checkSpecial(node); - return 'special'; - } else if (node.tagName === 'Raw') { - checkRaw(node); - return 'raw'; - } else { - return 'tag'; - } - } else { - return 'array'; - } - } else if (typeof node === 'string') { - return 'string'; - } else if (typeof node === 'function') { - return 'function'; - } else if (node == null) { - return 'null'; - } else { - throw new Error("Unexpected item in HTML tree: " + node); - } -}; \ No newline at end of file diff --git a/packages/htmljs/html.js b/packages/htmljs/html.js index 3144d4dbee..85ab8c303f 100644 --- a/packages/htmljs/html.js +++ b/packages/htmljs/html.js @@ -139,7 +139,7 @@ HTML.Raw = function (value) { HTML.EmitCode = function (value) { if (! (this instanceof HTML.EmitCode)) // called without `new` - return new HTML.Raw(value); + return new HTML.EmitCode(value); if (typeof value !== 'string') throw new Error('HTML.EmitCode must be constructed with a string'); diff --git a/packages/spacebars/spacebars.js b/packages/spacebars/spacebars.js index c50c2d9265..0a204d45b2 100644 --- a/packages/spacebars/spacebars.js +++ b/packages/spacebars/spacebars.js @@ -448,7 +448,7 @@ var optimize = function (tree) { var pushRawHTML = function (array, html) { var N = array.length; if (N > 0 && (array[N-1] instanceof HTML.Raw)) { - array[N-1][0] += html; + array[N-1] = HTML.Raw(array[N-1].value + html); } else { array.push(HTML.Raw(html)); } @@ -485,9 +485,9 @@ var optimize = function (tree) { // clean up unnecessary HTML.Raw wrappers around pure character data for (var j = 0; j < result.length; j++) { if ((result[j] instanceof HTML.Raw) && - isPureChars(result[j][0])) + isPureChars(result[j].value)) // replace HTML.Raw with simple string - result[j] = result[j][0]; + result[j] = result[j].value; } } return result; @@ -785,17 +785,14 @@ Spacebars._handleSpecialAttributes = function (oldAttrs) { // // If specials are found, sets `foundSpecials` to true. var convertSpecialToEmitCode = function (v) { - var type = HTML.typeOf(v); - if (type === 'null' || type === 'string' || type === 'charref') { - return v; - } else if (type === 'special') { + if (v instanceof HTML.Special) { foundSpecials = true; return HTML.EmitCode('function () { return ' + - codeGenMustache(v.attrs) + '; }'); - } else if (type === 'array') { + codeGenMustache(v.value) + '; }'); + } else if (v instanceof Array) { return _.map(v, convertSpecialToEmitCode); } else { - throw new Error("Unexpected node in attribute value: " + v); + return v; } }; diff --git a/packages/templating/plugin/html_scanner.js b/packages/templating/plugin/html_scanner.js index 6764b9e175..024b2d7778 100644 --- a/packages/templating/plugin/html_scanner.js +++ b/packages/templating/plugin/html_scanner.js @@ -165,7 +165,7 @@ html_scanner = { contents, { sourceName: "" }); // We may be one of many `` tags. - results.js += "\nUI.body2.contentParts.push(UI.Component.extend({render: " + renderFuncCode + "}));\nMeteor.startup(function () { if (! UI.body2.INSTANTIATED) { UI.materialize(UI.body2, document.body); } });\n"; + results.js += "\nUI.body.contentParts.push(UI.Component.extend({render: " + renderFuncCode + "}));\nMeteor.startup(function () { if (! UI.body.INSTANTIATED) { UI.materialize(UI.body, document.body); } });\n"; } } }; diff --git a/packages/templating/scanner_tests.js b/packages/templating/scanner_tests.js index 4c0ea337a1..304be0c0f3 100644 --- a/packages/templating/scanner_tests.js +++ b/packages/templating/scanner_tests.js @@ -26,7 +26,7 @@ Tinytest.add("templating - html scanner", function (test) { // where content is something simple like the string "Hello" // (passed in as a source string including the quotes). var simpleBody = function (content) { - return "\nUI.body2.contentParts.push(UI.Component.extend({render: (function() {\n var self = this;\n return " + content + ";\n})}));\nMeteor.startup(function () { if (! UI.body2.INSTANTIATED) { UI.materialize(UI.body2, document.body); } });\n"; + return "\nUI.body.contentParts.push(UI.Component.extend({render: (function() {\n var self = this;\n return " + content + ";\n})}));\nMeteor.startup(function () { if (! UI.body.INSTANTIATED) { UI.materialize(UI.body, document.body); } });\n"; }; // arguments are quoted strings like '"hello"' diff --git a/packages/ui/render.js b/packages/ui/render.js index e23baf3931..e8742203fb 100644 --- a/packages/ui/render.js +++ b/packages/ui/render.js @@ -213,11 +213,10 @@ var updateAttributes = function(elem, newAttrs, handlers) { for (var k in newAttrs) { var handler = null; var oldValue; - var value = attributeValueToString(newAttrs[k]); + var value = newAttrs[k]; if ((! handlers) || (! handlers.hasOwnProperty(k))) { if (value !== null) { // make new handler - checkAttributeName(k); handler = makeAttributeHandler(k, value); if (handlers) handlers[k] = handler; @@ -359,7 +358,7 @@ var materialize = function (node, parent, before, parentComponent) { // for example, maybe some of them go in the HTML package. UI.materialize = materialize; -UI.body2 = UI.Component.extend({ +UI.body = UI.Component.extend({ kind: 'body', contentParts: [], render: function () {