diff --git a/packages/spacebars/spacebars.js b/packages/spacebars/spacebars.js index 43cac2707c..ae126b0753 100644 --- a/packages/spacebars/spacebars.js +++ b/packages/spacebars/spacebars.js @@ -3,7 +3,7 @@ Spacebars = {}; var makeStacheTagStartRegex = function (r) { - return new RegExp(r.source + /(?![{>!#/@])/.source, + return new RegExp(r.source + /(?![{>!#/])/.source, r.ignoreCase ? 'i' : ''); }; @@ -22,8 +22,7 @@ var starts = { COMMENT: makeStacheTagStartRegex(/^\{\{\s*!/), INCLUSION: makeStacheTagStartRegex(/^\{\{\s*>\s*(?!\s)/), BLOCKOPEN: makeStacheTagStartRegex(/^\{\{\s*#\s*(?!\s)/), - BLOCKCLOSE: makeStacheTagStartRegex(/^\{\{\s*\/\s*(?!\s)/), - ANNOTATION: makeStacheTagStartRegex(/^\{\{\s*@\s*(?!\s)/) + BLOCKCLOSE: makeStacheTagStartRegex(/^\{\{\s*\/\s*(?!\s)/) }; var ends = { @@ -197,7 +196,6 @@ Spacebars.parseStacheTag = function (inputString, pos, options) { else if (run(starts.INCLUSION)) type = 'INCLUSION'; else if (run(starts.BLOCKOPEN)) type = 'BLOCKOPEN'; else if (run(starts.BLOCKCLOSE)) type = 'BLOCKCLOSE'; - else if (run(starts.ANNOTATION)) type = 'ANNOTATION'; else error('Unknown stache tag starting with "' + str.slice(0,5) + '"'); @@ -731,8 +729,6 @@ Spacebars.compile = function (inputString, options) { parts.push(codeGenBasicStache(tag, funcInfo)); break; - case 'ANNOTATION': - error("Can't use an annotation stache tag in an attribute name or value"); default: error("Unknown stache tag type: " + tag.type); } @@ -811,8 +807,6 @@ Spacebars.compile = function (inputString, options) { break; case 'COMMENT': break; - case 'ANNOTATION': - error("Annotation stache tag must occur inside an HTML start tag"); default: error("Unexpected tag type: " + tag.type); } @@ -824,48 +818,15 @@ Spacebars.compile = function (inputString, options) { case 'StartTag': var attrs = null; var dynamicAttrs = null; - var annotations = null; _.each(t.data, function (kv) { var name = kv.nodeName; var value = kv.nodeValue; if ((typeof name) !== 'string') { - if (name.length === 1 && - name[0].type === 'ANNOTATION' && - value === '') { - var tag = name[0]; - // XXX support arbitrary, user-defined - // annotations in the future - var annotationName = tag.path.join(''); - if (annotationName !== 'emit') - error("Unknown annotation: " + annotationName); - - // for now, we only allow strings and keyword - // arguments whose values are strings, - // as in `{{@emit "keydown" click="myclick"}}` - var emitData = null; - _.each(tag.args, function (arg) { - if (arg[0] !== 'STRING') - error("Argument values to @emit must be STRING"); - var highEvent = arg[1]; - var lowEvent = arg[2] || highEvent; - emitData = (emitData || {}); - emitData[toJSLiteral(lowEvent)] = - toJSLiteral(highEvent); - }); - if (emitData) { - annotations = (annotations || []); - annotations.push(makeObjectLiteral({ - type: toJSLiteral('emit'), - data: makeObjectLiteral(emitData) - })); - } - } else { - dynamicAttrs = (dynamicAttrs || []); - dynamicAttrs.push([interpolate(name, funcInfo, - INTERPOLATE_DYNAMIC_ATTR), - interpolate(value, funcInfo, - INTERPOLATE_DYNAMIC_ATTR)]); - } + dynamicAttrs = (dynamicAttrs || []); + dynamicAttrs.push([interpolate(name, funcInfo, + INTERPOLATE_DYNAMIC_ATTR), + interpolate(value, funcInfo, + INTERPOLATE_DYNAMIC_ATTR)]); } else { attrs = (attrs || {}); attrs[toJSLiteral(name)] = @@ -880,11 +841,6 @@ Spacebars.compile = function (inputString, options) { return '[' + pair[0] + ', ' + pair[1] + ']'; }).join(', ') + ']'; } - if (annotations) { - options = (options || {}); - options['annotations'] = '[' + - annotations.join(', ') + ']'; - } if (t.self_closing) { options = (options || {}); options['selfClose'] = 'true'; diff --git a/packages/ui/attrs.js b/packages/ui/attrs.js index 5a54e435eb..9b1df25584 100644 --- a/packages/ui/attrs.js +++ b/packages/ui/attrs.js @@ -1,4 +1,3 @@ -var Component = UIComponent; var ATTRIBUTE_NAME_REGEX = /^[^\s"'>/=/]+$/; @@ -128,7 +127,7 @@ _extend(AttributeHandler.prototype, { return ''; return this.name + '="' + - _UI.encodeSpecialEntities(this.stringifyValue(value), true) + '"'; + UI.encodeSpecialEntities(this.stringifyValue(value), true) + '"'; }, stringifyValue: function (value) { return String(value); diff --git a/packages/ui/base.js b/packages/ui/base.js index 18bc53f81b..2792cad54c 100644 --- a/packages/ui/base.js +++ b/packages/ui/base.js @@ -1,5 +1,5 @@ -// @export _UI -_UI = { +// @export UI +UI = { nextGuid: 1 }; @@ -54,7 +54,7 @@ var constrImpl = function (ths, args, type) { ths.data = dataFunc; } - ths.guid = _UI.nextGuid++; + ths.guid = UI.nextGuid++; ths.constructed(); return ths; @@ -241,5 +241,4 @@ Component.include({ } }); -// @export UIComponent -UIComponent = Component; \ No newline at end of file +UI.Component = Component; \ No newline at end of file diff --git a/packages/ui/components.js b/packages/ui/components.js index c31474f1a5..96ae5ac862 100644 --- a/packages/ui/components.js +++ b/packages/ui/components.js @@ -1,8 +1,7 @@ -var Component = UIComponent; -_UI.Text = Component.extend({ +UI.Text = Component.extend({ typeName: 'Text', - _encodeEntities: _UI.encodeSpecialEntities, + _encodeEntities: UI.encodeSpecialEntities, _stringify: function (x) { return String(x == null ? '' : x); }, @@ -12,7 +11,7 @@ _UI.Text = Component.extend({ } }); -_UI.HTML = Component.extend({ +UI.HTML = Component.extend({ typeName: 'HTML', _stringify: function (x) { return String(x == null ? '' : x); @@ -23,7 +22,7 @@ _UI.HTML = Component.extend({ } }); -_UI.If = Component.extend({ +UI.If = Component.extend({ typeName: 'If', render: function (buf) { var self = this; @@ -34,7 +33,18 @@ _UI.If = Component.extend({ } }); -_UI.Counter = Component.extend({ +UI.Unless = Component.extend({ + typeName: 'Unless', + render: function (buf) { + var self = this; + var condition = Deps.isolate(function () { + return ! self.data(); + }); + buf(condition ? self.content() : self.elseContent()); + } +}); + +UI.Counter = Component.extend({ typeName: "Counter", fields: { count: 0 @@ -46,7 +56,7 @@ _UI.Counter = Component.extend({ var self = this; buf("
", - new _UI.Text(function () { + new UI.Text(function () { return self.count(); }), "
"); diff --git a/packages/ui/dom.js b/packages/ui/dom.js index fd86dd402e..f07ff7fb1c 100644 --- a/packages/ui/dom.js +++ b/packages/ui/dom.js @@ -1,4 +1,3 @@ -var Component = UIComponent; var emptyCommentProp = 'meteor-ui-empty'; var createEmptyComment = function (beforeNode) { diff --git a/packages/ui/each.js b/packages/ui/each.js index 4ce025dfce..a2ec0fe47f 100644 --- a/packages/ui/each.js +++ b/packages/ui/each.js @@ -1,7 +1,6 @@ -var Component = UIComponent; // `id` arguments to this class MUST be non-empty strings -_UI.List = Component.extend({ +UI.List = Component.extend({ typeName: 'List', _items: null, // OrderedDict of id -> Component _else: null, // Component @@ -154,9 +153,9 @@ _UI.List = Component.extend({ } }); -_UI.Each = Component.extend({ +UI.Each = Component.extend({ typeName: 'Each', - List: _UI.List, + List: UI.List, _oldData: null, init: function () { var self = this; diff --git a/packages/ui/forms.js b/packages/ui/forms.js index 7a5771a490..369443bd79 100644 --- a/packages/ui/forms.js +++ b/packages/ui/forms.js @@ -1,4 +1,3 @@ -var Component = UIComponent; var getterImpl = function (foo) { diff --git a/packages/ui/lifecycle.js b/packages/ui/lifecycle.js index 89d258a3d2..1b898a8a34 100644 --- a/packages/ui/lifecycle.js +++ b/packages/ui/lifecycle.js @@ -1,4 +1,3 @@ -var Component = UIComponent; Component.define({ INITIAL: '', diff --git a/packages/ui/lookup.js b/packages/ui/lookup.js new file mode 100644 index 0000000000..b5f8e69676 --- /dev/null +++ b/packages/ui/lookup.js @@ -0,0 +1,46 @@ + +var global = (function () { return this; })(); + +Component.include({ + lookup: function (id) { + var self = this; + + var result = null; + var thisToBind = null; + + // XXX figure out what this should really do, + // and how custom component classes should + // hook into this behavior. + + if (! id) { + result = self.data(); + } else if (id in self) { + result = self[id]; + thisToBind = self; + } else if (id === 'if') { + result = UI.If; + } else if (id === 'each') { + result = UI.Each; + } else if (id === 'unless') { + result = UI.Unless; + } else if (id === 'with') { + result = Component; + } else if (id in global) { + result = global[id]; + thisToBind = self.data(); + } else { + var data = self.data(); + if (data != null) { + thisToBind = data; + result = data[id]; + } + } + + if (thisToBind && + typeof result === 'function' && + ! Component.isType(result)) + return _.bind(result, thisToBind); + + return result; + } +}); diff --git a/packages/ui/component.js b/packages/ui/old/component.js similarity index 100% rename from packages/ui/component.js rename to packages/ui/old/component.js diff --git a/packages/ui/library.js b/packages/ui/old/library.js similarity index 100% rename from packages/ui/library.js rename to packages/ui/old/library.js diff --git a/packages/ui/renderbuffer.js b/packages/ui/old/renderbuffer.js similarity index 100% rename from packages/ui/renderbuffer.js rename to packages/ui/old/renderbuffer.js diff --git a/packages/ui/package.js b/packages/ui/package.js index 16c44f21bb..f7e6c5a3c8 100644 --- a/packages/ui/package.js +++ b/packages/ui/package.js @@ -20,9 +20,7 @@ Package.on_use(function (api) { 'forms.js', 'each.js', 'components.js', - - 'component.js', 'renderbuffer.js', - 'library.js'], + 'lookup.js'], 'client'); }); diff --git a/packages/ui/render.js b/packages/ui/render.js index cdd0dd504e..4e305ba5b0 100644 --- a/packages/ui/render.js +++ b/packages/ui/render.js @@ -1,4 +1,3 @@ -var Component = UIComponent; var ESCAPED_CHARS_UNQUOTED_REGEX = /[&<>]/g; var ESCAPED_CHARS_QUOTED_REGEX = /[&<>"]/g; @@ -13,7 +12,7 @@ var escapeOne = function(c) { return escapeMap[c]; }; -_UI.encodeSpecialEntities = function (text, isQuoted) { +UI.encodeSpecialEntities = function (text, isQuoted) { // Encode Unicode characters to HTML entities. // // This implementation just encodes the characters that otherwise diff --git a/packages/ui/tree.js b/packages/ui/tree.js index 9df4fd8c67..176a7b261e 100644 --- a/packages/ui/tree.js +++ b/packages/ui/tree.js @@ -1,4 +1,3 @@ -var Component = UIComponent; // this is a shared object that lives on prototypes; // don't ever mutate it!