mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
202 lines
6.4 KiB
JavaScript
202 lines
6.4 KiB
JavaScript
|
|
UI.Text = Component.extend({
|
|
kind: 'Text',
|
|
_encodeEntities: UI.encodeSpecialEntities,
|
|
_stringify: function (x) {
|
|
return String(x == null ? '' : x);
|
|
},
|
|
render: function (buf) {
|
|
var data = this.get();
|
|
|
|
if (data instanceof Handlebars.SafeString)
|
|
buf.write(this._stringify(data.toString())); // don't escape
|
|
else
|
|
buf.write(this._encodeEntities(this._stringify(data)));
|
|
}
|
|
});
|
|
|
|
UI.HTML = Component.extend({
|
|
kind: 'HTML',
|
|
_stringify: function (x) {
|
|
return String(x == null ? '' : x);
|
|
},
|
|
render: function (buf) {
|
|
var data = this.get();
|
|
buf.write(this._stringify(data));
|
|
}
|
|
});
|
|
|
|
UI.If = Component.extend({
|
|
kind: 'If',
|
|
init: function () {
|
|
// XXX this probably deserves a better explanation if this code is
|
|
// going to stay with us.
|
|
this.condition = this.data;
|
|
|
|
// content doesn't see the condition as `data`
|
|
delete this.data;
|
|
// XXX I guess this means it's kosher to mutate properties
|
|
// of a Component during init (but presumably not before
|
|
// or after)?
|
|
},
|
|
render: function (buf) {
|
|
var self = this;
|
|
// re-render if and only if condition changes
|
|
var condition = Deps.isolateValue(function () {
|
|
var cond = self.get('condition');
|
|
|
|
// empty arrays are treated as falsey values
|
|
if (cond instanceof Array && cond.length === 0)
|
|
return false;
|
|
else
|
|
return !! cond;
|
|
});
|
|
|
|
buf.write(condition ? self.__content : self.__elseContent);
|
|
}
|
|
});
|
|
|
|
UI.Unless = Component.extend({
|
|
kind: 'Unless',
|
|
init: function () {
|
|
this.condition = this.data;
|
|
delete this.data;
|
|
},
|
|
render: function (buf) {
|
|
var self = this;
|
|
// re-render if and only if condition changes
|
|
var condition = Deps.isolateValue(function () {
|
|
var cond = self.get('condition');
|
|
|
|
// empty arrays are treated as falsey values
|
|
if (cond instanceof Array && cond.length === 0)
|
|
return false;
|
|
else
|
|
return !! cond;
|
|
});
|
|
|
|
buf.write(condition ? self.__elseContent : self.__content);
|
|
}
|
|
});
|
|
|
|
UI.With = Component.extend({
|
|
kind: 'With',
|
|
render: function (buf) {
|
|
buf.write(this.__content);
|
|
}
|
|
});
|
|
|
|
var callIfFunction = function (value) {
|
|
return (typeof value === 'function') ? value() : value;
|
|
};
|
|
var evalKeywordArgs = function (dict) {
|
|
var ret = {};
|
|
_.each(dict, function (v, k) {
|
|
ret[k] = callIfFunction(v);
|
|
});
|
|
return ret;
|
|
};
|
|
|
|
UI.DynamicComponent = Component.extend({
|
|
kind: 'DynamicComponent',
|
|
render: function (buf) {
|
|
var kind = this.compKind;
|
|
var args = this.compArgs;
|
|
// `isBlock` means this is a block call like `{{#foo}}...{{/foo}}`
|
|
// rather than an insertion like `{{>foo}}`. Note that we can't
|
|
// tell what kind of call this is otherwise.
|
|
var isBlock = this.isBlock;
|
|
|
|
var kwArgs = (args && args.length && args[0]) || {};
|
|
var posArgs = (args && args.length > 1 && args.slice(1)) || [];
|
|
|
|
var props = _.extend({}, kwArgs);
|
|
if (typeof kind === 'function') {
|
|
// Calling a helper function as a template. Evaluate the
|
|
// arguments and pass them to the function to get back
|
|
// a component. Completely different use of args than
|
|
// when calling a bare component like `Template.foo` or
|
|
// a "helper" that is a constant component (in which case
|
|
// the args are used to extend the component).
|
|
//
|
|
// `kind` should be already bound with a `this`, so it
|
|
// doesn't matter what we pass in for the first argument
|
|
// to `apply`. Same with arguments.
|
|
var args = _.map(posArgs, callIfFunction);
|
|
// May invalidate this render:
|
|
var evaledKWArgs = evalKeywordArgs(kwArgs);
|
|
args.push(evaledKWArgs);
|
|
props = null;
|
|
if (isBlock) {
|
|
// Prevent the `content` and `elseContent` keyword arguments
|
|
// from going to the function; send them to the returned
|
|
// component instead. We could send them to the function,
|
|
// but it would have make sure to use them, which is a pain!
|
|
//
|
|
// XXX revisit this when we determine whether `content` and
|
|
// `elseContent` are really treated as keyword args, e.g.
|
|
// whether you can say `{{>if content=... elseContent=...}}`,
|
|
// and when we get rid of DynamicComponent so we don't need
|
|
// this logic.
|
|
delete evaledKWArgs.__content;
|
|
delete evaledKWArgs.__elseContent;
|
|
if (kwArgs.__content || kwArgs.__elseContent) {
|
|
props = { __content: kwArgs.__content,
|
|
__elseContent: kwArgs.__elseContent };
|
|
}
|
|
}
|
|
// May invalidate this render:
|
|
kind = kind.apply(null, args);
|
|
} else {
|
|
// `kind` is a component (or template). we look at the next argument.
|
|
// * if it is a value, pass it as `data` for the component.
|
|
// * if is a function, wrap it to be called with the subseqeunt
|
|
// arguments (which could be either a value or a helper, which
|
|
// gets called)
|
|
if (posArgs && posArgs.length) {
|
|
if (isBlock) {
|
|
// don't pass keyword arguments to the component; they will
|
|
// either go to the function in the first argument or be ignored.
|
|
props = null;
|
|
// see earlier comment about special treatment of `content`
|
|
// and `elseContent` keyword args
|
|
if (kwArgs.__content || kwArgs.__elseContent) {
|
|
props = { __content: kwArgs.__content,
|
|
__elseContent: kwArgs.__elseContent };
|
|
}
|
|
if (typeof posArgs[0] === 'function') {
|
|
var f = posArgs[0];
|
|
posArgs.shift();
|
|
props.data = function() {
|
|
var args = _.map(posArgs, callIfFunction);
|
|
var evaledKWArgs = evalKeywordArgs(kwArgs);
|
|
// see earlier comment
|
|
delete evaledKWArgs.__content;
|
|
delete evaledKWArgs.__elseContent;
|
|
args.push(evaledKWArgs);
|
|
return f.apply(null, args);
|
|
};
|
|
} else {
|
|
if (posArgs.length > 1) {
|
|
throw new Error("Multiple arguments to block helpers only allowed "
|
|
+ "if the first argument is a helper");
|
|
}
|
|
props.data = posArgs[0];
|
|
}
|
|
} else {
|
|
if (posArgs.length > 1) {
|
|
throw new Error("Can't have more than one argument to a template");
|
|
}
|
|
|
|
if (posArgs.length) {
|
|
props.data = posArgs[0];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (kind) {
|
|
buf.write({kind: kind, props: props});
|
|
}
|
|
}
|
|
}); |