mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Merge branch 'devel' into auth
Conflicts: packages/livedata/livedata_common.js packages/livedata/livedata_connection.js packages/livedata/livedata_server.js packages/mongo-livedata/collection.js
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
if (Meteor.is_client) {
|
||||
if (Meteor.isClient) {
|
||||
Template.hello.greeting = function () {
|
||||
return "Welcome to ~name~.";
|
||||
};
|
||||
@@ -12,7 +12,7 @@ if (Meteor.is_client) {
|
||||
};
|
||||
}
|
||||
|
||||
if (Meteor.is_server) {
|
||||
if (Meteor.isServer) {
|
||||
Meteor.startup(function () {
|
||||
// code to run on server at startup
|
||||
});
|
||||
|
||||
@@ -10,8 +10,8 @@ available just on the client, just on the server, or *Anywhere*.
|
||||
|
||||
<h2 id="core"><span>Meteor Core</span></h2>
|
||||
|
||||
{{> api_box is_client}}
|
||||
{{> api_box is_server}}
|
||||
{{> api_box isClient}}
|
||||
{{> api_box isServer}}
|
||||
{{> api_box startup}}
|
||||
|
||||
On a server, the function will run as soon as the server process is
|
||||
@@ -20,7 +20,7 @@ is ready and any `<body>` templates from your `.html` files have been
|
||||
put on the screen.
|
||||
|
||||
// On server startup, if the database is empty, create some initial data.
|
||||
if (Meteor.is_server) {
|
||||
if (Meteor.isServer) {
|
||||
Meteor.startup(function () {
|
||||
if (Rooms.find().count() === 0) {
|
||||
Rooms.insert({name: "Initial room"});
|
||||
@@ -46,7 +46,7 @@ will publish that cursor's documents.
|
||||
|
||||
// server: publish the rooms collection, minus secret info.
|
||||
Meteor.publish("rooms", function () {
|
||||
return Rooms.find({}, {fields: {secret_info: false}});
|
||||
return Rooms.find({}, {fields: {secretInfo: false}});
|
||||
});
|
||||
|
||||
Otherwise, the publish function can <i>set</i> and <i>unset</i>
|
||||
@@ -68,7 +68,7 @@ Example:
|
||||
var uuid = Meteor.uuid();
|
||||
var count = 0;
|
||||
|
||||
var handle = Messages.find({room_id: roomId}).observe({
|
||||
var handle = Messages.find({roomId: roomId}).observe({
|
||||
added: function (doc, idx) {
|
||||
count++;
|
||||
self.set("counts", uuid, {roomId: roomId, count: count});
|
||||
@@ -197,7 +197,7 @@ remotely by clients. They should return a value or throw an exception.
|
||||
Inside your method invocation, `this` is bound to a method invocation
|
||||
object, which provides the following:
|
||||
|
||||
* `is_simulation`: a boolean value, true if this invocation is a stub.
|
||||
* `isSimulation`: a boolean value, true if this invocation is a stub.
|
||||
* `unblock`: when called, allows the next method from this client to
|
||||
begin running.
|
||||
|
||||
@@ -214,7 +214,7 @@ intended to *simulate* the result of what the server's method will do,
|
||||
but without waiting for the round trip delay. If a stub throws an
|
||||
exception it will be logged to the console.
|
||||
|
||||
{{> api_box method_invocation_is_simulation}}
|
||||
{{> api_box method_invocation_isSimulation}}
|
||||
|
||||
{{> api_box method_invocation_unblock}}
|
||||
|
||||
@@ -309,16 +309,16 @@ the server. The return value is an object with the following fields:
|
||||
new connection), and <code>waiting</code> (failed to connect and
|
||||
waiting to try to reconnect).</dd>
|
||||
|
||||
<dt><span class="name">retry_count</span>
|
||||
<dt><span class="name">retryCount</span>
|
||||
<span class="type">Number</span></dt>
|
||||
<dd>The number of times the client has tried to reconnect since the
|
||||
connection was lost. 0 when connected.</dd>
|
||||
|
||||
<dt><span class="name">retry_time</span>
|
||||
<dt><span class="name">retryTime</span>
|
||||
<span class="type">Number or undefined</span></dt>
|
||||
<dd>The estimated time of the next reconnection attempt. To turn this
|
||||
into an interval until the next reconnection, use
|
||||
<code>retry_time - (new Date()).getTime()</code>. This key will
|
||||
<code>retryTime - (new Date()).getTime()</code>. This key will
|
||||
be set only when <code>status</code> is <code>waiting</code>.
|
||||
</dd>
|
||||
</dl>
|
||||
@@ -396,13 +396,13 @@ compatible with the popular Mongo database API. The same database API
|
||||
works on both the client and the server (see below).
|
||||
|
||||
// return array of my messages
|
||||
var my_messages = Messages.find({user_id:Session.get('my_user_id')}).fetch();
|
||||
var myMessages = Messages.find({userId: Session.get('myUserId')}).fetch();
|
||||
|
||||
// create a new message
|
||||
Messages.insert({text: "Hello, world!"});
|
||||
|
||||
// mark my first message as "important"
|
||||
Messages.update(my_messages[0].id, {$set: {important: true}});
|
||||
Messages.update(myMessages[0].id, {$set: {important: true}});
|
||||
|
||||
If you pass a `name` when you create the collection, then you are
|
||||
declaring a persistent collection — one that is stored on the
|
||||
@@ -552,9 +552,9 @@ undefined. If the insert is successful, `error` is undefined and
|
||||
|
||||
Example:
|
||||
|
||||
var groceries_id = Lists.insert({name: "Groceries"});
|
||||
Items.insert({list: groceries_id, name: "Watercress"});
|
||||
Items.insert({list: groceries_id, name: "Persimmons"});
|
||||
var groceriesId = Lists.insert({name: "Groceries"});
|
||||
Items.insert({list: groceriesId, name: "Watercress"});
|
||||
Items.insert({list: groceriesId, name: "Persimmons"});
|
||||
|
||||
{{> api_box update}}
|
||||
|
||||
@@ -635,9 +635,9 @@ the matching documents.
|
||||
Examples:
|
||||
|
||||
// Print the titles of the five top-scoring posts
|
||||
var top_posts = Posts.find({}, {sort: {score: -1}, limit: 5});
|
||||
var topPosts = Posts.find({}, {sort: {score: -1}, limit: 5});
|
||||
var count = 0;
|
||||
top_posts.forEach(function (post) {
|
||||
topPosts.forEach(function (post) {
|
||||
console.log("Title of post " + count + ": " + post.title);
|
||||
count += 1;
|
||||
});
|
||||
@@ -663,8 +663,8 @@ the matching documents.
|
||||
// Display a count of posts matching certain criteria. Automatically
|
||||
// keep it updated as the database changes.
|
||||
var frag = Meteor.render(function () {
|
||||
var high_scoring = Posts.find({score: {$gt: 10}});
|
||||
return "<p>There are " + high_scoring.count() + " posts with " +
|
||||
var highScoring = Posts.find({score: {$gt: 10}});
|
||||
return "<p>There are " + highScoring.count() + " posts with " +
|
||||
"scores greater than 10</p>";
|
||||
});
|
||||
document.body.appendChild(frag);
|
||||
@@ -687,29 +687,29 @@ query result.
|
||||
`callbacks` may have the following functions as properties:
|
||||
|
||||
<dl class="callbacks">
|
||||
{{#dtdd "added(document, before_index)"}}
|
||||
{{#dtdd "added(document, beforeIndex)"}}
|
||||
A new document entered the result set. It was inserted
|
||||
immediately before the document currently at the
|
||||
position `before_index`. Or if it was inserted at the end
|
||||
of the list, `before_index` will be equal to the (prior)
|
||||
position `beforeIndex`. Or if it was inserted at the end
|
||||
of the list, `beforeIndex` will be equal to the (prior)
|
||||
length of the list.
|
||||
{{/dtdd}}
|
||||
|
||||
{{#dtdd "changed(new_document, at_index, old_document)"}}
|
||||
The contents of the document at position `at_index`
|
||||
changed to `new_document`, was previously `old_document`.
|
||||
{{#dtdd "changed(newDocument, atIndex, oldDocument)"}}
|
||||
The contents of the document at position `atIndex`
|
||||
changed to `newDocument`, was previously `oldDocument`.
|
||||
{{/dtdd}}
|
||||
|
||||
{{#dtdd "moved(document, old_index, new_index)"}}
|
||||
{{#dtdd "moved(document, oldIndex, newIndex)"}}
|
||||
A document changed its position in the result set,
|
||||
from `old_index` to `new_index`. For your
|
||||
from `oldIndex` to `newIndex`. For your
|
||||
convenience, its current contents is `document`. (This will
|
||||
only fire immediately after `changed`.
|
||||
{{/dtdd}}
|
||||
|
||||
{{#dtdd "removed(old_document, at_index)"}}
|
||||
The document at position `at_index`, which was previously
|
||||
`old_document`, is no longer in the result set.
|
||||
{{#dtdd "removed(oldDocument, atIndex)"}}
|
||||
The document at position `atIndex`, which was previously
|
||||
`oldDocument`, is no longer in the result set.
|
||||
{{/dtdd}}
|
||||
</dl>
|
||||
|
||||
@@ -725,7 +725,7 @@ Example:
|
||||
|
||||
// Keep track of how many administrators are online.
|
||||
var count = 0;
|
||||
var query = Users.find({admin: true, online_now: true});
|
||||
var query = Users.find({admin: true, onlineNow: true});
|
||||
var handle = query.observe({
|
||||
added: function (user) {
|
||||
count++;
|
||||
@@ -836,9 +836,9 @@ store an arbitrary set of key-value pairs. Use it to store things like
|
||||
the currently selected item in a list.
|
||||
|
||||
What's special about `Session` is that it's reactive. If
|
||||
you call [`Session.get`](#session_get)`("current_list")`
|
||||
you call [`Session.get`](#session_get)`("currentList")`
|
||||
from inside a template, the template will automatically be rerendered
|
||||
whenever [`Session.set`](#session_set) is called.
|
||||
whenever [`Session.set`](#session_set)`("currentList", x)` is called.
|
||||
|
||||
{{> api_box set}}
|
||||
|
||||
@@ -882,33 +882,33 @@ These two expressions do the same thing:
|
||||
|
||||
Example:
|
||||
|
||||
<template name="posts_view">
|
||||
<template name="postsView">
|
||||
{{dstache}}! Show a dynamically updating list of items. Let the user click on an
|
||||
item to select it. The selected item is given a CSS class so it
|
||||
can be rendered differently. }}
|
||||
|
||||
{{dstache}}#each posts}}
|
||||
{{dstache}}> post_item }}
|
||||
{{dstache}}> postItem }}
|
||||
{{dstache}}/each}}
|
||||
</{{! }}template>
|
||||
|
||||
<template name="post_item">
|
||||
<div class="{{dstache}}post_class}}">{{dstache}}title}}</div>
|
||||
<template name="postItem">
|
||||
<div class="{{dstache}}postClass}}">{{dstache}}title}}</div>
|
||||
</{{! }}template>
|
||||
|
||||
///// in JS file
|
||||
Template.posts_view.posts = function() {
|
||||
Template.postsView.posts = function() {
|
||||
return Posts.find();
|
||||
};
|
||||
|
||||
Template.post_item.post_class = function() {
|
||||
return Session.equals("selected_post", this._id) ?
|
||||
Template.postItem.postClass = function() {
|
||||
return Session.equals("selectedPost", this._id) ?
|
||||
"selected" : "";
|
||||
};
|
||||
|
||||
Template.post_item.events({
|
||||
Template.postItem.events({
|
||||
'click': function() {
|
||||
Session.set("selected_post", this._id);
|
||||
Session.set("selectedPost", this._id);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1486,7 +1486,7 @@ sources.
|
||||
|
||||
Create an invalidation context by calling this constructor, then run
|
||||
some code inside the context with [`run`](#run). Finally, register a
|
||||
callback with [`on_invalidate`](#on_invalidate) that will get called
|
||||
callback with [`onInvalidate`](#oninvalidate) that will get called
|
||||
when the code you run wants to signal that it should be rerun.
|
||||
|
||||
Code can see if it's running inside an invalidation context by reading
|
||||
@@ -1496,7 +1496,7 @@ from inside a context. If it wants to participate in the reactivity
|
||||
system, it should save this context away, and later call the
|
||||
[`invalidate`](#invalidate) method on the context when it wants to
|
||||
signal that something has changed. If it does this, it should also use
|
||||
[`on_invalidate`](#on_invalidate) to set up a cleanup function so that
|
||||
[`onInvalidate`](#oninvalidate) to set up a cleanup function so that
|
||||
it can know when to stop listening for changes.
|
||||
|
||||
Invalidation contexts have an attribute `id` which is a unique positive
|
||||
@@ -1513,7 +1513,7 @@ previous value. It returns the result of calling `func`.
|
||||
It's fine for `run` to be called recursively. `current` will return the
|
||||
innermost context.
|
||||
|
||||
{{> api_box on_invalidate }}
|
||||
{{> api_box onInvalidate }}
|
||||
|
||||
If this context hasn't been invalidated yet, adds `callback` to the list
|
||||
of callbacks that will be called when [`invalidate`](#invalidate) is
|
||||
@@ -1523,25 +1523,25 @@ immediately.
|
||||
Typically this function will have two kinds of callers:
|
||||
|
||||
* The function that creates the invalidation context will use the
|
||||
`on_invalidate` callback as a signal to rerun the code in the context,
|
||||
`onInvalidate` callback as a signal to rerun the code in the context,
|
||||
to see what new value it returns. In order to rerun the code, it'll
|
||||
create a fresh invalidation context and reregister its `on_invalidate`
|
||||
create a fresh invalidation context and reregister its `onInvalidate`
|
||||
callback on that new context. When that context is invalidated the
|
||||
cycle will repeat.
|
||||
|
||||
* Functions that are sources of reactive data will save
|
||||
[`Meteor.deps.Context.current`](#current) into some kind of list of
|
||||
listeners. They'll use the `on_invalidate` callback to remove the
|
||||
listeners. They'll use the `onInvalidate` callback to remove the
|
||||
context from their listener list.
|
||||
|
||||
Example:
|
||||
|
||||
// Print the current username to the console. Will re-run every time
|
||||
// the username changes.
|
||||
var log_current_username = function () {
|
||||
var logCurrentUsername = function () {
|
||||
var update = function () {
|
||||
var ctx = new Meteor.deps.Context(); // invalidation context
|
||||
ctx.on_invalidate(update); // rerun update() on invalidation
|
||||
ctx.onInvalidate(update); // rerun update() on invalidation
|
||||
ctx.run(function () {
|
||||
var username = Session.get("username");
|
||||
console.log("The current username is now", username);
|
||||
@@ -1551,10 +1551,10 @@ Example:
|
||||
};
|
||||
|
||||
// Example use. Since Session is reactive (meaning that it knows how
|
||||
// to use Meteor.deps to record its dependencies), log_current_username
|
||||
// to use Meteor.deps to record its dependencies), logCurrentUsername
|
||||
// will be re-run whenever Session.set is called for "username".
|
||||
Session.set("username", "matt");
|
||||
log_current_username(); // prints matt
|
||||
logCurrentUsername(); // prints matt
|
||||
Session.set("username", "geoff"); // immediately prints geoff
|
||||
Session.set("username", "geoff"); // won't print: Session won't trigger
|
||||
// invalidation if the value is the same.
|
||||
@@ -1563,7 +1563,7 @@ Example:
|
||||
|
||||
If this function has already been called on this context, it does
|
||||
nothing (a mathematician would say that it is "idempotent.") Otherwise
|
||||
it calls each [`on_invalidate`](#on_invalidate) function registered on
|
||||
it calls each [`onInvalidate`](#oninvalidate) function registered on
|
||||
the context.
|
||||
|
||||
The functions aren't called immediately — instead, they will be
|
||||
@@ -1586,7 +1586,7 @@ Example:
|
||||
|
||||
// Function to get the temperature (and, if called in a reactive
|
||||
// context, start listening for changes to the temperature.)
|
||||
Weather.prototype.get_temp = function () {
|
||||
Weather.prototype.getTemp = function () {
|
||||
var context = Meteor.deps.Context.current;
|
||||
|
||||
// If we're inside a context, and it's not yet listening to
|
||||
@@ -1597,7 +1597,7 @@ Example:
|
||||
|
||||
// .. and remember to take it off our list when it goes away.
|
||||
var self = this;
|
||||
context.on_invalidate(function () {
|
||||
context.onInvalidate(function () {
|
||||
delete self.listeners[context.id];
|
||||
});
|
||||
}
|
||||
@@ -1608,20 +1608,20 @@ Example:
|
||||
|
||||
// Function to set the temperature, and notify anyone that might be
|
||||
// listening for temperature updates.
|
||||
Weather.prototype.set_temp = function (new_temp) {
|
||||
if (this.temperature === new_temp)
|
||||
Weather.prototype.setTemp = function (newTemp) {
|
||||
if (this.temperature === newTemp)
|
||||
return; // don't want to trigger invalidation if there's no change.
|
||||
|
||||
// Set the temperature
|
||||
this.temperature = new_temp;
|
||||
this.temperature = newTemp;
|
||||
|
||||
// Notify any contexts that care about temperature changes
|
||||
for (var context_id in this.listeners)
|
||||
// This will trigger the on_invalidate function above, but not
|
||||
for (var contextId in this.listeners)
|
||||
// This will trigger the onInvalidate function above, but not
|
||||
// immediately -- only when Meteor.flush() is called, or at the end
|
||||
// of the event loop. So we know that this.listeners will be
|
||||
// emptied, but it won't change while we're trying to loop over it.
|
||||
this.listeners[context_id].invalidate();
|
||||
this.listeners[contextId].invalidate();
|
||||
};
|
||||
|
||||
{{> api_box current }}
|
||||
@@ -1658,7 +1658,7 @@ that any auto-updating elements that you have created by calling
|
||||
DOM tree.
|
||||
|
||||
Technically speaking, `flush` calls the [invalidation
|
||||
callbacks](#on_invalidate) on every [reactive context](#context) that
|
||||
callbacks](#oninvalidate) on every [reactive context](#context) that
|
||||
has been [invalidated](#invalidate), but hasn't yet has its callbacks
|
||||
called. If the invalidation callbacks invalidate still more contexts,
|
||||
flush keeps flushing until everything is totally settled. The DOM
|
||||
@@ -1742,10 +1742,10 @@ Contents of the result object:
|
||||
|
||||
Example server method:
|
||||
|
||||
Meteor.methods({check_twitter: function (user_id) {
|
||||
Meteor.methods({checkTwitter: function (userId) {
|
||||
this.unblock();
|
||||
var result = Meteor.http.call("GET", "http://api.twitter.com/xxx",
|
||||
{params: {user: user_id}});
|
||||
{params: {user: userId}});
|
||||
if (result.statusCode === 200)
|
||||
return true
|
||||
return false;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
Template.api.is_client = {
|
||||
id: "meteor_is_client",
|
||||
name: "Meteor.is_client",
|
||||
Template.api.isClient = {
|
||||
id: "meteor_isclient",
|
||||
name: "Meteor.isClient",
|
||||
locus: "Anywhere",
|
||||
descr: ["Boolean variable. True if running in client environment."]
|
||||
};
|
||||
|
||||
Template.api.is_server = {
|
||||
id: "meteor_is_server",
|
||||
name: "Meteor.is_server",
|
||||
Template.api.isServer = {
|
||||
id: "meteor_isserver",
|
||||
name: "Meteor.isServer",
|
||||
locus: "Anywhere",
|
||||
descr: ["Boolean variable. True if running in server environment."]
|
||||
};
|
||||
@@ -164,9 +164,9 @@ Template.api.method_invocation_unblock = {
|
||||
descr: ["Call inside method invocation. Allow subsequent method from this client to begin running in a new fiber."]
|
||||
};
|
||||
|
||||
Template.api.method_invocation_is_simulation = {
|
||||
id: "method_is_simulation",
|
||||
name: "<i>this</i>.is_simulation",
|
||||
Template.api.method_invocation_isSimulation = {
|
||||
id: "method_issimulation",
|
||||
name: "<i>this</i>.isSimulation",
|
||||
locus: "Anywhere",
|
||||
descr: ["Access inside method invocation. Boolean value, true if this invocation is a stub."]
|
||||
};
|
||||
@@ -478,7 +478,7 @@ Template.api.Context = {
|
||||
id: "context",
|
||||
name: "new Meteor.deps.Context",
|
||||
locus: "Client",
|
||||
descr: ["Create an invalidation context. Invalidation contexts are used to run a piece of code, and record its dependencies so it can be rerun later if one of its inputs changes.", "An invalidation context is basically just a list of callbacks for an event that can fire only once. The [`on_invalidate`](#on_invalidate) method adds a callback to the list, and the [`invalidate`](#invalidate) method fires the event."]
|
||||
descr: ["Create an invalidation context. Invalidation contexts are used to run a piece of code, and record its dependencies so it can be rerun later if one of its inputs changes.", "An invalidation context is basically just a list of callbacks for an event that can fire only once. The [`onInvalidate`](#oninvalidate) method adds a callback to the list, and the [`invalidate`](#invalidate) method fires the event."]
|
||||
};
|
||||
|
||||
Template.api.run = {
|
||||
@@ -493,9 +493,9 @@ Template.api.run = {
|
||||
]
|
||||
};
|
||||
|
||||
Template.api.on_invalidate = {
|
||||
id: "on_invalidate",
|
||||
name: "<em>context</em>.on_invalidate(callback)",
|
||||
Template.api.onInvalidate = {
|
||||
id: "oninvalidate",
|
||||
name: "<em>context</em>.onInvalidate(callback)",
|
||||
locus: "Client",
|
||||
descr: ["Registers `callback` to be called when this context is invalidated. `callback` will be run exactly once."],
|
||||
args: [
|
||||
@@ -509,7 +509,7 @@ Template.api.invalidate = {
|
||||
id: "invalidate",
|
||||
name: "<em>context</em>.invalidate()",
|
||||
locus: "Client",
|
||||
descr: ["Add this context to the list of contexts that will have their `on_invalidate|on_invalidate` callbacks called by the next call to [`Meteor.flush`](#meteor_flush)."]
|
||||
descr: ["Add this context to the list of contexts that will have their [`onInvalidate`](#oninvalidate) callbacks called by the next call to [`Meteor.flush`](#meteor_flush)."]
|
||||
};
|
||||
|
||||
Template.api.current = {
|
||||
@@ -700,7 +700,7 @@ Template.api.set = {
|
||||
args: [
|
||||
{name: "key",
|
||||
type: "String",
|
||||
descr: "The key to set, eg, `selected_item`"},
|
||||
descr: "The key to set, eg, `selectedItem`"},
|
||||
{name: "value",
|
||||
type: "Any type",
|
||||
descr: "The new value for `key`"}
|
||||
|
||||
@@ -46,7 +46,7 @@ create a nested tree of separate files, or anything in between.
|
||||
Files outside the `client` and `server`
|
||||
subdirectories are loaded on both the client and the server! That's
|
||||
the place for model definitions and other functions. Meteor provides
|
||||
the variables [`is_client` and `is_server`](#meteor_is_client) so that
|
||||
the variables [`isClient` and `isServer`](#meteor_isclient) so that
|
||||
your code can alter its behavior depending on whether it's running
|
||||
on the client or the server.
|
||||
|
||||
@@ -115,8 +115,8 @@ queries and updates.
|
||||
|
||||
// server: publish all room documents, and per-room messages
|
||||
Meteor.publish("chatrooms");
|
||||
Meteor.publish("messages", function (room_id) {
|
||||
return Messages.find({room: room_id});
|
||||
Meteor.publish("messages", function (roomId) {
|
||||
return Messages.find({room: roomId});
|
||||
});
|
||||
|
||||
// client: subscribe to all rooms, and messages in the first room
|
||||
@@ -339,15 +339,15 @@ functions in JavaScript. Just add the helper functions directly on the
|
||||
`Template.[template name]` object. For example, in this template:
|
||||
|
||||
<template name="players">
|
||||
{{dstache}}#each top_scorers}}
|
||||
{{dstache}}#each topScorers}}
|
||||
<div>{{dstache}}name}}</div>
|
||||
{{dstache}}/each}}
|
||||
</{{! }}template>
|
||||
|
||||
instead of passing in `top_scorers` as data when we call the
|
||||
instead of passing in `topScorers` as data when we call the
|
||||
template function, we could define a function on `Template.players`:
|
||||
|
||||
Template.players.top_scorers = function () {
|
||||
Template.players.topScorers = function () {
|
||||
return Users.find({score: {$gt: 100}}, {sort: {score: -1}});
|
||||
};
|
||||
|
||||
@@ -360,28 +360,28 @@ Helpers can take arguments, and they receive the current template data
|
||||
in `this`:
|
||||
|
||||
// in a JavaScript file
|
||||
Template.players.league_is = function (league) {
|
||||
Template.players.leagueIs = function (league) {
|
||||
return this.league === league;
|
||||
};
|
||||
|
||||
<!-- in a HTML file -->
|
||||
<template name="players">
|
||||
{{dstache}}#each top_scorers}}
|
||||
{{dstache}}#if league_is "junior"}}
|
||||
{{dstache}}#each topScorers}}
|
||||
{{dstache}}#if leagueIs "junior"}}
|
||||
<div>Junior: {{dstache}}name}}</div>
|
||||
{{dstache}}/if}}
|
||||
{{dstache}}#if league_is "senior"}}
|
||||
{{dstache}}#if leagueIs "senior"}}
|
||||
<div>Senior: {{dstache}}name}}</div>
|
||||
{{dstache}}/if}}
|
||||
{{dstache}}/each}}
|
||||
</{{! }}template>
|
||||
|
||||
{{#note}}
|
||||
Handlebars note: `{{dstache}}#if league_is "junior"}}` is
|
||||
Handlebars note: `{{dstache}}#if leagueIs "junior"}}` is
|
||||
allowed because of a Meteor extension that allows nesting a helper
|
||||
in a block helper. (Both `if` and `league_is` are
|
||||
in a block helper. (Both `if` and `leagueIs` are
|
||||
technically helpers, and stock Handlebars would not invoke
|
||||
`league_is` here.)
|
||||
`leagueIs` here.)
|
||||
{{/note}}
|
||||
|
||||
Helpers can also be used to pass in constant data.
|
||||
@@ -397,19 +397,19 @@ the data context of the element that triggered the event.
|
||||
<!-- myapp.html -->
|
||||
<template name="scores">
|
||||
{{dstache}}#each player}}
|
||||
{{dstache}}> player_score}}
|
||||
{{dstache}}> playerScore}}
|
||||
{{dstache}}/each}}
|
||||
</{{! }}template>
|
||||
|
||||
<template name="player_score">
|
||||
<template name="playerScore">
|
||||
<div>{{dstache}}name}}: {{dstache}}score}}
|
||||
<span class="give_points">Give points</span>
|
||||
<span class="givePoints">Give points</span>
|
||||
</div>
|
||||
</{{! }}template>
|
||||
|
||||
<!-- myapp.js -->
|
||||
Template.player_score.events({
|
||||
'click .give_points': function () {
|
||||
Template.playerScore.events({
|
||||
'click .givePoints': function () {
|
||||
Users.update({_id: this._id}, {$inc: {score: 2}});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -80,8 +80,8 @@ var toc = [
|
||||
|
||||
"API", [
|
||||
"Core", [
|
||||
"Meteor.is_client",
|
||||
"Meteor.is_server",
|
||||
"Meteor.isClient",
|
||||
"Meteor.isServer",
|
||||
"Meteor.startup"
|
||||
],
|
||||
|
||||
@@ -100,7 +100,7 @@ var toc = [
|
||||
|
||||
{name: "Methods", id: "methods_header"}, [
|
||||
"Meteor.methods", [
|
||||
{instance: "this", name: "is_simulation", id: "method_is_simulation"},
|
||||
{instance: "this", name: "isSimulation", id: "method_issimulation"},
|
||||
{instance: "this", name: "unblock", id: "method_unblock"}
|
||||
],
|
||||
"Meteor.Error",
|
||||
@@ -177,7 +177,7 @@ var toc = [
|
||||
"Meteor.deps", [
|
||||
{name: "Meteor.deps.Context", id: "context"}, [
|
||||
{instance: "context", name: "run"},
|
||||
{instance: "context", name: "on_invalidate"},
|
||||
{instance: "context", name: "onInvalidate", id: "oninvalidate"},
|
||||
{instance: "context", name: "invalidate"}
|
||||
],
|
||||
{name: "Meteor.deps.Context.current", id: "current"},
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
<template name="projects">
|
||||
<div>
|
||||
{{#markdown}}
|
||||
# Projects
|
||||
|
||||
XXX
|
||||
|
||||
|
||||
|
||||
<!-- XXX this is not the right place for this! I'm just putting it here
|
||||
so it is _somewhere_. Move it later. -->
|
||||
|
||||
You can use the Meteor.startup() method on the server to run code once all
|
||||
your javascript as finished loading.
|
||||
|
||||
<pre class="prettyprint">
|
||||
Meteor.startup(function () { do_something_once_all_code_is_loaded() });
|
||||
</pre>
|
||||
|
||||
This only works on the server. On the client, use jQuery.ready() or an
|
||||
equivalent method.
|
||||
|
||||
|
||||
{{/markdown}}
|
||||
</div>
|
||||
</template>
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
Players = new Meteor.Collection("players");
|
||||
|
||||
if (Meteor.is_client) {
|
||||
if (Meteor.isClient) {
|
||||
Template.leaderboard.players = function () {
|
||||
return Players.find({}, {sort: {score: -1, name: 1}});
|
||||
};
|
||||
@@ -31,7 +31,7 @@ if (Meteor.is_client) {
|
||||
}
|
||||
|
||||
// On server startup, create some players if the database is empty.
|
||||
if (Meteor.is_server) {
|
||||
if (Meteor.isServer) {
|
||||
Meteor.startup(function () {
|
||||
if (Players.find().count() === 0) {
|
||||
var names = ["Ada Lovelace",
|
||||
|
||||
@@ -152,7 +152,7 @@ var autorun = function (f) {
|
||||
return;
|
||||
ctx = new Meteor.deps.Context;
|
||||
ctx.run(f);
|
||||
ctx.on_invalidate(rerun);
|
||||
ctx.onInvalidate(rerun);
|
||||
};
|
||||
rerun();
|
||||
return {
|
||||
|
||||
@@ -9,7 +9,7 @@ Chat.schema({room: String, message: String,
|
||||
username: String, created: Number});
|
||||
*/
|
||||
|
||||
if (Meteor.is_server) {
|
||||
if (Meteor.isServer) {
|
||||
Meteor.publish('rooms', function () {
|
||||
return Rooms.find();
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Todos = new Meteor.Collection("todos");
|
||||
//Todos.schema({text: String, done: Boolean, order: Number});
|
||||
|
||||
if (Meteor.is_server) {
|
||||
if (Meteor.isServer) {
|
||||
Meteor.publish('todos', function () {
|
||||
return Todos.find();
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@ Todos.schema({text: String,
|
||||
tags: [String]});
|
||||
*/
|
||||
|
||||
if (Meteor.is_server) {
|
||||
if (Meteor.isServer) {
|
||||
Meteor.publish('lists', function () {
|
||||
return Lists.find();
|
||||
});
|
||||
|
||||
@@ -109,7 +109,7 @@ Meteor.methods({
|
||||
}
|
||||
|
||||
// now only on the server, check against dictionary and score it.
|
||||
if (Meteor.is_server) {
|
||||
if (Meteor.isServer) {
|
||||
if (DICTIONARY.indexOf(word.word.toLowerCase()) === -1) {
|
||||
Words.update(word._id, {$set: {score: 0, state: 'bad'}});
|
||||
} else {
|
||||
@@ -121,7 +121,7 @@ Meteor.methods({
|
||||
});
|
||||
|
||||
|
||||
if (Meteor.is_server) {
|
||||
if (Meteor.isServer) {
|
||||
// publish all the non-idle players.
|
||||
Meteor.publish('players', function () {
|
||||
return Players.find({idle: false});
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
// calls f immediately if this context was already
|
||||
// invalidated. receives one argument, the context.
|
||||
on_invalidate: function (f) {
|
||||
onInvalidate: function (f) {
|
||||
if (this._invalidated)
|
||||
f(this);
|
||||
else
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// URL prefix for tests to talk to
|
||||
var _XHR_URL_PREFIX = "/http_test_responder";
|
||||
var url_prefix = function () {
|
||||
if (Meteor.is_server && _XHR_URL_PREFIX.indexOf("http") !== 0) {
|
||||
if (Meteor.isServer && _XHR_URL_PREFIX.indexOf("http") !== 0) {
|
||||
var address = __meteor_bootstrap__.app.address();
|
||||
_XHR_URL_PREFIX = "http://127.0.0.1:" + address.port + _XHR_URL_PREFIX;
|
||||
}
|
||||
@@ -36,7 +36,7 @@ testAsyncMulti("httpcall - basic", [
|
||||
|
||||
Meteor.http.call("GET", url_prefix()+url, options, expect(callback));
|
||||
|
||||
if (Meteor.is_server) {
|
||||
if (Meteor.isServer) {
|
||||
// test sync version
|
||||
var result = Meteor.http.call("GET", url_prefix()+url, options);
|
||||
callback(result.error, result);
|
||||
@@ -160,7 +160,7 @@ testAsyncMulti("httpcall - redirect", [
|
||||
}
|
||||
}));
|
||||
};
|
||||
if (Meteor.is_client && ! followRedirects) {
|
||||
if (Meteor.isClient && ! followRedirects) {
|
||||
// not supported, should fail
|
||||
test.throws(do_it);
|
||||
} else {
|
||||
@@ -187,7 +187,7 @@ testAsyncMulti("httpcall - methods", [
|
||||
test.equal(data.url, "/foo");
|
||||
// IE <= 8 turns seems to turn POSTs with no body into
|
||||
// GETs, inexplicably.
|
||||
if (Meteor.is_client && $.browser.msie && $.browser.version <= 8
|
||||
if (Meteor.isClient && $.browser.msie && $.browser.version <= 8
|
||||
&& meth === "POST")
|
||||
meth = "GET";
|
||||
test.equal(data.method, meth);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// XXX namespacing
|
||||
|
||||
Meteor._MethodInvocation = function (is_simulation, userId,
|
||||
Meteor._MethodInvocation = function (isSimulation, userId,
|
||||
globallySetUserId, unblock) {
|
||||
var self = this;
|
||||
|
||||
@@ -8,10 +8,13 @@ Meteor._MethodInvocation = function (is_simulation, userId,
|
||||
// if we're on a client (which may be a browser, or in the future a
|
||||
// server connecting to another server) and presently running a
|
||||
// simulation of a server-side method for latency compensation
|
||||
// purposes). not current true except in a client such as a browser,
|
||||
// purposes). not currently true except in a client such as a browser,
|
||||
// since there's usually no point in running stubs unless you have a
|
||||
// zero-latency connection to the user.
|
||||
this.is_simulation = is_simulation;
|
||||
this.isSimulation = isSimulation;
|
||||
|
||||
// XXX Backwards compatibility only. Remove this before 1.0.
|
||||
this.is_simulation = isSimulation;
|
||||
|
||||
// call this function to allow other method invocations (from the
|
||||
// same client) to continue running without waiting for this one to
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
if (Meteor.is_server) {
|
||||
if (Meteor.isServer) {
|
||||
// XXX namespacing
|
||||
var Future = __meteor_bootstrap__.require('fibers/future');
|
||||
}
|
||||
@@ -291,7 +291,7 @@ _.extend(Meteor._LivedataConnection.prototype, {
|
||||
});
|
||||
}
|
||||
|
||||
if (Meteor.is_client) {
|
||||
if (Meteor.isClient) {
|
||||
// If on a client, run the stub, if we have one. The stub is
|
||||
// supposed to make some temporary writes to the database to
|
||||
// give the user a smooth experience until the actual result of
|
||||
@@ -310,7 +310,7 @@ _.extend(Meteor._LivedataConnection.prototype, {
|
||||
self.setUserId(userId);
|
||||
};
|
||||
var invocation = new Meteor._MethodInvocation(
|
||||
true /* is_simulation */, self.userId(), setUserId);
|
||||
true /* isSimulation */, self.userId(), setUserId);
|
||||
try {
|
||||
var ret = Meteor._CurrentInvocation.withValue(invocation,function () {
|
||||
return stub.apply(invocation, args);
|
||||
@@ -325,8 +325,8 @@ _.extend(Meteor._LivedataConnection.prototype, {
|
||||
// rather than going on to do an RPC. If there was no stub,
|
||||
// we'll end up returning undefined.
|
||||
var enclosing = Meteor._CurrentInvocation.get();
|
||||
var is_simulation = enclosing && enclosing.is_simulation;
|
||||
if (is_simulation) {
|
||||
var isSimulation = enclosing && enclosing.isSimulation;
|
||||
if (isSimulation) {
|
||||
if (callback) {
|
||||
callback(exception, ret);
|
||||
return;
|
||||
@@ -352,7 +352,7 @@ _.extend(Meteor._LivedataConnection.prototype, {
|
||||
|
||||
// If the caller didn't give a callback, decide what to do.
|
||||
if (!callback) {
|
||||
if (Meteor.is_client)
|
||||
if (Meteor.isClient)
|
||||
// On the client, we don't have fibers, so we can't block. The
|
||||
// only thing we can do is to return undefined and discard the
|
||||
// result of the RPC.
|
||||
@@ -782,7 +782,7 @@ _.extend(Meteor, {
|
||||
var local_subs = [];
|
||||
var context = new Meteor.deps.Context();
|
||||
|
||||
context.on_invalidate(function () {
|
||||
context.onInvalidate(function () {
|
||||
// recurse.
|
||||
Meteor.autosubscribe(sub_func);
|
||||
// unsub after re-subbing, to avoid bouncing.
|
||||
|
||||
@@ -81,6 +81,8 @@ Tinytest.add("livedata stub - this", function (test) {
|
||||
startAndConnect(test, stream);
|
||||
|
||||
conn.methods({test_this: function() {
|
||||
test.isTrue(this.isSimulation);
|
||||
// XXX Backwards compatibility only. Remove this before 1.0.
|
||||
test.isTrue(this.is_simulation);
|
||||
this.unblock(); // should be a no-op
|
||||
}});
|
||||
@@ -568,4 +570,4 @@ Tinytest.add("livedata connection - onReconnect prepends messages correctly with
|
||||
// - reconnect, with session resume.
|
||||
// - restart on update flag
|
||||
// - on_update event
|
||||
// - reloading when the app changes, including session migration
|
||||
// - reloading when the app changes, including session migration
|
||||
|
||||
@@ -282,7 +282,7 @@ _.extend(Meteor._LivedataSession.prototype, {
|
||||
};
|
||||
|
||||
var invocation = new Meteor._MethodInvocation(
|
||||
false /* is_simulation */, self.userId, setUserId, unblock);
|
||||
false /* isSimulation */, self.userId, setUserId, unblock);
|
||||
try {
|
||||
var ret =
|
||||
Meteor._CurrentWriteFence.withValue(fence, function () {
|
||||
@@ -868,7 +868,7 @@ _.extend(Meteor._LivedataServer.prototype, {
|
||||
}
|
||||
|
||||
var invocation = new Meteor._MethodInvocation(
|
||||
false /* is_simulation */, userId, setUserId);
|
||||
false /* isSimulation */, userId, setUserId);
|
||||
try {
|
||||
var ret = Meteor._CurrentInvocation.withValue(invocation, function () {
|
||||
return handler.apply(invocation, args);
|
||||
|
||||
@@ -6,8 +6,8 @@ Meteor.methods({
|
||||
},
|
||||
exception: function (where, intended) {
|
||||
var shouldThrow =
|
||||
(Meteor.is_server && where === "server") ||
|
||||
(Meteor.is_client && where === "client") ||
|
||||
(Meteor.isServer && where === "server") ||
|
||||
(Meteor.isClient && where === "client") ||
|
||||
where === "both";
|
||||
|
||||
if (shouldThrow) {
|
||||
@@ -63,11 +63,11 @@ Ledger.allow({
|
||||
});
|
||||
|
||||
Meteor.startup(function () {
|
||||
if (Meteor.is_server)
|
||||
if (Meteor.isServer)
|
||||
Ledger.remove({}); // XXX can this please be Ledger.remove()?
|
||||
});
|
||||
|
||||
if (Meteor.is_server)
|
||||
if (Meteor.isServer)
|
||||
Meteor.publish('ledger', function (world) {
|
||||
return Ledger.find({world: world}, {key: {collection: 'ledger',
|
||||
world: world}});
|
||||
@@ -78,7 +78,7 @@ Meteor.methods({
|
||||
var from = Ledger.findOne({name: from_name, world: world});
|
||||
var to = Ledger.findOne({name: to_name, world: world});
|
||||
|
||||
if (Meteor.is_server)
|
||||
if (Meteor.isServer)
|
||||
cheat = false;
|
||||
|
||||
if (!from)
|
||||
|
||||
@@ -41,7 +41,7 @@ Tinytest.add("livedata - methods with colliding names", function (test) {
|
||||
testAsyncMulti("livedata - basic method invocation", [
|
||||
// Unknown methods
|
||||
function (test, expect) {
|
||||
if (Meteor.is_server) {
|
||||
if (Meteor.isServer) {
|
||||
// On server, with no callback, throws exception
|
||||
try {
|
||||
var ret = Meteor.call("unknown method");
|
||||
@@ -53,7 +53,7 @@ testAsyncMulti("livedata - basic method invocation", [
|
||||
test.equal(ret, undefined);
|
||||
}
|
||||
|
||||
if (Meteor.is_client) {
|
||||
if (Meteor.isClient) {
|
||||
// On client, with no callback, just returns undefined
|
||||
var ret = Meteor.call("unknown method");
|
||||
test.equal(ret, undefined);
|
||||
@@ -69,36 +69,36 @@ testAsyncMulti("livedata - basic method invocation", [
|
||||
// make sure 'undefined' is preserved as such, instead of turning
|
||||
// into null (JSON does not have 'undefined' so there is special
|
||||
// code for this)
|
||||
if (Meteor.is_server)
|
||||
if (Meteor.isServer)
|
||||
test.equal(Meteor.call("nothing"), undefined);
|
||||
if (Meteor.is_client)
|
||||
if (Meteor.isClient)
|
||||
test.equal(Meteor.call("nothing"), undefined);
|
||||
|
||||
test.equal(Meteor.call("nothing", expect(undefined, undefined)), undefined);
|
||||
},
|
||||
|
||||
function (test, expect) {
|
||||
if (Meteor.is_server)
|
||||
if (Meteor.isServer)
|
||||
test.equal(Meteor.call("echo"), []);
|
||||
if (Meteor.is_client)
|
||||
if (Meteor.isClient)
|
||||
test.equal(Meteor.call("echo"), undefined);
|
||||
|
||||
test.equal(Meteor.call("echo", expect(undefined, [])), undefined);
|
||||
},
|
||||
|
||||
function (test, expect) {
|
||||
if (Meteor.is_server)
|
||||
if (Meteor.isServer)
|
||||
test.equal(Meteor.call("echo", 12), [12]);
|
||||
if (Meteor.is_client)
|
||||
if (Meteor.isClient)
|
||||
test.equal(Meteor.call("echo", 12), undefined);
|
||||
|
||||
test.equal(Meteor.call("echo", 12, expect(undefined, [12])), undefined);
|
||||
},
|
||||
|
||||
function (test, expect) {
|
||||
if (Meteor.is_server)
|
||||
if (Meteor.isServer)
|
||||
test.equal(Meteor.call("echo", 12, {x: 13}), [12, {x: 13}]);
|
||||
if (Meteor.is_client)
|
||||
if (Meteor.isClient)
|
||||
test.equal(Meteor.call("echo", 12, {x: 13}), undefined);
|
||||
|
||||
test.equal(Meteor.call("echo", 12, {x: 13},
|
||||
@@ -128,7 +128,7 @@ testAsyncMulti("livedata - basic method invocation", [
|
||||
function (test, expect) {
|
||||
// No callback
|
||||
|
||||
if (Meteor.is_server) {
|
||||
if (Meteor.isServer) {
|
||||
test.throws(function () {
|
||||
Meteor.call("exception", "both");
|
||||
});
|
||||
@@ -139,7 +139,7 @@ testAsyncMulti("livedata - basic method invocation", [
|
||||
test.equal(Meteor.call("exception", "client"), undefined);
|
||||
}
|
||||
|
||||
if (Meteor.is_client) {
|
||||
if (Meteor.isClient) {
|
||||
// The client exception is thrown away because it's in the
|
||||
// stub. The server exception is throw away because we didn't
|
||||
// give a callback.
|
||||
@@ -150,7 +150,7 @@ testAsyncMulti("livedata - basic method invocation", [
|
||||
|
||||
// With callback
|
||||
|
||||
if (Meteor.is_client) {
|
||||
if (Meteor.isClient) {
|
||||
test.equal(
|
||||
Meteor.call("exception", "both",
|
||||
expect(failure(test, 500, "Internal server error"))),
|
||||
@@ -162,7 +162,7 @@ testAsyncMulti("livedata - basic method invocation", [
|
||||
test.equal(Meteor.call("exception", "client"), undefined);
|
||||
}
|
||||
|
||||
if (Meteor.is_server) {
|
||||
if (Meteor.isServer) {
|
||||
test.equal(
|
||||
Meteor.call("exception", "both",
|
||||
expect(failure(test, "Test method throwing an exception"))),
|
||||
@@ -176,7 +176,7 @@ testAsyncMulti("livedata - basic method invocation", [
|
||||
},
|
||||
|
||||
function (test, expect) {
|
||||
if (Meteor.is_server) {
|
||||
if (Meteor.isServer) {
|
||||
var threw = false;
|
||||
try {
|
||||
Meteor.call("exception", "both", true);
|
||||
@@ -188,7 +188,7 @@ testAsyncMulti("livedata - basic method invocation", [
|
||||
test.isTrue(threw);
|
||||
}
|
||||
|
||||
if (Meteor.is_client) {
|
||||
if (Meteor.isClient) {
|
||||
test.equal(
|
||||
Meteor.call("exception", "both", true,
|
||||
expect(failure(test, 999,
|
||||
@@ -214,7 +214,7 @@ var checkBalances = function (test, a, b) {
|
||||
};
|
||||
|
||||
var onQuiesce = function (f) {
|
||||
if (Meteor.is_server)
|
||||
if (Meteor.isServer)
|
||||
f();
|
||||
else
|
||||
Meteor.default_connection.onQuiesce(f);
|
||||
@@ -224,7 +224,7 @@ var onQuiesce = function (f) {
|
||||
// this is a big hack (and XXX pollutes the global test namespace)
|
||||
testAsyncMulti("livedata - compound methods", [
|
||||
function (test) {
|
||||
if (Meteor.is_client)
|
||||
if (Meteor.isClient)
|
||||
Meteor.subscribe("ledger", test.runId());
|
||||
|
||||
Ledger.insert({name: "alice", balance: 100, world: test.runId()});
|
||||
@@ -246,7 +246,7 @@ testAsyncMulti("livedata - compound methods", [
|
||||
Meteor.call('ledger/transfer', test.runId(), "alice", "bob", 100, true,
|
||||
expect(failure(test, 409)));
|
||||
|
||||
if (Meteor.is_client)
|
||||
if (Meteor.isClient)
|
||||
// client can fool itself by cheating, but only until the sync
|
||||
// finishes
|
||||
checkBalances(test, -10, 160);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Meteor = {
|
||||
is_client: true,
|
||||
is_server: false
|
||||
isClient: true,
|
||||
isServer: false
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Tinytest.add("environment - client basics", function (test) {
|
||||
test.isTrue(Meteor.is_client);
|
||||
test.isFalse(Meteor.is_server);
|
||||
test.isTrue(Meteor.isClient);
|
||||
test.isFalse(Meteor.isServer);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Meteor = {
|
||||
is_client: false,
|
||||
is_server: true
|
||||
isClient: false,
|
||||
isServer: true
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Tinytest.add("environment - server basics", function (test) {
|
||||
test.isFalse(Meteor.is_client);
|
||||
test.isTrue(Meteor.is_server);
|
||||
test.isFalse(Meteor.isClient);
|
||||
test.isTrue(Meteor.isServer);
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ _.extend(Meteor, {
|
||||
|
||||
setTimeout: function (f, duration) {
|
||||
if (Meteor._CurrentInvocation) {
|
||||
if (Meteor._CurrentInvocation.get() && Meteor._CurrentInvocation.get().is_simulation)
|
||||
if (Meteor._CurrentInvocation.get() && Meteor._CurrentInvocation.get().isSimulation)
|
||||
throw new Error("Can't set timers inside simulations");
|
||||
|
||||
var f_with_ci = f;
|
||||
@@ -20,7 +20,7 @@ _.extend(Meteor, {
|
||||
|
||||
setInterval: function (f, duration) {
|
||||
if (Meteor._CurrentInvocation) {
|
||||
if (Meteor._CurrentInvocation.get() && Meteor._CurrentInvocation.get().is_simulation)
|
||||
if (Meteor._CurrentInvocation.get() && Meteor._CurrentInvocation.get().isSimulation)
|
||||
throw new Error("Can't set timers inside simulations");
|
||||
|
||||
var f_with_ci = f;
|
||||
|
||||
@@ -258,7 +258,7 @@ LocalCollection.Cursor.prototype._markAsReactive = function (options) {
|
||||
// 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.on_invalidate(handle.stop);
|
||||
context.onInvalidate(handle.stop);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ Meteor.Collection = function (name, manager, driver, preventAutopublish) {
|
||||
|
||||
// note: nameless collections never have a manager
|
||||
manager = name && (manager ||
|
||||
(Meteor.is_client ?
|
||||
(Meteor.isClient ?
|
||||
Meteor.default_connection : Meteor.default_server));
|
||||
|
||||
if (!driver) {
|
||||
@@ -402,7 +402,7 @@ _.each(["insert", "update", "remove"], function (name) {
|
||||
if (args.length && args[args.length - 1] instanceof Function)
|
||||
callback = args.pop();
|
||||
|
||||
if (Meteor.is_client && !callback) {
|
||||
if (Meteor.isClient && !callback) {
|
||||
// Client can't block, so it can't report errors by exception,
|
||||
// only by callback. If they forget the callback, give them a
|
||||
// default one that logs the error, so they aren't totally
|
||||
|
||||
@@ -14,7 +14,7 @@ testAsyncMulti("mongo-livedata - database failure reporting", [
|
||||
};
|
||||
|
||||
_.each(["insert", "remove", "update"], function (op) {
|
||||
if (Meteor.is_server) {
|
||||
if (Meteor.isServer) {
|
||||
test.throws(function () {
|
||||
ftc[op]({fail: true});
|
||||
});
|
||||
@@ -22,7 +22,7 @@ testAsyncMulti("mongo-livedata - database failure reporting", [
|
||||
ftc[op]({fail: true}, expect(exception));
|
||||
}
|
||||
|
||||
if (Meteor.is_client) {
|
||||
if (Meteor.isClient) {
|
||||
ftc[op]({fail: true}, expect(exception));
|
||||
|
||||
// This would log to console in normal operation.
|
||||
@@ -37,7 +37,7 @@ testAsyncMulti("mongo-livedata - database failure reporting", [
|
||||
Tinytest.addAsync("mongo-livedata - basics", function (test, onComplete) {
|
||||
var run = test.runId();
|
||||
var coll, coll2;
|
||||
if (Meteor.is_client) {
|
||||
if (Meteor.isClient) {
|
||||
coll = new Meteor.Collection(null); // local, unmanaged
|
||||
coll2 = new Meteor.Collection(null); // local, unmanaged
|
||||
} else {
|
||||
@@ -62,7 +62,7 @@ Tinytest.addAsync("mongo-livedata - basics", function (test, onComplete) {
|
||||
});
|
||||
|
||||
var captureObserve = function (f) {
|
||||
if (Meteor.is_client) {
|
||||
if (Meteor.isClient) {
|
||||
f();
|
||||
} else {
|
||||
var fence = new Meteor._WriteFence;
|
||||
@@ -119,7 +119,7 @@ Tinytest.addAsync("mongo-livedata - basics", function (test, onComplete) {
|
||||
var total = 0;
|
||||
cur.forEach(function (doc) {
|
||||
total *= 10;
|
||||
if (Meteor.is_server) {
|
||||
if (Meteor.isServer) {
|
||||
// Verify that the callbacks from forEach run sequentially and that
|
||||
// forEach waits for them to complete (issue# 321). If they do not run
|
||||
// sequentially, then the second callback could execute during the first
|
||||
@@ -173,7 +173,7 @@ Tinytest.addAsync("mongo-livedata - fuzz test", function(test, onComplete) {
|
||||
|
||||
var run = test.runId();
|
||||
var coll;
|
||||
if (Meteor.is_client) {
|
||||
if (Meteor.isClient) {
|
||||
coll = new Meteor.Collection(null); // local, unmanaged
|
||||
} else {
|
||||
coll = new Meteor.Collection("livedata_test_collection_"+run);
|
||||
@@ -219,7 +219,7 @@ Tinytest.addAsync("mongo-livedata - fuzz test", function(test, onComplete) {
|
||||
};
|
||||
|
||||
var finishObserve = function (f) {
|
||||
if (Meteor.is_client) {
|
||||
if (Meteor.isClient) {
|
||||
f();
|
||||
} else {
|
||||
var fence = new Meteor._WriteFence;
|
||||
@@ -238,7 +238,7 @@ Tinytest.addAsync("mongo-livedata - fuzz test", function(test, onComplete) {
|
||||
var max_counters = _.clone(counters);
|
||||
|
||||
finishObserve(function () {
|
||||
if (Meteor.is_server)
|
||||
if (Meteor.isServer)
|
||||
obs._suspendPolling();
|
||||
|
||||
// Do a batch of 1-10 operations
|
||||
@@ -271,7 +271,7 @@ Tinytest.addAsync("mongo-livedata - fuzz test", function(test, onComplete) {
|
||||
max_counters.remove++;
|
||||
}
|
||||
}
|
||||
if (Meteor.is_server)
|
||||
if (Meteor.isServer)
|
||||
obs._resumePolling();
|
||||
|
||||
});
|
||||
@@ -297,14 +297,14 @@ Tinytest.addAsync("mongo-livedata - fuzz test", function(test, onComplete) {
|
||||
Tinytest.addAsync("mongo-livedata - scribbling", function (test, onComplete) {
|
||||
var run = test.runId();
|
||||
var coll;
|
||||
if (Meteor.is_client) {
|
||||
if (Meteor.isClient) {
|
||||
coll = new Meteor.Collection(null); // local, unmanaged
|
||||
} else {
|
||||
coll = new Meteor.Collection("livedata_test_collection_"+run);
|
||||
}
|
||||
|
||||
var runInFence = function (f) {
|
||||
if (Meteor.is_client) {
|
||||
if (Meteor.isClient) {
|
||||
f();
|
||||
} else {
|
||||
var fence = new Meteor._WriteFence;
|
||||
|
||||
4
packages/past/client_past_test.js
Normal file
4
packages/past/client_past_test.js
Normal file
@@ -0,0 +1,4 @@
|
||||
Tinytest.add("past - client", function (test) {
|
||||
test.isTrue(Meteor.is_client);
|
||||
test.isFalse(Meteor.is_server);
|
||||
});
|
||||
@@ -4,5 +4,14 @@ Package.describe({
|
||||
});
|
||||
|
||||
Package.on_use(function (api) {
|
||||
api.use('deps');
|
||||
api.add_files('past.js', ['client', 'server']);
|
||||
});
|
||||
|
||||
Package.on_test(function (api) {
|
||||
api.use('past');
|
||||
api.use('tinytest');
|
||||
|
||||
api.add_files('client_past_test.js', 'client');
|
||||
api.add_files('server_past_test.js', 'server');
|
||||
});
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// for a little while, accept Sky as an alias for Meteor.
|
||||
// remove this once people have transitioned.
|
||||
if (typeof Sky === "undefined") Sky = Meteor;
|
||||
// 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;
|
||||
// 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.
|
||||
|
||||
4
packages/past/server_past_test.js
Normal file
4
packages/past/server_past_test.js
Normal file
@@ -0,0 +1,4 @@
|
||||
Tinytest.add("past - server", function (test) {
|
||||
test.isFalse(Meteor.is_client);
|
||||
test.isTrue(Meteor.is_server);
|
||||
});
|
||||
@@ -54,7 +54,7 @@ Session = _.extend({}, {
|
||||
|
||||
if (context && !(context.id in self.key_deps[key])) {
|
||||
self.key_deps[key][context.id] = context;
|
||||
context.on_invalidate(function () {
|
||||
context.onInvalidate(function () {
|
||||
delete self.key_deps[key][context.id];
|
||||
});
|
||||
}
|
||||
@@ -79,7 +79,7 @@ Session = _.extend({}, {
|
||||
|
||||
if (!(context.id in self.key_value_deps[key][value])) {
|
||||
self.key_value_deps[key][value][context.id] = context;
|
||||
context.on_invalidate(function () {
|
||||
context.onInvalidate(function () {
|
||||
delete self.key_value_deps[key][value][context.id];
|
||||
|
||||
// clean up [key][value] if it's now empty, so we don't use
|
||||
|
||||
@@ -324,7 +324,7 @@ var scheduleOnscreenSetup = function (frag, landmarkRanges) {
|
||||
};
|
||||
|
||||
var ctx = new Meteor.deps.Context;
|
||||
ctx.on_invalidate(function () {
|
||||
ctx.onInvalidate(function () {
|
||||
if (finalized)
|
||||
return;
|
||||
|
||||
@@ -783,10 +783,10 @@ Spark.isolate = function (htmlFunc) {
|
||||
Spark.renderToRange(range, function () {
|
||||
return ctx.run(htmlFunc);
|
||||
});
|
||||
ctx.on_invalidate(refresh);
|
||||
ctx.onInvalidate(refresh);
|
||||
};
|
||||
|
||||
ctx.on_invalidate(refresh);
|
||||
ctx.onInvalidate(refresh);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -807,7 +807,7 @@ var atFlushTime = function (f) {
|
||||
|
||||
if (! atFlushContext) {
|
||||
atFlushContext = new Meteor.deps.Context;
|
||||
atFlushContext.on_invalidate(function () {
|
||||
atFlushContext.onInvalidate(function () {
|
||||
var f;
|
||||
while ((f = atFlushQueue.shift())) {
|
||||
// Since atFlushContext is truthy, if f() calls atFlushTime
|
||||
|
||||
@@ -42,7 +42,9 @@ Meteor._Stream = function (url) {
|
||||
|
||||
//// Reactive status
|
||||
self.current_status = {
|
||||
status: "connecting", connected: false, retry_count: 0
|
||||
status: "connecting", connected: false, retryCount: 0,
|
||||
// XXX Backwards compatibility only. Remove this before 1.0.
|
||||
retry_count: 0
|
||||
};
|
||||
|
||||
self.status_listeners = {}; // context.id -> context
|
||||
@@ -119,7 +121,7 @@ _.extend(Meteor._Stream.prototype, {
|
||||
var context = Meteor.deps && Meteor.deps.Context.current;
|
||||
if (context && !(context.id in self.status_listeners)) {
|
||||
self.status_listeners[context.id] = context;
|
||||
context.on_invalidate(function () {
|
||||
context.onInvalidate(function () {
|
||||
delete self.status_listeners[context.id];
|
||||
});
|
||||
}
|
||||
@@ -146,7 +148,9 @@ _.extend(Meteor._Stream.prototype, {
|
||||
if (self.retry_timer)
|
||||
clearTimeout(self.retry_timer);
|
||||
self.retry_timer = null;
|
||||
self.current_status.retry_count -= 1; // don't count manual retries
|
||||
self.current_status.retryCount -= 1; // don't count manual retries
|
||||
// XXX Backwards compatibility only. Remove this before 1.0.
|
||||
self.current_status.retry_count = self.current_status.retryCount;
|
||||
self._retry_now();
|
||||
},
|
||||
|
||||
@@ -197,7 +201,9 @@ _.extend(Meteor._Stream.prototype, {
|
||||
// update status
|
||||
self.current_status.status = "connected";
|
||||
self.current_status.connected = true;
|
||||
self.current_status.retry_count = 0;
|
||||
self.current_status.retryCount = 0;
|
||||
// XXX Backwards compatibility only. Remove before 1.0.
|
||||
self.current_status.retry_count = self.current_status.retryCount;
|
||||
self.status_changed();
|
||||
|
||||
// fire resets. This must come after status change so that clients
|
||||
@@ -275,14 +281,16 @@ _.extend(Meteor._Stream.prototype, {
|
||||
_retry_later: function () {
|
||||
var self = this;
|
||||
|
||||
var timeout = self._retry_timeout(self.current_status.retry_count);
|
||||
var timeout = self._retry_timeout(self.current_status.retryCount);
|
||||
if (self.retry_timer)
|
||||
clearTimeout(self.retry_timer);
|
||||
self.retry_timer = setTimeout(_.bind(self._retry_now, self), timeout);
|
||||
|
||||
self.current_status.status = "waiting";
|
||||
self.current_status.connected = false;
|
||||
self.current_status.retry_time = (new Date()).getTime() + timeout;
|
||||
self.current_status.retryTime = (new Date()).getTime() + timeout;
|
||||
// XXX Backwards compatibility only. Remove this before 1.0.
|
||||
self.current_status.retry_time = self.current_status.retryTime;
|
||||
self.status_changed();
|
||||
},
|
||||
|
||||
@@ -292,9 +300,13 @@ _.extend(Meteor._Stream.prototype, {
|
||||
if (self.force_fail)
|
||||
return;
|
||||
|
||||
self.current_status.retry_count += 1;
|
||||
self.current_status.retryCount += 1;
|
||||
// XXX Backwards compatibility only. Remove this before 1.0.
|
||||
self.current_status.retry_count = self.current_status.retryCount;
|
||||
self.current_status.status = "connecting";
|
||||
self.current_status.connected = false;
|
||||
delete self.current_status.retryTime;
|
||||
// XXX Backwards compatibility only. Remove this before 1.0.
|
||||
delete self.current_status.retry_time;
|
||||
self.status_changed();
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@ Tinytest.add("stream - status", function (test) {
|
||||
var status = Meteor.status();
|
||||
test.equal(typeof status, "object");
|
||||
test.isTrue(status.status);
|
||||
// Make sure backward-compatiblity names are defined.
|
||||
test.equal(status.retryCount, status.retry_count);
|
||||
test.equal(status.retryTime, status.retry_time);
|
||||
});
|
||||
|
||||
testAsyncMulti("stream - reconnect", [
|
||||
|
||||
@@ -51,7 +51,7 @@ OnscreenDiv.prototype.kill = function() {
|
||||
self.div.parentNode.removeChild(self.div);
|
||||
|
||||
var cx = new Meteor.deps.Context;
|
||||
cx.on_invalidate(function() {
|
||||
cx.onInvalidate(function() {
|
||||
Spark.finalize(self.div);
|
||||
});
|
||||
cx.invalidate();
|
||||
|
||||
@@ -27,7 +27,7 @@ ReactiveVar.prototype.get = function() {
|
||||
if (context && !(context.id in this._deps)) {
|
||||
this._deps[context.id] = context;
|
||||
var self = this;
|
||||
context.on_invalidate(function() {
|
||||
context.onInvalidate(function() {
|
||||
delete self._deps[context.id];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ WrappedFrag.prototype.release = function() {
|
||||
// Clean up on flush, if hits 0. Wait to decrement
|
||||
// so no one else cleans it up first.
|
||||
var cx = new Meteor.deps.Context;
|
||||
cx.on_invalidate(function() {
|
||||
cx.onInvalidate(function() {
|
||||
if (! --frag["_protect"]) {
|
||||
Spark.finalize(frag);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ _.extend(TestCaseResults.prototype, {
|
||||
var self = this;
|
||||
|
||||
if (self.stop_at_offset === 0) {
|
||||
if (Meteor.is_client) {
|
||||
if (Meteor.isClient) {
|
||||
// Only supported on the browser for now..
|
||||
var now = (+new Date);
|
||||
debugger;
|
||||
@@ -351,7 +351,7 @@ _.extend(TestRun.prototype, {
|
||||
var testGroups = _.values(
|
||||
_.groupBy(self.manager.ordered_tests,
|
||||
function(t) {
|
||||
if (Meteor.is_server)
|
||||
if (Meteor.isServer)
|
||||
return "SERVER";
|
||||
if (t.async)
|
||||
return "ASYNC";
|
||||
|
||||
Reference in New Issue
Block a user