mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
port "if"; fix chaining; buf.write(func); more get()
This commit is contained in:
@@ -307,7 +307,7 @@ _.extend(Deps, {
|
||||
},
|
||||
|
||||
// two values are equal if `equals(x, y)`, which defaults to `===`
|
||||
isolate: function (f, equals) {
|
||||
isolateValue: function (f, equals) {
|
||||
if (! Deps.active)
|
||||
return f();
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ UI.If = Component.extend({
|
||||
},
|
||||
render: function (buf) {
|
||||
var self = this;
|
||||
var condition = Deps.isolate(function () {
|
||||
var condition = Deps.isolateValue(function () {
|
||||
return !! self.condition();
|
||||
});
|
||||
buf(condition ? self.content() : self.elseContent());
|
||||
@@ -59,7 +59,7 @@ UI.Unless = Component.extend({
|
||||
},
|
||||
render: function (buf) {
|
||||
var self = this;
|
||||
var condition = Deps.isolate(function () {
|
||||
var condition = Deps.isolateValue(function () {
|
||||
return ! self.condition();
|
||||
});
|
||||
buf(condition ? self.content() : self.elseContent());
|
||||
|
||||
@@ -133,12 +133,18 @@ _extend(UI.Component, {
|
||||
}
|
||||
});
|
||||
|
||||
callChainedCallback = function (comp, propName) {
|
||||
callChainedCallback = function (comp, propName, orig) {
|
||||
// Call `comp.foo`, `comp._super.foo`,
|
||||
// `comp._super._super.foo`, and so on, but in reverse
|
||||
// order, and only if `foo` is an "own property" in each
|
||||
// case. Furthermore, the passed value of `this` should
|
||||
// remain `comp` for all calls (which is achieved by
|
||||
// filling in `orig` when recursing).
|
||||
if (comp._super)
|
||||
callChainedCallback(comp._super, propName);
|
||||
callChainedCallback(comp._super, propName, orig || comp);
|
||||
|
||||
if (comp.hasOwnProperty(propName))
|
||||
comp[propName].call(comp);
|
||||
comp[propName].call(orig || comp);
|
||||
};
|
||||
|
||||
// Make `typeName` a non-empty string starting with an ASCII
|
||||
@@ -410,7 +416,7 @@ _extend(UI.Component, {
|
||||
// building on the client, and it can also be used on the
|
||||
// client or server to generate initial HTML.
|
||||
render: function (buf) {
|
||||
buf.write(this.content.extend());
|
||||
buf.write(this.content);
|
||||
},
|
||||
|
||||
_populate: function (div) {
|
||||
|
||||
@@ -23,46 +23,45 @@ UI.HTML = Component.extend({
|
||||
buf.write(this._stringify(data));
|
||||
}
|
||||
});
|
||||
/*
|
||||
|
||||
UI.If = Component.extend({
|
||||
typeName: 'If',
|
||||
init: function () {
|
||||
// here we implement the idea that the one positional arg to
|
||||
// a component becomes its data by default, but components
|
||||
// like `#if` don't want it to be the data context
|
||||
// seen by the content so they can change it.
|
||||
// the implementation will change (but not the idea)
|
||||
// if Geoff's proposal for extend and args is implemented.
|
||||
// It's also possible the right thing to do is
|
||||
// to have `arg` and `data` be separate.
|
||||
this.condition = this.data;
|
||||
this.data = this.parent.data;
|
||||
// content doesn't see the condition as `data`
|
||||
this.data = null;
|
||||
// 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;
|
||||
var condition = Deps.isolate(function () {
|
||||
return !! self.condition();
|
||||
// re-render if and only if condition changes
|
||||
var condition = Deps.isolateValue(function () {
|
||||
return !! self.get('condition');
|
||||
});
|
||||
buf(condition ? self.content() : self.elseContent());
|
||||
buf.write(condition ? self.content : self.elseContent);
|
||||
}
|
||||
});
|
||||
|
||||
UI.Unless = Component.extend({
|
||||
typeName: 'Unless',
|
||||
init: function () {
|
||||
// see comment in `If`
|
||||
this.condition = this.data;
|
||||
this.data = this.parent.data;
|
||||
this.data = null;
|
||||
},
|
||||
render: function (buf) {
|
||||
var self = this;
|
||||
var condition = Deps.isolate(function () {
|
||||
return ! self.condition();
|
||||
// re-render if and only if condition changes
|
||||
var condition = Deps.isolateValue(function () {
|
||||
return !! self.get('condition');
|
||||
});
|
||||
buf(condition ? self.content() : self.elseContent());
|
||||
buf.write(condition ? self.elseContent : self.content);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
UI.Counter = Component.extend({
|
||||
typeName: "Counter",
|
||||
fields: {
|
||||
|
||||
@@ -1,11 +1,38 @@
|
||||
var UI = UI2;
|
||||
|
||||
var findComponentWithProp = function (id, comp) {
|
||||
while (comp) {
|
||||
if (id in comp)
|
||||
return comp;
|
||||
comp = comp.parent;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
var getData = function (comp) {
|
||||
comp = findComponentWithProp('data', comp);
|
||||
return (comp ?
|
||||
(typeof comp.data === 'function' ?
|
||||
comp.data() : comp.data) :
|
||||
null);
|
||||
};
|
||||
|
||||
_extend(UI.Component, {
|
||||
get: function (id) {
|
||||
// this is the (! id) case where `id` is `""` or absent.
|
||||
// actually it should probably search up the parent tree too.
|
||||
return (typeof this.data === 'function' ?
|
||||
this.data() : this.data);
|
||||
if (! id) {
|
||||
// `id` is `""` or absent/undefined
|
||||
return getData(this);
|
||||
} else {
|
||||
var comp = findComponentWithProp(id, this);
|
||||
if (comp) {
|
||||
// found a method
|
||||
return (typeof comp[id] === 'function' ?
|
||||
comp[id]() : comp[id]);
|
||||
} else {
|
||||
var data = getData(this);
|
||||
return data[id];
|
||||
}
|
||||
}
|
||||
},
|
||||
// convenient syntax
|
||||
withData: function (data) {
|
||||
|
||||
@@ -114,7 +114,8 @@ makeRenderBuffer = function (component, options) {
|
||||
arg = arg.extend();
|
||||
|
||||
handleComponent(arg);
|
||||
} else if (arg.child) {
|
||||
} else if ((typeof arg === 'function') || arg.child) {
|
||||
// `componentFunction`, or
|
||||
// `{child: componentOrFunction, props: object}`
|
||||
|
||||
// In `{child: comp}` with no `props`, it's ok
|
||||
@@ -130,8 +131,15 @@ makeRenderBuffer = function (component, options) {
|
||||
// is uninited and we instantiate a copy, `curComp`
|
||||
// is not that copy, it's the original component used
|
||||
// as a prototype.
|
||||
var curComp = arg.child;
|
||||
var props = arg.props;
|
||||
var curComp, props;
|
||||
if (typeof arg === 'function') {
|
||||
curComp = arg;
|
||||
props = null;
|
||||
} else {
|
||||
curComp = arg.child;
|
||||
props = arg.props;
|
||||
}
|
||||
|
||||
if (typeof curComp === 'function') {
|
||||
var compFunc = curComp;
|
||||
// use `Deps.autorun`, not `component.autorun`,
|
||||
|
||||
@@ -150,6 +150,7 @@ Tinytest.add("ui - render", function (test) {
|
||||
test.equal(which.numListeners(), 0);
|
||||
})();
|
||||
|
||||
|
||||
(function () {
|
||||
var R = ReactiveVar(1);
|
||||
var which = ReactiveVar("H");
|
||||
@@ -170,7 +171,7 @@ Tinytest.add("ui - render", function (test) {
|
||||
var c = UI.Component.extend({
|
||||
render: function (buf) {
|
||||
var self = this;
|
||||
// also, choose which one to use reactively
|
||||
// choose which one to use reactively
|
||||
buf.write({child: function () {
|
||||
return which.get() === "H" ? Hello : World;
|
||||
}, props: {
|
||||
@@ -203,4 +204,95 @@ Tinytest.add("ui - render", function (test) {
|
||||
test.equal(name.numListeners(), 0);
|
||||
})();
|
||||
|
||||
(function () {
|
||||
var which = ReactiveVar("H");
|
||||
|
||||
// two factory (uninited) Components
|
||||
var Hello = UI.Text.withData("hello");
|
||||
var World = UI.Text.withData("world");
|
||||
|
||||
var c = UI.Component.extend({
|
||||
render: function (buf) {
|
||||
var self = this;
|
||||
// choose which one to use reactively
|
||||
buf.write(function () {
|
||||
return which.get() === "H" ? Hello : World;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
c.build();
|
||||
test.equal($(c._offscreen).html(), "hello");
|
||||
which.set("W");
|
||||
Deps.flush();
|
||||
test.equal($(c._offscreen).html(), "world");
|
||||
test.equal(_.keys(c.children).length, 1);
|
||||
which.set("H");
|
||||
Deps.flush();
|
||||
test.equal($(c._offscreen).html(), "hello");
|
||||
test.equal(_.keys(c.children).length, 1);
|
||||
c.destroy();
|
||||
test.equal(which.numListeners(), 0);
|
||||
})();
|
||||
|
||||
});
|
||||
|
||||
Tinytest.add("ui - if/unless", function (test) {
|
||||
var hello = UI.Text.withData("hello");
|
||||
var world = UI.Text.withData("world");
|
||||
var R = ReactiveVar('true');
|
||||
var renderedCounts = [0, 0, 0];
|
||||
var c = UI.Component.extend({
|
||||
rendered: function () { renderedCounts[0]++; },
|
||||
render: function (buf) {
|
||||
buf.write(
|
||||
UI.If.extend({
|
||||
data: function () {
|
||||
return R.get().charAt(0) === 't';
|
||||
},
|
||||
content: hello,
|
||||
elseContent: world,
|
||||
rendered: function () {
|
||||
renderedCounts[1]++;
|
||||
}
|
||||
}),
|
||||
UI.Unless.extend({
|
||||
data: function () {
|
||||
return R.get().charAt(0) === 't';
|
||||
},
|
||||
content: hello,
|
||||
elseContent: world,
|
||||
rendered: function () {
|
||||
renderedCounts[2]++;
|
||||
}
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
c.build();
|
||||
test.equal($(c._offscreen).html(), "helloworld");
|
||||
test.equal(renderedCounts, [1,1,1]);
|
||||
R.set('false');
|
||||
Deps.flush();
|
||||
test.equal($(c._offscreen).html(), "worldhello");
|
||||
test.equal(renderedCounts, [1,2,2]);
|
||||
R.set('true');
|
||||
Deps.flush();
|
||||
test.equal($(c._offscreen).html(), "helloworld");
|
||||
test.equal(renderedCounts, [1,3,3]);
|
||||
R.set('torrid');
|
||||
Deps.flush();
|
||||
test.equal($(c._offscreen).html(), "helloworld");
|
||||
test.equal(renderedCounts, [1,3,3]);
|
||||
R.set('flagrant');
|
||||
Deps.flush();
|
||||
test.equal($(c._offscreen).html(), "worldhello");
|
||||
test.equal(renderedCounts, [1,4,4]);
|
||||
R.set('fromage');
|
||||
Deps.flush();
|
||||
test.equal($(c._offscreen).html(), "worldhello");
|
||||
test.equal(renderedCounts, [1,4,4]);
|
||||
|
||||
c.destroy();
|
||||
test.equal(R.numListeners(), 0);
|
||||
});
|
||||
Reference in New Issue
Block a user