From 25dafeb38f889602e989e44d4d5d9bb09483ceb5 Mon Sep 17 00:00:00 2001 From: David Greenspan Date: Mon, 10 Jun 2013 20:55:41 -0700 Subject: [PATCH] more spacebars WIP --- packages/spacebars/spacebars.js | 77 +++++++++++++++++++++++++++------ packages/ui/renderbuffer.js | 29 +++++++++++++ 2 files changed, 93 insertions(+), 13 deletions(-) diff --git a/packages/spacebars/spacebars.js b/packages/spacebars/spacebars.js index 55488e61a8..af6614c255 100644 --- a/packages/spacebars/spacebars.js +++ b/packages/spacebars/spacebars.js @@ -487,6 +487,21 @@ var toJSLiteral = function (obj) { .replace(/\u2029/g, '\\u2029')); }; +// takes an object whose keys and values are strings of +// JavaScript source code and returns the source code +// of an object literal. +var makeObjectLiteral = function (obj) { + var buf = []; + buf.push('{'); + for (var k in obj) { + if (buf.length > 1) + buf.push(', '); + buf.push(k, ':', obj[k]); + } + buf.push('}'); + return buf.join(''); +}; + Spacebars.compile = function (inputString) { var tree; if (typeof inputString === 'object') { @@ -495,7 +510,25 @@ Spacebars.compile = function (inputString) { tree = Spacebars.parse(inputString); } - // XXX rewrite interpolate + // XXX rewrite interpolate. + // + // Should now return the source code of either a + // string or a (reactive) function. Ideally it is + // a simple string if possible. + // + // Oh snap, can't do components this way. + // Only double and triple stache. + // Should first write the logic that parses out + // block helpers and inclusions in a run of Characters, + // in tokensToFunc. These tags aren't allowed in an + // interpolation, only double-stache and triple-stache are. + // + // Will need to write the lookup rules for component names, + // helper functions, and values. Maybe it's the same? + // Delegates to `component.lookup(path)`? + // + // We will probably lose the `{{#if equal a b}}` convenience + // syntax (but maybe introduce new syntax for this later). var interpolate = function (strOrArray, indent) { if (typeof strOrArray === "string") return toJSLiteral(strOrArray); @@ -552,27 +585,45 @@ Spacebars.compile = function (inputString) { _.each(tokens, function (t) { switch (t.type) { case 'Characters': - // XXX what does interpolate do here? - js += indent + 'html.text(' + interpolate(t.data, indent) +');\n'; + js += indent + 'buf.text(' + interpolate(t.data, indent) +');\n'; break; case 'StartTag': - // XXX take `t.data` and generate an appropriate + // XXX Take `t.data` and generate an appropriate // attrs argument. - // Also, emit the `selfClose` option. - js += indent + 'html.openTag(' + toJSLiteral(t.name) + - (t.data.length ? ', [' + _.map(t.data, function (kv) { - return '[' + interpolate(kv.nodeName, indent) + ', ' + - interpolate(kv.nodeValue, indent) + ']'; - }).join(', ') + ']' : '') + ');\n'; + var attrs = null; + var dynamicAttrs = null; + _.each(t.data, function (kv) { + var name = kv.nodeName; + var value = kv.nodeValue; + if ((typeof name) !== 'string') { + dynamicAttrs = (dynamicAttrs || []); + dynamicAttrs.push([interpolate(name, indent), + interpolate(value, indent)]); + } else { + attrs = (attrs || {}); + attrs[toJSLiteral(name)] = + interpolate(value, indent); + } + }); + var options = null; + if (dynamicAttrs) { + options = (options || {}); + options['dynamicAttrs'] = makeObjectLiteral(dynamicAttrs); + } + // XXX Pass the `selfClose` option. + js += indent + 'buf.openTag(' + toJSLiteral(t.name) + + ((attrs || options) ? ', ' + makeObjectLiteral(attrs) : '') + + (options ? ', ' + makeObjectLiteral(options) : '') + + ');\n'; break; case 'EndTag': - js += indent + 'html.close(' + interpolate(t.name, indent) + ');\n'; + js += indent + 'buf.close(' + toJSLiteral(t.name) + ');\n'; break; case 'Comment': - js += indent + 'html.comment(' + interpolate(t.name, indent) + ');\n'; + js += indent + 'buf.comment(' + interpolate(t.name, indent) + ');\n'; break; case 'DocType': - js += indent + 'html.doctype(' + toJSLiteral(t.name) + ', ' + + js += indent + 'buf.doctype(' + toJSLiteral(t.name) + ', ' + toJSLiteral({correct: t.correct, publicId: t.publicId, systemId: t.systemId}) + ');\n'; break; diff --git a/packages/ui/renderbuffer.js b/packages/ui/renderbuffer.js index cda0e7ba44..07c562180f 100644 --- a/packages/ui/renderbuffer.js +++ b/packages/ui/renderbuffer.js @@ -53,6 +53,8 @@ var updateDOMAttribute = function (component, elemKey, attrName, _.extend(RenderBuffer.prototype, { _encodeEntities: encodeEntities, + // XXX implement dynamicAttrs option, + // takes [[k, v], ...] openTag: function (tagName, attrs, options) { var self = this; @@ -174,6 +176,33 @@ _.extend(RenderBuffer.prototype, { self._childrenToAttach[commentString] = childComp; }, + comment: function (stringOrFunction) { + // XXX making comments reactively update seems + // right; consider doing that. + + var self = this; + + var content; + if (typeof stringOrFunction === 'function') { + var func = stringOrFunction; + content = func(); + } else { + if (typeof stringOrFunction !== 'string') + throw new Error("string required"); + content = stringOrFunction; + } + + // comments can't have "--" in them in HTML. + // just strip those so that we don't run into trouble. + content = content.replace(/--/g, ''); + self._htmlBuf.push(''); + }, + doctype: function (name, options) { + var buf = this._htmlBuf; + buf.push(''); + }, build: function () { var self = this;