mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
some render tests
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
var UI = UI2;
|
||||
|
||||
var ATTRIBUTE_NAME_REGEX = /^[^\s"'>/=/]+$/;
|
||||
|
||||
@@ -76,7 +77,8 @@ _extend(AttributeManager.prototype, {
|
||||
var handlers = self.handlers;
|
||||
|
||||
component.autorun(function (c) {
|
||||
if (component.stage !== Component.BUILT ||
|
||||
if ((! component.isBuilt) ||
|
||||
component.isDestroyed ||
|
||||
! component.containsElement(element)) {
|
||||
c.stop();
|
||||
return;
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
// A very basic operation like Underscore's `_.extend` that
|
||||
// copies `src`'s own, enumerable properties onto `tgt` and
|
||||
// returns `tgt`.
|
||||
_extend = function (tgt, src) {
|
||||
for (var k in src)
|
||||
if (src.hasOwnProperty(k))
|
||||
tgt[k] = src[k];
|
||||
return tgt;
|
||||
};
|
||||
|
||||
// @export UI2
|
||||
var UI = UI2 = {
|
||||
nextGuid: 2, // Component is 1!
|
||||
@@ -14,78 +24,18 @@ var UI = UI2 = {
|
||||
// create instances (and the hope is we can gloss over the
|
||||
// difference in the docs).
|
||||
|
||||
Component: {
|
||||
// If a Component has a `typeName` property set via `extend`,
|
||||
// we make it use that name when printed in Chrome Dev Tools.
|
||||
// If you then extend this Component and don't supply any
|
||||
// new typeName, it should use the same typeName (or the
|
||||
// most specific one in the case of an `extend` chain with
|
||||
// `typeName` set at multiple points).
|
||||
//
|
||||
// To accomplish this, keeping performance in mind,
|
||||
// any Component where `typeName` is explicitly set
|
||||
// also has a function property `_constr` whose source-code
|
||||
// name is `typeName`. `extend` creates this `_constr`
|
||||
// function, which can then be used internally as a
|
||||
// constructor to quickly create new instances that
|
||||
// pretty-print correctly.
|
||||
typeName: "Component",
|
||||
_constr: function Component() {},
|
||||
Component: (function (constr) {
|
||||
// Make sure the "class name" that Chrome infers for
|
||||
// UI.Component is "Component", and that
|
||||
// `new UI.Component._constr` (which is what `extend`
|
||||
// does) also produces objects whose inferred class
|
||||
// name is "Component". Chrome's name inference rules
|
||||
// are a little mysterious, but a function name in
|
||||
// the source code (as in `function Component() {}`)
|
||||
// seems to be reliable and high precedence.
|
||||
return _extend(new constr, {_constr: constr});
|
||||
})(function Component() {}),
|
||||
|
||||
_super: null,
|
||||
guid: 1,
|
||||
|
||||
extend: function (props) {
|
||||
// this function should never cause `props` to be
|
||||
// mutated in case people want to reuse `props` objects
|
||||
// in a mixin-like way.
|
||||
|
||||
if (this.isInited)
|
||||
// Disallow extending inited Components so that
|
||||
// inited Components don't inherit instance-specific
|
||||
// properties from other inited Components, just
|
||||
// default values.
|
||||
throw new Error("Can't extend an inited Component");
|
||||
|
||||
// Any Component with a typeName of "Foo" (say) is given
|
||||
// a `._constr` of the form `function Foo() {}`.
|
||||
if (props && props.typeName)
|
||||
this._constr =
|
||||
Function("return function " +
|
||||
sanitizeTypeName(props.typeName) +
|
||||
"() {};")();
|
||||
|
||||
// We don't know where we're getting `_constr` from --
|
||||
// it might be from some supertype -- just that it has
|
||||
// the right function name. So set the `prototype`
|
||||
// property each time we use it as a constructor.
|
||||
this._constr.prototype = this;
|
||||
|
||||
var c = new this._constr;
|
||||
if (props)
|
||||
_extend(c, props);
|
||||
|
||||
// for efficient Component instantiations, we assign
|
||||
// as few things as possible here.
|
||||
c._super = this;
|
||||
c.guid = UI.nextGuid++;
|
||||
|
||||
return c;
|
||||
},
|
||||
|
||||
// `x.isa(Foo)` where `x` is a Component returns `true`
|
||||
// if `x` is `Foo` or a Component that descends from
|
||||
// (transitively extends) `Foo`.
|
||||
isa: function (obj) {
|
||||
var x = this;
|
||||
while (x) {
|
||||
if (x === obj)
|
||||
return true;
|
||||
x = x._super;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
isComponent: function (obj) {
|
||||
return obj && obj.isa === UI.Component.isa;
|
||||
},
|
||||
@@ -102,15 +52,86 @@ var UI = UI2 = {
|
||||
}
|
||||
};
|
||||
|
||||
// A very basic operation like Underscore's `_.extend` that
|
||||
// copies `src`'s own, enumerable properties onto `tgt` and
|
||||
// returns `tgt`.
|
||||
_extend = function (tgt, src) {
|
||||
for (var k in src)
|
||||
if (src.hasOwnProperty(k))
|
||||
tgt[k] = src[k];
|
||||
return tgt;
|
||||
};
|
||||
_extend(UI.Component, {
|
||||
// If a Component has a `typeName` property set via `extend`,
|
||||
// we make it use that name when printed in Chrome Dev Tools.
|
||||
// If you then extend this Component and don't supply any
|
||||
// new typeName, it should use the same typeName (or the
|
||||
// most specific one in the case of an `extend` chain with
|
||||
// `typeName` set at multiple points).
|
||||
//
|
||||
// To accomplish this, keeping performance in mind,
|
||||
// any Component where `typeName` is explicitly set
|
||||
// also has a function property `_constr` whose source-code
|
||||
// name is `typeName`. `extend` creates this `_constr`
|
||||
// function, which can then be used internally as a
|
||||
// constructor to quickly create new instances that
|
||||
// pretty-print correctly.
|
||||
typeName: "Component",
|
||||
_constr: function Component() {},
|
||||
|
||||
_super: null,
|
||||
guid: 1,
|
||||
|
||||
extend: function (props) {
|
||||
// this function should never cause `props` to be
|
||||
// mutated in case people want to reuse `props` objects
|
||||
// in a mixin-like way.
|
||||
|
||||
if (this.isInited)
|
||||
// Disallow extending inited Components so that
|
||||
// inited Components don't inherit instance-specific
|
||||
// properties from other inited Components, just
|
||||
// default values.
|
||||
throw new Error("Can't extend an inited Component");
|
||||
|
||||
var constr;
|
||||
var constrMade = false;
|
||||
// Any Component with a typeName of "Foo" (say) is given
|
||||
// a `._constr` of the form `function Foo() {}`.
|
||||
if (props && props.typeName) {
|
||||
constr = Function("return function " +
|
||||
sanitizeTypeName(props.typeName) +
|
||||
"() {};")();
|
||||
constrMade = true;
|
||||
} else {
|
||||
constr = this._constr;
|
||||
}
|
||||
|
||||
// We don't know where we're getting `constr` from --
|
||||
// it might be from some supertype -- just that it has
|
||||
// the right function name. So set the `prototype`
|
||||
// property each time we use it as a constructor.
|
||||
constr.prototype = this;
|
||||
|
||||
var c = new constr;
|
||||
if (constrMade)
|
||||
c._constr = constr;
|
||||
|
||||
if (props)
|
||||
_extend(c, props);
|
||||
|
||||
// for efficient Component instantiations, we assign
|
||||
// as few things as possible here.
|
||||
c._super = this;
|
||||
c.guid = UI.nextGuid++;
|
||||
|
||||
return c;
|
||||
},
|
||||
|
||||
// `x.isa(Foo)` where `x` is a Component returns `true`
|
||||
// if `x` is `Foo` or a Component that descends from
|
||||
// (transitively extends) `Foo`.
|
||||
isa: function (obj) {
|
||||
var x = this;
|
||||
while (x) {
|
||||
if (x === obj)
|
||||
return true;
|
||||
x = x._super;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
callChainedCallback = function (comp, propName) {
|
||||
if (comp._super)
|
||||
@@ -532,7 +553,6 @@ _extend(UI.Component, {
|
||||
_attach: function (parentNode, beforeNode) {
|
||||
var self = this;
|
||||
|
||||
this._requireBuilt();
|
||||
this._requireNotDestroyed();
|
||||
|
||||
if (! self.isInited)
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
|
||||
// All `<body>` tags in HTML files are compiled to extend
|
||||
// Body. If you put helpers and events on Body, they all
|
||||
// inherit them.
|
||||
UI.Body = Component.extend({isRoot: true});
|
||||
var UI = UI2;
|
||||
var Component = UI.Component;
|
||||
|
||||
UI.Text = Component.extend({
|
||||
typeName: 'Text',
|
||||
@@ -11,8 +8,8 @@ UI.Text = Component.extend({
|
||||
return String(x == null ? '' : x);
|
||||
},
|
||||
render: function (buf) {
|
||||
var data = this.data();
|
||||
buf(this._encodeEntities(this._stringify(data)));
|
||||
var data = this.get();
|
||||
buf.write(this._encodeEntities(this._stringify(data)));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -22,11 +19,11 @@ UI.HTML = Component.extend({
|
||||
return String(x == null ? '' : x);
|
||||
},
|
||||
render: function (buf) {
|
||||
var data = this.data();
|
||||
buf(this._stringify(data));
|
||||
var data = this.get();
|
||||
buf.write(this._stringify(data));
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
UI.If = Component.extend({
|
||||
typeName: 'If',
|
||||
init: function () {
|
||||
@@ -89,4 +86,5 @@ UI.Counter = Component.extend({
|
||||
self.increment();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
*/
|
||||
14
packages/ui2/fields.js
Normal file
14
packages/ui2/fields.js
Normal file
@@ -0,0 +1,14 @@
|
||||
var UI = UI2;
|
||||
|
||||
_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);
|
||||
},
|
||||
// convenient syntax
|
||||
withData: function (data) {
|
||||
return this.extend({data: data});
|
||||
}
|
||||
});
|
||||
@@ -8,7 +8,11 @@ Package.on_use(function (api) {
|
||||
api.use('ejson');
|
||||
api.use('ordered-dict');
|
||||
|
||||
api.add_files(['base.js']);
|
||||
api.add_files(['base.js',
|
||||
'attrs.js',
|
||||
'render.js',
|
||||
'fields.js',
|
||||
'components.js']);
|
||||
});
|
||||
|
||||
Package.on_test(function (api) {
|
||||
@@ -17,6 +21,7 @@ Package.on_test(function (api) {
|
||||
api.use(['test-helpers', 'underscore'], 'client');
|
||||
|
||||
api.add_files([
|
||||
'base_tests.js'
|
||||
'base_tests.js',
|
||||
'render_tests.js'
|
||||
], 'client');
|
||||
});
|
||||
|
||||
@@ -97,7 +97,7 @@ makeRenderBuffer = function (component, options) {
|
||||
componentsToAttach[commentString] = arg;
|
||||
} else if (arg.extend) {
|
||||
// `{extend: componentOrFunction, props: object}`
|
||||
if (UI.isComponent(arg.extend)) {
|
||||
/* if (UI.isComponent(arg.extend)) {
|
||||
// In `{extend: comp}` with no `props`, it's ok
|
||||
// for `comp` to be already inited. This lets
|
||||
// you write `{{> foo}}` to insert already-inited
|
||||
@@ -133,8 +133,8 @@ makeRenderBuffer = function (component, options) {
|
||||
var curChild = curType.create(arg.args);
|
||||
handle(curChild);
|
||||
} else {
|
||||
throw new Error("Expected 'type' to be Component or function");
|
||||
}
|
||||
throw new Error("Expected 'extend' to be Component or function");
|
||||
}*/
|
||||
} else if (arg.attrs) {
|
||||
// `{attrs: functionOrDictionary }`
|
||||
// attrs object inserts zero or more `name="value"` items
|
||||
@@ -175,7 +175,8 @@ makeRenderBuffer = function (component, options) {
|
||||
}
|
||||
};
|
||||
|
||||
var buf = function (/*args*/) {
|
||||
var buf = {};
|
||||
buf.write = function (/*args*/) {
|
||||
for (var i = 0; i < arguments.length; i++)
|
||||
handle(arguments[i]);
|
||||
};
|
||||
@@ -204,13 +205,13 @@ makeRenderBuffer = function (component, options) {
|
||||
if (n === root.lastChild)
|
||||
end = comp;
|
||||
}
|
||||
if (comp.stage === Component.INITIAL) {
|
||||
if (! comp.isInited) {
|
||||
component.add(comp);
|
||||
} else if (comp.parent !== component) {
|
||||
throw new Error("Component used in render must be a child " +
|
||||
"(or addable as one)");
|
||||
}
|
||||
comp.attach(parent, n);
|
||||
comp._attach(parent, n);
|
||||
parent.removeChild(n);
|
||||
delete componentsToAttach[n.nodeValue];
|
||||
}
|
||||
|
||||
66
packages/ui2/render_tests.js
Normal file
66
packages/ui2/render_tests.js
Normal file
@@ -0,0 +1,66 @@
|
||||
var UI = UI2;
|
||||
|
||||
Tinytest.add("ui - render", function (test) {
|
||||
var c, R;
|
||||
|
||||
c = UI.Component.extend({
|
||||
render: function (buf) {
|
||||
buf.write("asdf");
|
||||
}
|
||||
});
|
||||
|
||||
c.build();
|
||||
test.equal($(c._offscreen).html(), "asdf");
|
||||
c.destroy();
|
||||
|
||||
|
||||
|
||||
c = UI.Component.extend({
|
||||
render: function (buf) {
|
||||
buf.write("<div>asdf</div>");
|
||||
}
|
||||
});
|
||||
|
||||
c.build();
|
||||
test.equal($(c._offscreen).html(), "<div>asdf</div>");
|
||||
c.destroy();
|
||||
|
||||
|
||||
|
||||
R = ReactiveVar("blam");
|
||||
c = UI.Component.extend({
|
||||
render: function (buf) {
|
||||
buf.write(
|
||||
"foo",
|
||||
UI.Text.withData(function () { return R.get(); }),
|
||||
"bar");
|
||||
}
|
||||
});
|
||||
|
||||
c.build();
|
||||
test.equal($(c._offscreen).html(), "fooblambar");
|
||||
R.set("ki");
|
||||
Deps.flush();
|
||||
test.equal($(c._offscreen).html(), "fookibar");
|
||||
c.destroy();
|
||||
|
||||
|
||||
|
||||
R = ReactiveVar("<hr>");
|
||||
c = UI.Component.extend({
|
||||
render: function (buf) {
|
||||
buf.write(
|
||||
"foo",
|
||||
UI.HTML.withData(function () { return R.get(); }),
|
||||
"bar");
|
||||
}
|
||||
});
|
||||
|
||||
c.build();
|
||||
test.equal($(c._offscreen).html(), "foo<hr>bar");
|
||||
R.set("<div>hi</div>");
|
||||
Deps.flush();
|
||||
test.equal($(c._offscreen).html(), "foo<div>hi</div>bar");
|
||||
c.destroy();
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user