mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
port all packages to new Deps (tests pass)
This commit is contained in:
@@ -6,18 +6,18 @@
|
||||
};
|
||||
|
||||
var loggingIn = false;
|
||||
var loggingInListeners = new Meteor.deps._ContextSet;
|
||||
var loggingInVar = new Deps.Variable;
|
||||
// This is mostly just called within this file, but Meteor.loginWithPassword
|
||||
// also uses it to make loggingIn() be true during the beginPasswordExchange
|
||||
// method call too.
|
||||
Accounts._setLoggingIn = function (x) {
|
||||
if (loggingIn !== x) {
|
||||
loggingIn = x;
|
||||
loggingInListeners.invalidateAll();
|
||||
loggingInVar.changed();
|
||||
}
|
||||
};
|
||||
Meteor.loggingIn = function () {
|
||||
loggingInListeners.addCurrentContext();
|
||||
loggingInVar.changed();
|
||||
return loggingIn;
|
||||
};
|
||||
|
||||
@@ -181,10 +181,10 @@
|
||||
// XXX this can be simplified if we merge in
|
||||
// https://github.com/meteor/meteor/pull/273
|
||||
var loginServicesConfigured = false;
|
||||
var loginServicesConfiguredListeners = new Meteor.deps._ContextSet;
|
||||
var loginServicesConfiguredVar = new Deps.Variable;
|
||||
Meteor.subscribe("meteor.loginServiceConfiguration", function () {
|
||||
loginServicesConfigured = true;
|
||||
loginServicesConfiguredListeners.invalidateAll();
|
||||
loginServicesConfiguredVar.changed();
|
||||
});
|
||||
|
||||
// A reactive function returning whether the
|
||||
@@ -196,7 +196,7 @@
|
||||
return true;
|
||||
|
||||
// not yet complete, save the context for invalidation once we are.
|
||||
loginServicesConfiguredListeners.addCurrentContext();
|
||||
Deps.depend(loginServicesConfiguredVar);
|
||||
return false;
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -54,7 +54,7 @@ if (Meteor.isClient) (function () {
|
||||
// Set up a reactive context that only refreshes when Meteor.user() is
|
||||
// invalidated.
|
||||
var loaded = false;
|
||||
var handle = Meteor.autorun(function () {
|
||||
var handle = Deps.autorun(function () {
|
||||
if (Meteor.user() && Meteor.user().emails)
|
||||
loaded = true;
|
||||
});
|
||||
@@ -66,7 +66,7 @@ if (Meteor.isClient) (function () {
|
||||
// By the time of the login callback, the user should be loaded.
|
||||
test.isTrue(Meteor.user().emails);
|
||||
// Flushing should get us the autorun as well.
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.isTrue(loaded);
|
||||
handle.stop();
|
||||
}));
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
Template._loginButtons.events({
|
||||
'click #login-name-link, click #login-sign-in-link': function () {
|
||||
loginButtonsSession.set('dropdownVisible', true);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
correctDropdownZIndexes();
|
||||
},
|
||||
'click .login-close-text': function () {
|
||||
@@ -85,7 +85,7 @@
|
||||
loginButtonsSession.set('inSignupFlow', true);
|
||||
loginButtonsSession.set('inForgotPasswordFlow', false);
|
||||
// force the ui to update so that we have the approprate fields to fill in
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
// update new fields with appropriate defaults
|
||||
if (username !== null)
|
||||
@@ -121,7 +121,7 @@
|
||||
loginButtonsSession.set('inSignupFlow', false);
|
||||
loginButtonsSession.set('inForgotPasswordFlow', true);
|
||||
// force the ui to update so that we have the approprate fields to fill in
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
// update new fields with appropriate defaults
|
||||
if (email !== null)
|
||||
@@ -141,7 +141,7 @@
|
||||
loginButtonsSession.set('inSignupFlow', false);
|
||||
loginButtonsSession.set('inForgotPasswordFlow', false);
|
||||
// force the ui to update so that we have the approprate fields to fill in
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
if (document.getElementById('login-username'))
|
||||
document.getElementById('login-username').value = username;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
this.invalidated = false;
|
||||
};
|
||||
|
||||
_.extend(Computation.prototype, {
|
||||
_.extend(Deps.Computation.prototype, {
|
||||
run: function (f) {
|
||||
var previous = Deps.currentComputation;
|
||||
Deps.currentComputation = this;
|
||||
@@ -60,8 +60,10 @@
|
||||
this._callbacks.push(f);
|
||||
},
|
||||
|
||||
// Make this computation depend on v. Return true
|
||||
// if this is a new dependency.
|
||||
depend: function (v) {
|
||||
v._addDependent(this);
|
||||
return v._addDependent(this);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -69,7 +71,7 @@
|
||||
this._dependentsById = {};
|
||||
};
|
||||
|
||||
_.extend(Variable.prototype, {
|
||||
_.extend(Deps.Variable.prototype, {
|
||||
// Adds `computation` to this set if it is not already
|
||||
// present. Returns true if `computation` is a new member of the set.
|
||||
_addDependent: function (computation) {
|
||||
@@ -98,9 +100,13 @@
|
||||
});
|
||||
|
||||
_.extend(Deps, {
|
||||
// Make the current computation depend on v. Returns true
|
||||
// if this is a new dependency. If there is no current
|
||||
// computation, does nothing and returns false.
|
||||
depend: function (v) {
|
||||
if (Deps.active)
|
||||
v._addDependent(Deps.currentComputation);
|
||||
return v._addDependent(Deps.currentComputation);
|
||||
return false;
|
||||
},
|
||||
|
||||
flush: function () {
|
||||
|
||||
@@ -1,46 +1,46 @@
|
||||
Tinytest.add('deps - autorun', function (test) {
|
||||
var listeners = new Meteor.deps._ContextSet;
|
||||
var v = new Deps.Variable;
|
||||
var x = 0;
|
||||
var handle = Meteor.autorun(function (handle) {
|
||||
listeners.addCurrentContext();
|
||||
var handle = Deps.autorun(function (handle) {
|
||||
Deps.depend(v);
|
||||
++x;
|
||||
});
|
||||
test.equal(x, 1);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(x, 1);
|
||||
listeners.invalidateAll();
|
||||
v.changed();
|
||||
test.equal(x, 1);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(x, 2);
|
||||
listeners.invalidateAll();
|
||||
v.changed();
|
||||
test.equal(x, 2);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(x, 3);
|
||||
listeners.invalidateAll();
|
||||
v.changed();
|
||||
// Prevent the function from running further.
|
||||
handle.stop();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(x, 3);
|
||||
listeners.invalidateAll();
|
||||
Meteor.flush();
|
||||
v.changed();
|
||||
Deps.flush();
|
||||
test.equal(x, 3);
|
||||
|
||||
Meteor.autorun(function (internalHandle) {
|
||||
listeners.addCurrentContext();
|
||||
Deps.autorun(function (internalHandle) {
|
||||
Deps.depend(v);
|
||||
++x;
|
||||
if (x == 6)
|
||||
internalHandle.stop();
|
||||
});
|
||||
test.equal(x, 4);
|
||||
listeners.invalidateAll();
|
||||
Meteor.flush();
|
||||
v.changed();
|
||||
Deps.flush();
|
||||
test.equal(x, 5);
|
||||
listeners.invalidateAll();
|
||||
v.changed();
|
||||
// Increment to 6 and stop.
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(x, 6);
|
||||
listeners.invalidateAll();
|
||||
Meteor.flush();
|
||||
v.changed();
|
||||
Deps.flush();
|
||||
// Still 6!
|
||||
test.equal(x, 6);
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ Package.on_use(function (api, where) {
|
||||
where = where || ['client', 'server'];
|
||||
|
||||
api.use('underscore', where);
|
||||
api.add_files(['deps.js', 'deps-utils.js'], where);
|
||||
api.add_files(['deps.js'], where);
|
||||
});
|
||||
|
||||
Package.on_test(function (api) {
|
||||
|
||||
@@ -145,7 +145,8 @@ Meteor._LivedataConnection = function (url, options) {
|
||||
// - id
|
||||
// - name
|
||||
// - params
|
||||
// - context (the Context in which Meteor.subscribe was called, if any)
|
||||
// - computation (the Deps.Computation in which Meteor.subscribe was
|
||||
// called, if any)
|
||||
// - ready (has the 'ready' message been received?)
|
||||
// - readyCallback (an optional callback to call when ready)
|
||||
// - errorCallback (an optional callback to call if the sub terminates with
|
||||
@@ -158,7 +159,7 @@ Meteor._LivedataConnection = function (url, options) {
|
||||
|
||||
// Reactive userId.
|
||||
self._userId = null;
|
||||
self._userIdListeners = Meteor.deps && new Meteor.deps._ContextSet;
|
||||
self._userIdVar = (typeof Deps !== "undefined") && new Deps.Variable;
|
||||
|
||||
// Block auto-reload while we're waiting for method responses.
|
||||
if (!options.reloadWithOutstanding) {
|
||||
@@ -426,10 +427,10 @@ _.extend(Meteor._LivedataConnection.prototype, {
|
||||
}
|
||||
|
||||
// Is there an existing sub with the same name and param, run in an
|
||||
// invalidated Context? This can only happen if the context just got
|
||||
// invalidated and we haven't fully finished a round of Meteor.flush()
|
||||
// invalidated Computation? This can only happen if the computation just got
|
||||
// invalidated and we haven't fully finished a round of Deps.flush()
|
||||
// yet. For example, this will happen with the pattern of:
|
||||
// Meteor.autorun(function () {
|
||||
// Deps.autorun(function () {
|
||||
// Meteor.subscribe("foo", Session.get("foo"));
|
||||
// Meteor.subscribe("bar", Session.get("bar"));
|
||||
// });
|
||||
@@ -440,16 +441,16 @@ _.extend(Meteor._LivedataConnection.prototype, {
|
||||
// being invalidated, we will require N matching subscribe calls to keep
|
||||
// them all active.
|
||||
var existing = _.find(self._subscriptions, function (sub) {
|
||||
return sub.context && sub.context.invalidated && sub.name === name &&
|
||||
EJSON.equals(sub.params, params);
|
||||
return sub.computation && sub.computation.invalidated &&
|
||||
sub.name === name && EJSON.equals(sub.params, params);
|
||||
});
|
||||
|
||||
var currentContext = Meteor.deps && Meteor.deps.Context.current;
|
||||
var currentComputation = Deps.currentComputation;
|
||||
var id;
|
||||
if (existing) {
|
||||
id = existing.id;
|
||||
// Substitute our current context (if any) for the one on the sub.
|
||||
existing.context = currentContext;
|
||||
// Substitute our current computation (if any) for the one on the sub.
|
||||
existing.computation = currentComputation;
|
||||
|
||||
if (callbacks.onReady) {
|
||||
// If the sub is not already ready, replace any ready callback with the
|
||||
@@ -472,9 +473,9 @@ _.extend(Meteor._LivedataConnection.prototype, {
|
||||
id: id,
|
||||
name: name,
|
||||
params: params,
|
||||
context: currentContext,
|
||||
computation: currentComputation,
|
||||
ready: false,
|
||||
readyListeners: Meteor.deps && new Meteor.deps._ContextSet,
|
||||
readyVar: (typeof Deps !== "undefined") && new Deps.Variable,
|
||||
readyCallback: callbacks.onReady,
|
||||
errorCallback: callbacks.onError
|
||||
};
|
||||
@@ -494,37 +495,34 @@ _.extend(Meteor._LivedataConnection.prototype, {
|
||||
if (!_.has(self._subscriptions, id))
|
||||
return false;
|
||||
var record = self._subscriptions[id];
|
||||
record.readyListeners && record.readyListeners.addCurrentContext();
|
||||
record.readyVar && Deps.depend(record.readyVar);
|
||||
return record.ready;
|
||||
}
|
||||
};
|
||||
|
||||
if (currentContext) {
|
||||
// We're in a reactive context, so we'd like to unsubscribe when the
|
||||
// context is invalidated... but not if some *OTHER* onInvalidate callback
|
||||
// on currentContext re-subscribes to the same subscription (eg, as part
|
||||
// of an autorun). Meteor.flush guarantees that it won't interleave calls
|
||||
// to currentContext's callbacks and unsubscribeContext's callbacks, so
|
||||
// this ensures that by the time unsubscribeContext's onInvalidate
|
||||
// callback is called, we've already re-run the autorun function (if this
|
||||
// was an autorun context).
|
||||
var unsubscribeContext = new Meteor.deps.Context;
|
||||
unsubscribeContext.onInvalidate(function () {
|
||||
// Did we already unsubscribe from this? Do nothing.
|
||||
if (!_.has(self._subscriptions, id))
|
||||
return;
|
||||
// Did we substitute a new context in for this constitute in the
|
||||
// "Substitute" block above? (eg, are we in an autorun and the re-run of
|
||||
// the function subscribed to this again?)
|
||||
if (self._subscriptions[id].context !== currentContext)
|
||||
return;
|
||||
// Nope, the only reason we are currently subscribed to this
|
||||
// subscription is that *THIS* subscribe call wanted it to be so, and
|
||||
// its context is invalidated, so it's time to unsubscribe.
|
||||
handle.stop();
|
||||
});
|
||||
currentContext.onInvalidate(function () {
|
||||
unsubscribeContext.invalidate();
|
||||
if (currentComputation) {
|
||||
// We're in a reactive computation, so we'd like to unsubscribe when the
|
||||
// computation is invalidated... but not if some *OTHER* onInvalidate
|
||||
// callback on currentComputation re-subscribes to the same subscription
|
||||
// (eg, as part of a Deps.autorun). Use Deps.afterFlush to schedule
|
||||
// this check to happen later in the flush cycle, after all of
|
||||
// currentComputation's callbacks have been called, and therefore after
|
||||
// the current Deps.autorun (if any) has been re-run.
|
||||
currentComputation.onInvalidate(function () {
|
||||
Deps.afterFlush(function () {
|
||||
// Did we already unsubscribe from this? Do nothing.
|
||||
if (!_.has(self._subscriptions, id))
|
||||
return;
|
||||
// Did we substitute a new computation in for this constitute in the
|
||||
// "Substitute" block above? (eg, are we in an autorun and the re-run of
|
||||
// the function subscribed to this again?)
|
||||
if (self._subscriptions[id].computation !== currentComputation)
|
||||
return;
|
||||
// Nope, the only reason we are currently subscribed to this
|
||||
// subscription is that *THIS* subscribe call wanted it to be so, and
|
||||
// its computation is invalidated, so it's time to unsubscribe.
|
||||
handle.stop();
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
@@ -785,19 +783,19 @@ _.extend(Meteor._LivedataConnection.prototype, {
|
||||
///
|
||||
userId: function () {
|
||||
var self = this;
|
||||
if (self._userIdListeners)
|
||||
self._userIdListeners.addCurrentContext();
|
||||
if (self._userIdVar)
|
||||
Deps.depend(self._userIdVar);
|
||||
return self._userId;
|
||||
},
|
||||
|
||||
setUserId: function (userId) {
|
||||
var self = this;
|
||||
// Avoid invalidating listeners if setUserId is called with current value.
|
||||
// Avoid invalidating dependents if setUserId is called with current value.
|
||||
if (self._userId === userId)
|
||||
return;
|
||||
self._userId = userId;
|
||||
if (self._userIdListeners)
|
||||
self._userIdListeners.invalidateAll();
|
||||
if (self._userIdVar)
|
||||
self._userIdVar.changed();
|
||||
},
|
||||
|
||||
// Returns true if we are in a state after reconnect of waiting for subs to be
|
||||
@@ -1116,7 +1114,7 @@ _.extend(Meteor._LivedataConnection.prototype, {
|
||||
return;
|
||||
subRecord.readyCallback && subRecord.readyCallback();
|
||||
subRecord.ready = true;
|
||||
subRecord.readyListeners && subRecord.readyListeners.invalidateAll();
|
||||
subRecord.readyVar && subRecord.readyVar.changed();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
@@ -115,7 +115,7 @@ Tinytest.add("livedata stub - subscribe", function (test) {
|
||||
test.equal(message, {msg: 'sub', name: 'my_data', params: []});
|
||||
|
||||
var reactivelyReady = false;
|
||||
var autorunHandle = Meteor.autorun(function () {
|
||||
var autorunHandle = Deps.autorun(function () {
|
||||
reactivelyReady = sub.ready();
|
||||
});
|
||||
test.isFalse(reactivelyReady);
|
||||
@@ -123,7 +123,7 @@ Tinytest.add("livedata stub - subscribe", function (test) {
|
||||
// get the sub satisfied. callback fires.
|
||||
stream.receive({msg: 'ready', 'subs': [id]});
|
||||
test.isTrue(callback_fired);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.isTrue(reactivelyReady);
|
||||
autorunHandle.stop();
|
||||
|
||||
@@ -165,7 +165,7 @@ Tinytest.add("livedata stub - reactive subscribe", function (test) {
|
||||
|
||||
// Subscribe to some subs.
|
||||
var stopperHandle;
|
||||
var autorunHandle = Meteor.autorun(function () {
|
||||
var autorunHandle = Deps.autorun(function () {
|
||||
conn.subscribe("foo", rFoo.get(), onReady(rFoo.get()));
|
||||
conn.subscribe("bar", rBar.get(), onReady(rBar.get()));
|
||||
conn.subscribe("completer", onReady("completer"));
|
||||
@@ -216,7 +216,7 @@ Tinytest.add("livedata stub - reactive subscribe", function (test) {
|
||||
// subscription should *NOT* call its new onReady callback, because we only
|
||||
// call at most one onReady for a given reactively-saved subscription.
|
||||
rFoo.set("foo2");
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.length(stream.sent, 3);
|
||||
|
||||
message = JSON.parse(stream.sent.shift());
|
||||
@@ -246,7 +246,7 @@ Tinytest.add("livedata stub - reactive subscribe", function (test) {
|
||||
// Shut down the autorun. This should unsub us from all current subs at flush
|
||||
// time.
|
||||
autorunHandle.stop();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
test.length(stream.sent, 4);
|
||||
// The order of unsubs here is not important.
|
||||
|
||||
@@ -44,7 +44,7 @@ _.extend(Meteor, {
|
||||
// won't be necessary once we clobber the global setTimeout
|
||||
//
|
||||
// XXX consider making this guarantee ordering of defer'd callbacks, like
|
||||
// Meteor._atFlush or Node's nextTick (in practice). Then tests can do:
|
||||
// Deps.afterFlush or Node's nextTick (in practice). Then tests can do:
|
||||
// callSomethingThatDefersSomeWork();
|
||||
// Meteor.defer(expect(somethingThatValidatesThatTheWorkHappened));
|
||||
defer: function (f) {
|
||||
|
||||
@@ -140,11 +140,11 @@ LocalCollection.Cursor.prototype.forEach = function (callback) {
|
||||
self.db_objects = self._getRawObjects(true);
|
||||
|
||||
if (self.reactive)
|
||||
self._markAsReactive({
|
||||
addedBefore: true,
|
||||
removed: true,
|
||||
changed: true,
|
||||
movedBefore: true});
|
||||
self._depend({
|
||||
addedBefore: true,
|
||||
removed: true,
|
||||
changed: true,
|
||||
movedBefore: true});
|
||||
|
||||
while (self.cursor_pos < self.db_objects.length)
|
||||
callback(EJSON.clone(self.db_objects[self.cursor_pos++]));
|
||||
@@ -172,7 +172,7 @@ LocalCollection.Cursor.prototype.count = function () {
|
||||
var self = this;
|
||||
|
||||
if (self.reactive)
|
||||
self._markAsReactive({added: true, removed: true});
|
||||
self._depend({added: true, removed: true});
|
||||
|
||||
if (self.db_objects === null)
|
||||
self.db_objects = self._getRawObjects(true);
|
||||
@@ -339,27 +339,28 @@ LocalCollection.Cursor.prototype._getRawObjects = function (ordered) {
|
||||
|
||||
// XXX Maybe we need a version of observe that just calls a callback if
|
||||
// anything changed.
|
||||
LocalCollection.Cursor.prototype._markAsReactive = function (options) {
|
||||
LocalCollection.Cursor.prototype._depend = function (changers) {
|
||||
var self = this;
|
||||
|
||||
var context = Meteor.deps.Context.current;
|
||||
if (Deps.active) {
|
||||
var v = new Deps.Variable;
|
||||
Deps.depend(v);
|
||||
var notifyChange = _.bind(v.change, v);
|
||||
|
||||
if (context) {
|
||||
var invalidate = _.bind(context.invalidate, context);
|
||||
var handle;
|
||||
var newOptions = {_suppress_initial: true};
|
||||
var options = {_suppress_initial: true};
|
||||
_.each(['added', 'changed', 'removed', 'addedBefore', 'movedBefore'],
|
||||
function (fnName) {
|
||||
if (options[fnName])
|
||||
newOptions[fnName] = invalidate;
|
||||
});
|
||||
handle = self.observeChanges(newOptions);
|
||||
if (changers[fnName])
|
||||
options[fnName] = notifyChange;
|
||||
});
|
||||
|
||||
var handle = self.observeChanges(options);
|
||||
|
||||
// XXX in many cases, the query will be immediately
|
||||
// recreated. so we might want to let it linger for a little
|
||||
// while and repurpose it if it comes back. this will save us
|
||||
// work because we won't have to redo the initial find.
|
||||
context.onInvalidate(handle.stop);
|
||||
Deps.currentComputation.onInvalidate(handle.stop);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Old under_score version of camelCase public API names.
|
||||
Meteor.is_client = Meteor.isClient;
|
||||
Meteor.is_server = Meteor.isServer;
|
||||
Meteor.deps.Context.prototype.on_invalidate =
|
||||
Meteor.deps.Context.prototype.onInvalidate;
|
||||
//Meteor.deps.Context.prototype.on_invalidate =
|
||||
// Meteor.deps.Context.prototype.onInvalidate;
|
||||
// See also the "this.is_simulation" assignment in livedata/livedata_common.js
|
||||
// and the retry_count and retry_time fields of self.current_status in
|
||||
// stream/stream_client.js.
|
||||
@@ -10,7 +10,7 @@ Meteor.deps.Context.prototype.on_invalidate =
|
||||
|
||||
// We used to require a special "autosubscribe" call to reactively subscribe to
|
||||
// things. Now, it works with autorun.
|
||||
Meteor.autosubscribe = Meteor.autorun;
|
||||
Meteor.autosubscribe = Deps.autorun;
|
||||
|
||||
// Instead of the "random" package with Random.id(), we used to have this
|
||||
// Meteor.uuid() implementing the RFC 4122 v4 UUID.
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
|
||||
Session = _.extend({}, {
|
||||
keys: {}, // key -> value
|
||||
keyDeps: {}, // key -> _ContextSet
|
||||
keyValueDeps: {}, // key -> value -> _ContextSet
|
||||
keyVars: {}, // key -> Variable
|
||||
keyValueVars: {}, // key -> value -> Variable
|
||||
|
||||
set: function (key, value) {
|
||||
var self = this;
|
||||
@@ -29,14 +29,14 @@
|
||||
return;
|
||||
self.keys[key] = value;
|
||||
|
||||
var invalidateAll = function (cset) {
|
||||
cset && cset.invalidateAll();
|
||||
var changed = function (v) {
|
||||
v && v.changed();
|
||||
};
|
||||
|
||||
invalidateAll(self.keyDeps[key]);
|
||||
if (self.keyValueDeps[key]) {
|
||||
invalidateAll(self.keyValueDeps[key][oldSerializedValue]);
|
||||
invalidateAll(self.keyValueDeps[key][value]);
|
||||
changed(self.keyVars[key]);
|
||||
if (self.keyValueVars[key]) {
|
||||
changed(self.keyValueVars[key][oldSerializedValue]);
|
||||
changed(self.keyValueVars[key][value]);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -53,19 +53,18 @@
|
||||
get: function (key) {
|
||||
var self = this;
|
||||
self._ensureKey(key);
|
||||
self.keyDeps[key].addCurrentContext();
|
||||
Deps.depend(self.keyVars[key]);
|
||||
return parse(self.keys[key]);
|
||||
},
|
||||
|
||||
equals: function (key, value) {
|
||||
var self = this;
|
||||
var context = Meteor.deps.Context.current;
|
||||
|
||||
// We don't allow objects (or arrays that might include objects) for
|
||||
// .equals, because JSON.stringify doesn't canonicalize object key
|
||||
// order. (We can make equals have the right return value by parsing the
|
||||
// current value and using EJSON.equals, but we won't have a canonical
|
||||
// element of keyValueDeps[key] to store the context.) You can still use
|
||||
// element of keyValueVars[key] to store the dependency.) You can still use
|
||||
// "EJSON.equals(Session.get(key), value)".
|
||||
//
|
||||
// XXX we could allow arrays as long as we recursively check that there
|
||||
@@ -80,19 +79,19 @@
|
||||
throw new Error("Session.equals: value must be scalar");
|
||||
var serializedValue = stringify(value);
|
||||
|
||||
if (context) {
|
||||
if (Deps.active) {
|
||||
self._ensureKey(key);
|
||||
|
||||
if (! _.has(self.keyValueDeps[key], serializedValue))
|
||||
self.keyValueDeps[key][serializedValue] = new Meteor.deps._ContextSet;
|
||||
if (! _.has(self.keyValueVars[key], serializedValue))
|
||||
self.keyValueVars[key][serializedValue] = new Deps.Variable;
|
||||
|
||||
var isNew = self.keyValueDeps[key][serializedValue].add(context);
|
||||
var isNew = Deps.depend(self.keyValueVars[key][serializedValue]);
|
||||
if (isNew) {
|
||||
context.onInvalidate(function () {
|
||||
Deps.currentComputation.onInvalidate(function () {
|
||||
// clean up [key][serializedValue] if it's now empty, so we don't
|
||||
// use O(n) memory for n = values seen ever
|
||||
if (self.keyValueDeps[key][serializedValue].isEmpty())
|
||||
delete self.keyValueDeps[key][serializedValue];
|
||||
if (! self.keyValueVars[key][serializedValue].hasDependents())
|
||||
delete self.keyValueVars[key][serializedValue];
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -104,9 +103,9 @@
|
||||
|
||||
_ensureKey: function (key) {
|
||||
var self = this;
|
||||
if (!(key in self.keyDeps)) {
|
||||
self.keyDeps[key] = new Meteor.deps._ContextSet;
|
||||
self.keyValueDeps[key] = {};
|
||||
if (!(key in self.keyVars)) {
|
||||
self.keyVars[key] = new Deps.Variable;
|
||||
self.keyValueVars[key] = {};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
|
||||
Tinytest.add('session - context invalidation for get', function (test) {
|
||||
var xGetExecutions = 0;
|
||||
Meteor.autorun(function () {
|
||||
Deps.autorun(function () {
|
||||
++xGetExecutions;
|
||||
Session.get('x');
|
||||
});
|
||||
@@ -113,44 +113,44 @@
|
||||
Session.set('x', 1);
|
||||
// Invalidation shouldn't happen until flush time.
|
||||
test.equal(xGetExecutions, 1);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(xGetExecutions, 2);
|
||||
// Setting to the same value doesn't re-run.
|
||||
Session.set('x', 1);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(xGetExecutions, 2);
|
||||
Session.set('x', '1');
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(xGetExecutions, 3);
|
||||
});
|
||||
|
||||
Tinytest.add('session - context invalidation for equals', function (test) {
|
||||
var xEqualsExecutions = 0;
|
||||
Meteor.autorun(function () {
|
||||
Deps.autorun(function () {
|
||||
++xEqualsExecutions;
|
||||
Session.equals('x', 5);
|
||||
});
|
||||
test.equal(xEqualsExecutions, 1);
|
||||
Session.set('x', 1);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
// Changing undefined -> 1 shouldn't affect equals(5).
|
||||
test.equal(xEqualsExecutions, 1);
|
||||
Session.set('x', 5);
|
||||
// Invalidation shouldn't happen until flush time.
|
||||
test.equal(xEqualsExecutions, 1);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(xEqualsExecutions, 2);
|
||||
Session.set('x', 5);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
// Setting to the same value doesn't re-run.
|
||||
test.equal(xEqualsExecutions, 2);
|
||||
Session.set('x', '5');
|
||||
test.equal(xEqualsExecutions, 2);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(xEqualsExecutions, 3);
|
||||
Session.set('x', 5);
|
||||
test.equal(xEqualsExecutions, 3);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(xEqualsExecutions, 4);
|
||||
});
|
||||
|
||||
@@ -159,27 +159,27 @@
|
||||
function (test) {
|
||||
// Make sure the special casing for equals undefined works.
|
||||
var yEqualsExecutions = 0;
|
||||
Meteor.autorun(function () {
|
||||
Deps.autorun(function () {
|
||||
++yEqualsExecutions;
|
||||
Session.equals('y', undefined);
|
||||
});
|
||||
test.equal(yEqualsExecutions, 1);
|
||||
Session.set('y', undefined);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(yEqualsExecutions, 1);
|
||||
Session.set('y', 5);
|
||||
test.equal(yEqualsExecutions, 1);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(yEqualsExecutions, 2);
|
||||
Session.set('y', 3);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(yEqualsExecutions, 2);
|
||||
Session.set('y', 'undefined');
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(yEqualsExecutions, 2);
|
||||
Session.set('y', undefined);
|
||||
test.equal(yEqualsExecutions, 2);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(yEqualsExecutions, 3);
|
||||
});
|
||||
}());
|
||||
|
||||
@@ -352,7 +352,7 @@ var scheduleOnscreenSetup = function (frag, landmarkRanges) {
|
||||
finalized = true;
|
||||
};
|
||||
|
||||
Meteor._atFlush(function () {
|
||||
Deps.afterFlush(function () {
|
||||
if (finalized)
|
||||
return;
|
||||
|
||||
@@ -807,7 +807,7 @@ Spark.attachEvents = withRenderer(function (eventMap, html, _renderer) {
|
||||
var landmark = (landmarkRange && landmarkRange.landmark);
|
||||
|
||||
// Note that the handler can do arbitrary things, like call
|
||||
// Meteor.flush() or otherwise remove and finalize parts of
|
||||
// Deps.flush() or otherwise remove and finalize parts of
|
||||
// the DOM. We can't assume `range` is valid past this point,
|
||||
// and we'll check the `finalized` flag at the top of the loop.
|
||||
var returnValue = callback.call(eventData, event, landmark);
|
||||
@@ -837,20 +837,20 @@ Spark.isolate = function (htmlFunc) {
|
||||
var range;
|
||||
var firstRun = true;
|
||||
var retHtml;
|
||||
Meteor.autorun(function (handle) {
|
||||
Deps.autorun(function (handle) {
|
||||
if (firstRun) {
|
||||
retHtml = renderer.annotate(
|
||||
htmlFunc(), Spark._ANNOTATION_ISOLATE,
|
||||
function (r) {
|
||||
if (! r) {
|
||||
// annotation not used; kill our context
|
||||
// annotation not used; kill this autorun
|
||||
handle.stop();
|
||||
} else {
|
||||
range = r;
|
||||
range.finalize = function () {
|
||||
// Spark.finalize() was called on our range (presumably
|
||||
// because it was removed from the document.) Kill
|
||||
// this context and stop rerunning.
|
||||
// this autorun.
|
||||
handle.stop();
|
||||
};
|
||||
}
|
||||
@@ -976,7 +976,7 @@ Spark.list = function (cursor, itemFunc, elseFunc) {
|
||||
};
|
||||
|
||||
var later = function (f) {
|
||||
Meteor._atFlush(function () {
|
||||
Deps.afterFlush(function () {
|
||||
if (! stopped)
|
||||
withEventGuard(f);
|
||||
});
|
||||
@@ -1155,15 +1155,9 @@ Spark.createLandmark = function (options, htmlFunc) {
|
||||
landmark = new Spark.Landmark;
|
||||
if (options.created) {
|
||||
// Run callback outside the current Spark.isolate's deps context.
|
||||
// XXX Can't call run() on null, so this is a hack. Running inside
|
||||
// a fresh context wouldn't be equivalent.
|
||||
var oldCx = Meteor.deps.Context.current;
|
||||
Meteor.deps.Context.current = null;
|
||||
try {
|
||||
Deps.nonreactive(function () {
|
||||
options.created.call(landmark);
|
||||
} finally {
|
||||
Meteor.deps.Context.current = oldCx;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
notes.landmark = landmark;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -41,7 +41,7 @@
|
||||
" if (typeof Meteor !== 'undefined' " +
|
||||
" && typeof(Meteor.status) !== 'undefined' " +
|
||||
" && Meteor.status().connected) {" +
|
||||
" Meteor.flush();" +
|
||||
" Deps.flush();" +
|
||||
" return Meteor._LivedataConnection._allSubscriptionsReady();" +
|
||||
" }" +
|
||||
" return false;" +
|
||||
|
||||
@@ -47,10 +47,10 @@ Meteor._Stream = function (url) {
|
||||
retry_count: 0
|
||||
};
|
||||
|
||||
self.status_listeners = (Meteor.deps && new Meteor.deps._ContextSet);
|
||||
self.status_listeners = window.Deps && new Deps.Variable;
|
||||
self.status_changed = function () {
|
||||
if (self.status_listeners)
|
||||
self.status_listeners.invalidateAll();
|
||||
self.status_listeners.changed();
|
||||
};
|
||||
|
||||
//// Retry logic
|
||||
@@ -139,7 +139,7 @@ _.extend(Meteor._Stream.prototype, {
|
||||
status: function () {
|
||||
var self = this;
|
||||
if (self.status_listeners)
|
||||
self.status_listeners.addCurrentContext();
|
||||
Deps.depend(self.status_listeners);
|
||||
return self.current_status;
|
||||
},
|
||||
|
||||
|
||||
@@ -18,10 +18,10 @@ Tinytest.add("templating - assembly", function (test) {
|
||||
document.body.appendChild(onscreen);
|
||||
test.equal(canonicalizeHtml(onscreen.innerHTML), "xyhi");
|
||||
Session.set("stuff", false);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(canonicalizeHtml(onscreen.innerHTML), "xhi");
|
||||
document.body.removeChild(onscreen);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
});
|
||||
|
||||
// Test that if a template throws an error, then pending_partials is
|
||||
@@ -71,7 +71,7 @@ Tinytest.add("templating - table assembly", function(test) {
|
||||
|
||||
|
||||
document.body.removeChild(onscreen);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
});
|
||||
|
||||
Tinytest.add("templating - event handler this", function(test) {
|
||||
@@ -111,7 +111,7 @@ Tinytest.add("templating - event handler this", function(test) {
|
||||
event_buf.length = 0;
|
||||
|
||||
tmpl.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
});
|
||||
|
||||
Tinytest.add("templating - safestring", function(test) {
|
||||
@@ -345,7 +345,7 @@ Tinytest.add("templating - rendered template", function(test) {
|
||||
test.isTrue(hr1);
|
||||
|
||||
R.set('bar');
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
var br2 = div.node().getElementsByTagName('br')[0];
|
||||
var hr2 = div.node().getElementsByTagName('hr')[0];
|
||||
test.isTrue(br2);
|
||||
@@ -354,7 +354,7 @@ Tinytest.add("templating - rendered template", function(test) {
|
||||
test.isFalse(hr1 === hr2);
|
||||
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
/////
|
||||
|
||||
@@ -379,7 +379,7 @@ Tinytest.add("templating - rendered template", function(test) {
|
||||
test.isTrue(hr1);
|
||||
|
||||
R.set('bar');
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
var br2 = div.node().getElementsByTagName('br')[0];
|
||||
var hr2 = div.node().getElementsByTagName('hr')[0];
|
||||
test.isTrue(br2);
|
||||
@@ -388,7 +388,7 @@ Tinytest.add("templating - rendered template", function(test) {
|
||||
test.isFalse(hr1 === hr2);
|
||||
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
/////
|
||||
|
||||
@@ -409,7 +409,7 @@ Tinytest.add("templating - rendered template", function(test) {
|
||||
test.isTrue(hr1);
|
||||
|
||||
stuff.update({foo:'bar'}, {$set: {foo: 'baz'}});
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
var br2 = div.node().getElementsByTagName('br')[0];
|
||||
var hr2 = div.node().getElementsByTagName('hr')[0];
|
||||
test.isTrue(br2);
|
||||
@@ -418,7 +418,7 @@ Tinytest.add("templating - rendered template", function(test) {
|
||||
test.isFalse(hr1 === hr2);
|
||||
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
/////
|
||||
|
||||
@@ -436,7 +436,7 @@ Tinytest.add("templating - rendered template", function(test) {
|
||||
test.isTrue(hr1);
|
||||
|
||||
stuff.update({foo:'bar'}, {$set: {foo: 'baz'}});
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
var br2 = div.node().getElementsByTagName('br')[0];
|
||||
var hr2 = div.node().getElementsByTagName('hr')[0];
|
||||
test.isTrue(br2);
|
||||
@@ -445,7 +445,7 @@ Tinytest.add("templating - rendered template", function(test) {
|
||||
test.isFalse(hr1 === hr2);
|
||||
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
});
|
||||
|
||||
@@ -477,12 +477,12 @@ Tinytest.add("templating - branch labels", function(test) {
|
||||
};
|
||||
|
||||
var div = OnscreenDiv(Meteor.render(Template.test_branches_a));
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(DomUtils.find(div.node(), 'span').innerHTML, 'foo');
|
||||
test.equal(elems.length, 3);
|
||||
|
||||
R.set('bar');
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
var elems2 = DomUtils.findAll(div.node(), 'hr');
|
||||
elems2.sort(function(a, b) { return a.myIndex - b.myIndex; });
|
||||
test.equal(elems[0], elems2[0]);
|
||||
@@ -491,7 +491,7 @@ Tinytest.add("templating - branch labels", function(test) {
|
||||
test.equal(DomUtils.find(div.node(), 'span').innerHTML, 'bar');
|
||||
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
});
|
||||
|
||||
Tinytest.add("templating - matching in list", function (test) {
|
||||
@@ -519,7 +519,7 @@ Tinytest.add("templating - matching in list", function (test) {
|
||||
|
||||
var R = ReactiveVar('foo');
|
||||
var div = OnscreenDiv(Spark.render(Template.test_listmatching_a0));
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
test.equal(DomUtils.find(div.node(), 'span').innerHTML, 'foo');
|
||||
test.equal(div.html().match(/<p>(.*?)<\/p>/)[1].match(/\S+/g), ['a','b','c']);
|
||||
@@ -527,13 +527,13 @@ Tinytest.add("templating - matching in list", function (test) {
|
||||
|
||||
buf.length = 0;
|
||||
R.set('bar');
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(DomUtils.find(div.node(), 'span').innerHTML, 'bar');
|
||||
test.equal(div.html().match(/<p>(.*?)<\/p>/)[1].match(/\S+/g), ['a','b','c']);
|
||||
test.equal(buf.join(''), '*a*b*c');
|
||||
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
});
|
||||
|
||||
@@ -560,19 +560,19 @@ Tinytest.add("templating - isolate helper", function (test) {
|
||||
test.equal(getTallies().join(','), str);
|
||||
};
|
||||
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
expect("1,1,1,1");
|
||||
bump(1); Meteor.flush(); expect("2,2,2,2");
|
||||
bump(2); Meteor.flush(); expect("2,3,3,3");
|
||||
bump(3); Meteor.flush(); expect("2,3,4,4");
|
||||
bump(4); Meteor.flush(); expect("2,3,4,5");
|
||||
Meteor.flush(); expect("2,3,4,5");
|
||||
bump(3); Meteor.flush(); expect("2,3,5,6");
|
||||
bump(2); Meteor.flush(); expect("2,4,6,7");
|
||||
bump(1); Meteor.flush(); expect("3,5,7,8");
|
||||
bump(1); Deps.flush(); expect("2,2,2,2");
|
||||
bump(2); Deps.flush(); expect("2,3,3,3");
|
||||
bump(3); Deps.flush(); expect("2,3,4,4");
|
||||
bump(4); Deps.flush(); expect("2,3,4,5");
|
||||
Deps.flush(); expect("2,3,4,5");
|
||||
bump(3); Deps.flush(); expect("2,3,5,6");
|
||||
bump(2); Deps.flush(); expect("2,4,6,7");
|
||||
bump(1); Deps.flush(); expect("3,5,7,8");
|
||||
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
});
|
||||
|
||||
@@ -618,13 +618,13 @@ Tinytest.add("templating - template arg", function (test) {
|
||||
}));
|
||||
|
||||
test.equal(div.text(), "Foo Bar Baz");
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(div.text(), "Greetings 1-bold Line");
|
||||
clickElement(DomUtils.find(div.node(), 'i'));
|
||||
test.equal(div.text(), "Hello 3-element World (the secret is strawberry pie)");
|
||||
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
});
|
||||
|
||||
Tinytest.add("templating - preserve", function (test) {
|
||||
@@ -641,7 +641,7 @@ Tinytest.add("templating - preserve", function (test) {
|
||||
tmpl['var'] = function () { return R.get(); };
|
||||
|
||||
var div = OnscreenDiv(Meteor.render(tmpl));
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(DomUtils.find(div.node(), 'u').firstChild.nodeValue.match(
|
||||
/\S+/)[0], 'foo');
|
||||
var spans1 = {};
|
||||
@@ -650,7 +650,7 @@ Tinytest.add("templating - preserve", function (test) {
|
||||
});
|
||||
|
||||
R.set('bar');
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(DomUtils.find(div.node(), 'u').firstChild.nodeValue.match(
|
||||
/\S+/)[0], 'bar');
|
||||
var spans2 = {};
|
||||
@@ -668,7 +668,7 @@ Tinytest.add("templating - preserve", function (test) {
|
||||
test.isFalse(spans1.z === spans2.z);
|
||||
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
});
|
||||
|
||||
Tinytest.add("templating - helpers", function (test) {
|
||||
@@ -682,7 +682,7 @@ Tinytest.add("templating - helpers", function (test) {
|
||||
var div = OnscreenDiv(Meteor.render(tmpl));
|
||||
test.equal(div.text().match(/\S+/)[0], 'abc');
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
tmpl = Template.test_template_helpers_b;
|
||||
|
||||
@@ -707,14 +707,14 @@ Tinytest.add("templating - helpers", function (test) {
|
||||
test.expect_fail();
|
||||
test.equal(txt, 'ABC4D');
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
// test that helpers don't "leak"
|
||||
tmpl = Template.test_template_helpers_c;
|
||||
div = OnscreenDiv(Meteor.render(tmpl));
|
||||
test.equal(div.text(), 'x');
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
});
|
||||
|
||||
Tinytest.add("templating - events", function (test) {
|
||||
@@ -731,7 +731,7 @@ Tinytest.add("templating - events", function (test) {
|
||||
clickElement(DomUtils.find(div.node(), 'b'));
|
||||
test.equal(buf, ['b']);
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
///
|
||||
|
||||
@@ -750,7 +750,7 @@ Tinytest.add("templating - events", function (test) {
|
||||
clickElement(DomUtils.find(div.node(), 'i'));
|
||||
test.equal(buf, ['u', 'i']);
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
});
|
||||
|
||||
@@ -773,34 +773,34 @@ Tinytest.add("templating - #each rendered callback", function (test) {
|
||||
DomUtils.rangeToHtml(this.firstNode, this.lastNode)).replace(/\s/g, ''));
|
||||
};
|
||||
var div = OnscreenDiv(Meteor.render(tmpl));
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(buf, ['<div>a</div><div>b</div><div>c</div>']);
|
||||
buf.length = 0;
|
||||
|
||||
// added
|
||||
entries.insert({x:'d'});
|
||||
test.equal(buf, []);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(buf, ['<div>a</div><div>b</div><div>c</div><div>d</div>']);
|
||||
buf.length = 0;
|
||||
|
||||
// removed
|
||||
entries.remove({x:'a'});
|
||||
test.equal(buf, []);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(buf, ['<div>b</div><div>c</div><div>d</div>']);
|
||||
buf.length = 0;
|
||||
|
||||
// moved/changed
|
||||
entries.update({x:'b'}, {$set: {x: 'z'}});
|
||||
test.equal(buf, []);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(buf, ['<div>c</div><div>d</div><div>z</div>',
|
||||
'<div>c</div><div>d</div><div>z</div>']);
|
||||
buf.length = 0;
|
||||
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
// test pure "moved"
|
||||
|
||||
@@ -827,7 +827,7 @@ Tinytest.add("templating - #each rendered callback", function (test) {
|
||||
buf = [];
|
||||
var div = OnscreenDiv(Meteor.render(tmpl));
|
||||
test.equal(buf, []);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(buf, ['<div>a</div><div>b</div><div>c</div>']);
|
||||
buf.length = 0;
|
||||
|
||||
@@ -835,14 +835,14 @@ Tinytest.add("templating - #each rendered callback", function (test) {
|
||||
callbacks.movedBefore('a', null);
|
||||
});
|
||||
test.equal(buf, []);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(div.html().replace(/\s/g, ''),
|
||||
'<div>b</div><div>c</div><div>a</div>');
|
||||
test.equal(buf, ['<div>b</div><div>c</div><div>a</div>']);
|
||||
buf.length = 0;
|
||||
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
});
|
||||
|
||||
Tinytest.add("templating - landmarks in helpers", function (test) {
|
||||
@@ -864,19 +864,19 @@ Tinytest.add("templating - landmarks in helpers", function (test) {
|
||||
|
||||
var div = OnscreenDiv(Meteor.render(tmpl));
|
||||
test.equal(div.text().match(/\S+/)[0], 'xxxxfoo');
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
buf.sort();
|
||||
test.equal(buf.join(''), 'ccccrrrr');
|
||||
buf.length = 0;
|
||||
|
||||
R.set('bar');
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(div.text().match(/\S+/)[0], 'xxxxbar');
|
||||
test.equal(buf.join(''), 'rrrr');
|
||||
buf.length = 0;
|
||||
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(buf.join(''), 'dddd');
|
||||
});
|
||||
|
||||
@@ -899,19 +899,19 @@ Tinytest.add("templating - bare each has no matching", function (test) {
|
||||
};
|
||||
|
||||
var div = OnscreenDiv(Meteor.render(tmpl));
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
buf.sort();
|
||||
test.equal(buf.join(''), 'cccrrr');
|
||||
buf.length = 0;
|
||||
|
||||
R.set('bar');
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
buf.sort();
|
||||
test.equal(buf.join(''), 'cccdddrrr');
|
||||
buf.length = 0;
|
||||
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(buf.join(''), 'ddd');
|
||||
});
|
||||
|
||||
@@ -934,21 +934,21 @@ Tinytest.add("templating - templates are labeled", function (test) {
|
||||
});
|
||||
|
||||
var div = OnscreenDiv(Meteor.render(tmpls[0]));
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(div.html(), "<hr><hr><hr>foo");
|
||||
buf.sort();
|
||||
test.equal(buf.join(''), 'cccrrr');
|
||||
buf.length = 0;
|
||||
|
||||
R.set('bar');
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(div.html(), "<hr><hr><hr>bar");
|
||||
buf.sort();
|
||||
test.equal(buf.join(''), 'rrr');
|
||||
buf.length = 0;
|
||||
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(buf.join(''), 'ddd');
|
||||
});
|
||||
|
||||
@@ -971,10 +971,10 @@ Tinytest.add("templating - unlabeled cursor", function (test) {
|
||||
// This will fail with "can't create second landmark in branch"
|
||||
// unless _id-less objects returned from a cursor are given
|
||||
// unique branch labels in an {{#each}}.
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
});
|
||||
|
||||
Tinytest.add("templating - constant text patching", function (test) {
|
||||
@@ -990,16 +990,16 @@ Tinytest.add("templating - constant text patching", function (test) {
|
||||
};
|
||||
|
||||
var div = OnscreenDiv(Meteor.render(tmpl));
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
R.set("bar");
|
||||
// This flush will fail if we can't patch the constant region,
|
||||
// which starts with a text node, after preserving the preceding
|
||||
// paragraph.
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
});
|
||||
|
||||
|
||||
@@ -1055,16 +1055,16 @@ Tinytest.add("templating - tricky branch labels", function (test) {
|
||||
});
|
||||
|
||||
var div = OnscreenDiv(Meteor.render(Template.test_template_trickylabels_a0));
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
loading.set(false);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
x.length = 0;
|
||||
|
||||
v.set(2);
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
test.equal(x.join(''), 'r'); // no 'c' or 'd'
|
||||
test.equal(div.html().replace(/\s+/g, ''), '<div>foo</div>2<div>bar</div>');
|
||||
|
||||
div.kill();
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
});
|
||||
|
||||
@@ -43,14 +43,14 @@ OnscreenDiv.prototype.node = function() {
|
||||
};
|
||||
|
||||
// remove the DIV from the document and trigger
|
||||
// "fast GC" -- i.e., after the next Meteor.flush()
|
||||
// "fast GC" -- i.e., after the next Deps.flush()
|
||||
// the DIV will be fully cleaned up by LiveUI.
|
||||
OnscreenDiv.prototype.kill = function() {
|
||||
var self = this;
|
||||
if (self.div.parentNode)
|
||||
self.div.parentNode.removeChild(self.div);
|
||||
|
||||
Meteor._atFlush(function () {
|
||||
Deps.afterFlush(function () {
|
||||
Spark.finalize(self.div);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -19,11 +19,11 @@ var ReactiveVar = function(initialValue) {
|
||||
|
||||
this._value = (typeof initialValue === "undefined" ? null :
|
||||
initialValue);
|
||||
this._deps = new Meteor.deps._ContextSet;
|
||||
this._depsVar = new Deps.Variable;
|
||||
};
|
||||
|
||||
ReactiveVar.prototype.get = function() {
|
||||
this._deps.addCurrentContext();
|
||||
Deps.depend(this._depsVar);
|
||||
return this._value;
|
||||
};
|
||||
|
||||
@@ -35,9 +35,10 @@ ReactiveVar.prototype.set = function(newValue) {
|
||||
|
||||
this._value = newValue;
|
||||
|
||||
this._deps.invalidateAll();
|
||||
this._depsVar.changed();
|
||||
};
|
||||
|
||||
ReactiveVar.prototype.numListeners = function() {
|
||||
return _.keys(this._deps._contextsById).length;
|
||||
// accesses private field (tests want to know)
|
||||
return _.keys(this._depsVar._dependentsById).length;
|
||||
};
|
||||
|
||||
@@ -31,7 +31,7 @@ WrappedFrag.prototype.release = function() {
|
||||
// decrement frag's GC protection reference count
|
||||
// Clean up on flush, if hits 0. Wait to decrement
|
||||
// so no one else cleans it up first.
|
||||
Meteor._atFlush(function () {
|
||||
Deps.afterFlush(function () {
|
||||
if (! --frag["_protect"]) {
|
||||
Spark.finalize(frag);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ var running = true;
|
||||
|
||||
var resultTree = [];
|
||||
var failedTests = [];
|
||||
var resultDeps = new Meteor.deps._ContextSet;
|
||||
var countDeps = new Meteor.deps._ContextSet;
|
||||
var resultsVar = new Deps.Variable;
|
||||
var countVar = new Deps.Variable;
|
||||
var totalCount = 0;
|
||||
var passedCount = 0;
|
||||
var failedCount = 0;
|
||||
@@ -13,37 +13,37 @@ Session.setDefault("groupPath", ["tinytest"]);
|
||||
Session.set("rerunScheduled", false);
|
||||
|
||||
Meteor.startup(function () {
|
||||
Meteor.flush();
|
||||
Deps.flush();
|
||||
Meteor._runTestsEverywhere(reportResults, function () {
|
||||
running = false;
|
||||
Meteor.onTestsComplete && Meteor.onTestsComplete();
|
||||
_resultsChanged();
|
||||
Meteor.flush();
|
||||
resultsVar.changed();
|
||||
Deps.flush();
|
||||
}, Session.get("groupPath"));
|
||||
|
||||
});
|
||||
|
||||
Template.progressBar.running = function () {
|
||||
countDeps.addCurrentContext();
|
||||
Deps.depend(countVar);
|
||||
return passedCount + failedCount < totalCount;
|
||||
};
|
||||
|
||||
Template.progressBar.percentPass = function () {
|
||||
countDeps.addCurrentContext();
|
||||
Deps.depend(countVar);
|
||||
if (totalCount === 0)
|
||||
return 0;
|
||||
return 100*passedCount/totalCount;
|
||||
};
|
||||
|
||||
Template.progressBar.percentFail = function () {
|
||||
countDeps.addCurrentContext();
|
||||
Deps.depend(countVar);
|
||||
if (totalCount === 0)
|
||||
return 0;
|
||||
return 100*failedCount/totalCount;
|
||||
};
|
||||
|
||||
Template.progressBar.anyFail = function () {
|
||||
countDeps.addCurrentContext();
|
||||
Deps.depend(countVar);
|
||||
return failedCount > 0;
|
||||
};
|
||||
|
||||
@@ -85,12 +85,12 @@ Template.test_group.events({
|
||||
});
|
||||
|
||||
Template.test_table.running = function() {
|
||||
resultDeps.addCurrentContext();
|
||||
Deps.depend(resultsVar);
|
||||
return running;
|
||||
};
|
||||
|
||||
Template.test_table.passed = function() {
|
||||
resultDeps.addCurrentContext();
|
||||
Deps.depend(resultsVar);
|
||||
|
||||
// walk whole tree to look for failed tests
|
||||
var walk = function (groups) {
|
||||
@@ -119,7 +119,7 @@ Template.test_table.passed = function() {
|
||||
|
||||
|
||||
Template.test_table.total_test_time = function() {
|
||||
resultDeps.addCurrentContext();
|
||||
Deps.depend(resultsVar);
|
||||
|
||||
// walk whole tree to get all tests
|
||||
var walk = function (groups) {
|
||||
@@ -142,11 +142,11 @@ Template.test_table.total_test_time = function() {
|
||||
|
||||
|
||||
Template.test_table.data = function() {
|
||||
resultDeps.addCurrentContext();
|
||||
Deps.depend(resultsVar);
|
||||
return resultTree;
|
||||
};
|
||||
Template.test_table.failedTests = function() {
|
||||
resultDeps.addCurrentContext();
|
||||
Deps.depend(resultsVar);
|
||||
return failedTests;
|
||||
};
|
||||
|
||||
@@ -182,7 +182,7 @@ Template.test.test_class = function() {
|
||||
Template.test.events({
|
||||
'click .testname': function() {
|
||||
this.expanded = ! this.expanded;
|
||||
_resultsChanged();
|
||||
resultsVar.changed();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -275,11 +275,6 @@ Template.event.is_debuggable = function() {
|
||||
return !!this.cookie;
|
||||
};
|
||||
|
||||
|
||||
var _resultsChanged = function() {
|
||||
resultDeps.invalidateAll();
|
||||
};
|
||||
|
||||
var _testTime = function(t) {
|
||||
if (t.events && t.events.length > 0) {
|
||||
var lastEvent = _.last(t.events);
|
||||
@@ -351,7 +346,7 @@ var _findTestForResults = function (results) {
|
||||
test = {name: testName, parent: group, server: server, fullName: fullName};
|
||||
group.tests.push(test);
|
||||
totalCount++;
|
||||
countDeps.invalidateAll();
|
||||
countVar.changed();
|
||||
}
|
||||
|
||||
return test;
|
||||
@@ -380,7 +375,7 @@ var reportResults = function(results) {
|
||||
var status = _testStatus(test);
|
||||
if (status === "failed") {
|
||||
failedCount++;
|
||||
countDeps.invalidateAll();
|
||||
countVar.changed();
|
||||
// Expand a failed test (but only set this if the user hasn't clicked on the
|
||||
// test name yet).
|
||||
if (test.expanded === undefined)
|
||||
@@ -389,7 +384,7 @@ var reportResults = function(results) {
|
||||
failedTests.push(test.fullName);
|
||||
} else if (status === "succeeded") {
|
||||
passedCount++;
|
||||
countDeps.invalidateAll();
|
||||
countVar.changed();
|
||||
}
|
||||
|
||||
_.defer(_throttled_update);
|
||||
@@ -401,16 +396,16 @@ var forgetEvents = function (results) {
|
||||
var status = _testStatus(test);
|
||||
if (status === "failed") {
|
||||
failedCount--;
|
||||
countDeps.invalidateAll();
|
||||
countVar.changed();
|
||||
} else if (status === "succeeded") {
|
||||
passedCount--;
|
||||
countDeps.invalidateAll();
|
||||
countVar.changed();
|
||||
}
|
||||
delete test.events;
|
||||
_resultsChanged();
|
||||
resultsVar.changed();
|
||||
};
|
||||
|
||||
var _throttled_update = _.throttle(function() {
|
||||
_resultsChanged();
|
||||
Meteor.flush();
|
||||
resultsVar.changed();
|
||||
Deps.flush();
|
||||
}, 500);
|
||||
|
||||
Reference in New Issue
Block a user