mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Merge branch 'master' into devel
Brings changes done on release-0.5.3 into devel.
This commit is contained in:
80
History.md
80
History.md
@@ -1,12 +1,80 @@
|
||||
|
||||
## vNEXT
|
||||
|
||||
* `OAuth1Binding` improvements: #539
|
||||
* `OAuth1Binding.get` and `OAuth1Binding.call` now return the full response
|
||||
(including headers and statusCode), rather than just the data.
|
||||
* Introduce `OAuth1Binding.post`.
|
||||
* `OAuth1Binding.get`, `OAuth1Binding.call` and `OAuth1Binding.post` now take
|
||||
a `params` argument. This facilitates making calls to the Twitter API.
|
||||
## v0.5.3
|
||||
|
||||
* Add `--settings` argument to `meteor deploy` and `meteor run`. This
|
||||
allows you to specify deployment-specific information made available
|
||||
to server code in the variable `Meteor.settings`.
|
||||
|
||||
* Support unlimited open tabs in a single browser. Work around the
|
||||
browser per-hostname connection limit by using randomized hostnames
|
||||
for deployed apps. #131
|
||||
|
||||
* minimongo improvements:
|
||||
* Allow observing cursors with `skip` or `limit`. #528
|
||||
* Allow sorting on `dotted.sub.keys`. #533
|
||||
* Allow querying specific array elements (`foo.1.bar`).
|
||||
* `$and`, `$or`, and `$nor` no longer accept empty arrays (for consistency
|
||||
with Mongo)
|
||||
|
||||
* Re-rendering a template with Spark no longer reverts changes made by
|
||||
users to a `preserve`d form element. Instead, the newly rendered value
|
||||
is only applied if it is different from the previously rendered value.
|
||||
Additionally, <INPUT> elements with type other than TEXT can now have
|
||||
reactive values (eg, the labels on submit buttons can now be
|
||||
reactive). #510 #514 #523 #537 #558
|
||||
|
||||
* Support JavaScript RegExp objects in selectors in Collection write
|
||||
methods on the client, eg `myCollection.remove({foo: /bar/})`. #346
|
||||
|
||||
* `meteor` command-line improvements:
|
||||
* Improve error message when mongod fails to start.
|
||||
* The `NODE_OPTIONS` environment variable can be used to pass command-line
|
||||
flags to node (eg, `--debug` or `--debug-brk` to enable the debugger).
|
||||
* Die with error if an app name is mistakenly passed to `meteor reset`.
|
||||
|
||||
* Add support for "offline" access tokens with Google login. #464 #525
|
||||
|
||||
* Don't remove `serviceData` fields from previous logins when logging in
|
||||
with an external service.
|
||||
|
||||
* Improve `OAuth1Binding` to allow making authenticated API calls to
|
||||
OAuth1 providers (eg Twitter). #539
|
||||
|
||||
* New login providers automatically work with `{{loginButtons}}` without
|
||||
needing to edit the `accounts-ui-unstyled` package. #572
|
||||
|
||||
* Use `Content-Type: application/json` by default when sending JSON data
|
||||
with `Meteor.http`.
|
||||
|
||||
* Improvements to `jsparse`: hex literals, keywords as property names, ES5 line
|
||||
continuations, trailing commas in object literals, line numbers in error
|
||||
messages, decimal literals starting with `.`, regex character classes with
|
||||
slashes.
|
||||
|
||||
* Spark improvements:
|
||||
* Improve rendering of <SELECT> elements on IE. #496
|
||||
* Don't lose nested data contexts in IE9/10 after two seconds. #458
|
||||
* Don't print a stack trace if DOM nodes are manually removed
|
||||
from the document without calling `Spark.finalize`. #392
|
||||
|
||||
* Always use the `autoReconnect` flag when connecting to Mongo. #425
|
||||
|
||||
* Fix server-side `observe` with no `added` callback. #589
|
||||
|
||||
* Fix re-sending method calls on reconnect. #538
|
||||
|
||||
* Remove deprecated `/sockjs` URL support from `Meteor.connect`.
|
||||
|
||||
* Avoid losing a few bits of randomness in UUID v4 creation. #519
|
||||
|
||||
* Update clean-css package from 0.8.2 to 0.8.3, fixing minification of `0%`
|
||||
values in `hsl` colors. #515
|
||||
|
||||
Patches contributed by GitHub users Ed-von-Schleck, egtann, jwulf, lvbreda,
|
||||
martin-naumann, meawoppl, nwmartin, timhaines, and zealoushacker.
|
||||
|
||||
|
||||
## v0.5.2
|
||||
|
||||
|
||||
@@ -6,9 +6,13 @@
|
||||
cd `dirname $0`
|
||||
METEOR=`pwd`/../meteor
|
||||
|
||||
if [ -z "$NODE" ]; then
|
||||
NODE=`pwd`/node.sh
|
||||
fi
|
||||
|
||||
#If this ever takes more options, use getopt
|
||||
if [ "$1" == "--global" ]; then
|
||||
METEOR=/usr/local/bin/meteor
|
||||
METEOR=meteor
|
||||
fi
|
||||
|
||||
DIR=`mktemp -d -t meteor-cli-test-XXXXXXXX`
|
||||
@@ -77,7 +81,8 @@ echo "... run"
|
||||
MONGOMARK='--bind_ip 127.0.0.1 --smallfiles --port 9102'
|
||||
# kill any old test meteor
|
||||
# there is probably a better way to do this, but it is at least portable across macos and linux
|
||||
ps ax | grep -e 'meteor.js -p 9100' | grep -v grep | awk '{print $1}' | xargs kill
|
||||
# (the || true is needed on linux, whose xargs will invoke kill even with no args)
|
||||
ps ax | grep -e 'meteor.js -p 9100' | grep -v grep | awk '{print $1}' | xargs kill || true
|
||||
|
||||
! $METEOR mongo > /dev/null 2>&1
|
||||
$METEOR reset > /dev/null 2>&1
|
||||
@@ -89,7 +94,7 @@ PORT=9100
|
||||
$METEOR -p $PORT > /dev/null 2>&1 &
|
||||
METEOR_PID=$!
|
||||
|
||||
sleep 1 # XXX XXX lame
|
||||
sleep 2 # XXX XXX lame
|
||||
|
||||
test -d .meteor/local/db
|
||||
ps ax | grep -e "$MONGOMARK" | grep -v grep > /dev/null
|
||||
@@ -111,25 +116,31 @@ echo "... rerun"
|
||||
$METEOR -p $PORT > /dev/null 2>&1 &
|
||||
METEOR_PID=$!
|
||||
|
||||
sleep 1 # XXX XXX lame
|
||||
sleep 2 # XXX XXX lame
|
||||
|
||||
ps ax | grep -e "$MONGOMARK" | grep -v grep > /dev/null
|
||||
curl -s "http://localhost:$PORT" > /dev/null
|
||||
|
||||
kill $METEOR_PID
|
||||
ps ax | grep -e "$MONGOMARK" | grep -v grep | awk '{print $1}' | xargs kill
|
||||
sleep 10 # XXX XXX lame. have to wait for inner app to die via keepalive!
|
||||
|
||||
ps ax | grep -e "$MONGOMARK" | grep -v grep | awk '{print $1}' | xargs kill || true
|
||||
sleep 2 # need to make sure these kills take effect
|
||||
|
||||
echo "... mongo message"
|
||||
|
||||
nc -l localhost $(($PORT + 2)) &
|
||||
NC_PID=$!
|
||||
# Run a server on the same port as mongod, so that mongod fails to start up. Rig
|
||||
# it so that a single connection will cause it to exit.
|
||||
$NODE -e 'require("net").createServer(function(){process.exit(0)}).listen('$PORT'+2, "127.0.0.1")' &
|
||||
|
||||
sleep 1
|
||||
|
||||
$METEOR -p $PORT > error.txt || true
|
||||
|
||||
grep 'port was closed' error.txt > /dev/null
|
||||
|
||||
kill -9 $NC_PID > /dev/null
|
||||
|
||||
# Kill the server by connecting to it.
|
||||
$NODE -e 'require("net").connect({host:"127.0.0.1",port:'$PORT'+2},function(){process.exit(0);})'
|
||||
|
||||
echo "... settings"
|
||||
|
||||
|
||||
53
admin/copy-release-from-jenkins.sh
Executable file
53
admin/copy-release-from-jenkins.sh
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Requires s3cmd to be installed and an appropriate ~/.s3cfg.
|
||||
# Usage:
|
||||
# admin/copy-release-from-jenkins.sh [--prod] BUILDNUMBER
|
||||
# where BUILDNUMBER is the small integer Jenkins build number.
|
||||
|
||||
set -e
|
||||
set -u
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
TARGET="s3://com.meteor.static/test/"
|
||||
TEST=no
|
||||
if [ $# -ge 1 -a $1 = '--prod' ]; then
|
||||
shift
|
||||
TARGET="s3://com.meteor.static/"
|
||||
else
|
||||
TEST=yes
|
||||
fi
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "usage: $0 [--prod] jenkins-build-number" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DIRNAME=$(s3cmd ls s3://com.meteor.jenkins/ | perl -nle 'print $1 if m!/(release-.+--'$1'--.+)/!')
|
||||
|
||||
if [ -z "$DIRNAME" ]; then
|
||||
echo "build not found" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo Found build $DIRNAME
|
||||
|
||||
# Check to make sure the proper number of each kind of file is there.
|
||||
s3cmd ls s3://com.meteor.jenkins/$DIRNAME/ | \
|
||||
perl -nle '++$RPM if /\.rpm/; ++$DEB if /\.deb/; ++$TAR if /\.tar\.gz/; ++$DIR if /DIR/; END { exit !($RPM == 2 && $DEB == 2 && $TAR == 3 && $DIR == 1) }'
|
||||
|
||||
echo Copying to $TARGET
|
||||
s3cmd -P cp -r s3://com.meteor.jenkins/$DIRNAME/ $TARGET
|
||||
|
||||
if [ $TEST = 'yes' ]; then
|
||||
echo Uploading modified install-s3.sh and manifest.json
|
||||
|
||||
OUTDIR=$(mktemp -dt meteor-crfj)
|
||||
perl -pe 's!https://d3sqy0vbqsdhku.cloudfront.net!https://s3.amazonaws.com/com.meteor.static/test!g' install-s3.sh >$OUTDIR/install-s3.sh
|
||||
perl -pe 's!https://d3sqy0vbqsdhku.cloudfront.net!https://s3.amazonaws.com/com.meteor.static/test!g' manifest.json >$OUTDIR/manifest.json
|
||||
|
||||
cd $OUTDIR
|
||||
s3cmd -P put install-s3.sh s3://com.meteor.static/test/update/
|
||||
s3cmd -P put manifest.json s3://com.meteor.static/test/update/
|
||||
fi
|
||||
@@ -1,4 +1,4 @@
|
||||
meteor (0.5.2-1) unstable; urgency=low
|
||||
meteor (0.5.3-1) unstable; urgency=low
|
||||
|
||||
* Automated debian build.
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
## example.
|
||||
|
||||
URLBASE="https://d3sqy0vbqsdhku.cloudfront.net"
|
||||
VERSION="0.5.2"
|
||||
VERSION="0.5.3"
|
||||
PKGVERSION="${VERSION}-1"
|
||||
|
||||
UNAME=`uname`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"version": "0.5.2",
|
||||
"deb_version": "0.5.2-1",
|
||||
"rpm_version": "0.5.2-1",
|
||||
"version": "0.5.3",
|
||||
"deb_version": "0.5.3-1",
|
||||
"rpm_version": "0.5.3-1",
|
||||
"urlbase": "https://d3sqy0vbqsdhku.cloudfront.net"
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Summary: Meteor platform and JavaScript application server
|
||||
Vendor: Meteor
|
||||
Name: meteor
|
||||
Version: 0.5.2
|
||||
Version: 0.5.3
|
||||
Release: 1
|
||||
License: MIT
|
||||
Group: Networking/WWW
|
||||
|
||||
@@ -20,6 +20,7 @@ if [ "$EMACS" == t ]; then
|
||||
fi
|
||||
|
||||
"$TOPDIR/dev_bundle/bin/node" "$@"
|
||||
EXITSTATUS=$?
|
||||
|
||||
# Node sets stdin to non-blocking, which causes Emacs shell to die after it
|
||||
# exits. Work around this by setting stdin to blocking again.
|
||||
@@ -27,3 +28,5 @@ if [ "$EMACS" == t ]; then
|
||||
perl -MFcntl=F_GETFL,F_SETFL,O_NONBLOCK -e \
|
||||
'fcntl(STDIN, F_SETFL, ~O_NONBLOCK & fcntl(STDIN, F_GETFL, 0))'
|
||||
fi
|
||||
|
||||
exit $EXITSTATUS
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var spawn = require('child_process').spawn;
|
||||
var child_process = require('child_process');
|
||||
|
||||
var files = require(path.join(__dirname, '..', 'lib', 'files.js'));
|
||||
|
||||
@@ -15,37 +15,34 @@ var _ = require('underscore');
|
||||
*/
|
||||
var find_mongo_pids = function (app_dir, port, callback) {
|
||||
// 'ps ax' should be standard across all MacOS and Linux.
|
||||
var proc = spawn('ps', ['ax']);
|
||||
var data = '';
|
||||
proc.stdout.on('data', function (d) {
|
||||
data += d;
|
||||
});
|
||||
child_process.exec('ps ax',
|
||||
function (error, stdout, stderr) {
|
||||
if (error) {
|
||||
callback({reason: error});
|
||||
} else if (stderr) {
|
||||
callback({reason: 'ps produced stderr ' + stderr});
|
||||
} else {
|
||||
var pids = [];
|
||||
|
||||
proc.on('exit', function (code, signal) {
|
||||
if (code === 0) {
|
||||
var pids = [];
|
||||
_.each(stdout.split('\n'), function (ps_line) {
|
||||
// matches mongos we start.
|
||||
var m = ps_line.match(/^\s*(\d+).+mongod .+--port (\d+) --dbpath (.+)(?:\/|\\)\.meteor(?:\/|\\)local(?:\/|\\)db\s*$/);
|
||||
if (m && m.length === 4) {
|
||||
var found_pid = parseInt(m[1]);
|
||||
var found_port = parseInt(m[2]);
|
||||
var found_path = m[3];
|
||||
|
||||
_.each(data.split('\n'), function (ps_line) {
|
||||
// matches mongos we start.
|
||||
var m = ps_line.match(/^\s*(\d+).+mongod .+--port (\d+) --dbpath (.+)(?:\/|\\)\.meteor(?:\/|\\)local(?:\/|\\)db\s*$/);
|
||||
if (m && m.length === 4) {
|
||||
var found_pid = parseInt(m[1]);
|
||||
var found_port = parseInt(m[2]);
|
||||
var found_path = m[3];
|
||||
|
||||
if ( (!port || port === found_port) &&
|
||||
(!app_dir || app_dir === found_path)) {
|
||||
pids.push({
|
||||
pid: found_pid, port: found_port, app_dir: found_path});
|
||||
if ( (!port || port === found_port) &&
|
||||
(!app_dir || app_dir === found_path)) {
|
||||
pids.push({
|
||||
pid: found_pid, port: found_port, app_dir: found_path});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
callback(null, pids);
|
||||
} else {
|
||||
callback({reason: 'ps exit code ' + code});
|
||||
}
|
||||
});
|
||||
callback(null, pids);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -162,7 +159,7 @@ exports.launch_mongo = function (app_dir, port, launch_callback, on_exit_callbac
|
||||
return;
|
||||
}
|
||||
|
||||
var proc = spawn(mongod_path, [
|
||||
var proc = child_process.spawn(mongod_path, [
|
||||
'--bind_ip', '127.0.0.1',
|
||||
'--smallfiles',
|
||||
'--port', port,
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
exports.CURRENT_VERSION = "0.5.2";
|
||||
// During automated QA of the updater, modify this file to set testingUpdater to
|
||||
// true. This will make it act as if it is at version 0.1.0 and use test URLs
|
||||
// for update checks.
|
||||
var testingUpdater = false;
|
||||
exports.CURRENT_VERSION = testingUpdater ? "0.1.0" : "0.5.3";
|
||||
|
||||
var fs = require("fs");
|
||||
var http = require("http");
|
||||
@@ -8,11 +12,10 @@ var semver = require("semver");
|
||||
|
||||
var files = require(path.join(__dirname, 'files.js'));
|
||||
|
||||
var manifest_options = {
|
||||
/* uncomment for testing
|
||||
var manifest_options = testingUpdater ? {
|
||||
host: 's3.amazonaws.com',
|
||||
path: '/com.meteor.static/test/update/manifest.json'
|
||||
*/
|
||||
} : {
|
||||
host: 'update.meteor.com',
|
||||
path: '/manifest.json'
|
||||
};
|
||||
|
||||
@@ -86,26 +86,6 @@ Fiber(function () {
|
||||
process.exit(1);
|
||||
};
|
||||
|
||||
var getSettings = function (filename) {
|
||||
var str;
|
||||
try {
|
||||
str = fs.readFileSync(filename, "utf8");
|
||||
} catch (e) {
|
||||
throw new Error("Could not find settings file " + filename);
|
||||
}
|
||||
if (str.length > 0x10000) {
|
||||
throw new Error("Settings file must be less than 64 KB long");
|
||||
}
|
||||
// Ensure that the string is parseable in JSON, but there's
|
||||
// no reason to use the object value of it yet.
|
||||
if (str.match(/\S/)) {
|
||||
JSON.parse(str);
|
||||
return str;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
// XXX when the pass unexpected argument or unrecognized flags, print
|
||||
// an error and fail out
|
||||
|
||||
@@ -121,6 +101,10 @@ Fiber(function () {
|
||||
.boolean('production')
|
||||
.describe('production', 'Run in production mode. Minify and bundle CSS and JS files.')
|
||||
.describe('settings', 'Set optional data for Meteor.settings on the server')
|
||||
// With --once, meteor does not re-run the project if it crashes and
|
||||
// does not monitor for file changes. Intentionally undocumented:
|
||||
// intended for automated testing (eg, cli-test.sh), not end-user
|
||||
// use.
|
||||
.boolean('once')
|
||||
.usage(
|
||||
"Usage: meteor run [options]\n" +
|
||||
@@ -143,14 +127,11 @@ Fiber(function () {
|
||||
process.stdout.write(opt.help());
|
||||
process.exit(1);
|
||||
}
|
||||
if (new_argv.settings) {
|
||||
settings = getSettings(new_argv.settings);
|
||||
}
|
||||
|
||||
var app_dir = path.resolve(require_project("run", true)); // app or package
|
||||
|
||||
var bundle_opts = { no_minify: !new_argv.production, symlink_dev_bundle: true };
|
||||
runner.run(app_dir, bundle_opts, new_argv.port, new_argv.once, settings);
|
||||
runner.run(app_dir, bundle_opts, new_argv.port, new_argv.once, new_argv.settings);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -581,7 +562,7 @@ Fiber(function () {
|
||||
} else {
|
||||
var settings = undefined;
|
||||
if (new_argv.settings)
|
||||
settings = getSettings(new_argv.settings);
|
||||
settings = runner.getSettings(new_argv.settings);
|
||||
// accept packages iff we're deploying tests
|
||||
var project_dir = path.resolve(require_project("bundle", new_argv.tests));
|
||||
deploy.deploy_app(new_argv._[1], project_dir, new_argv.debug,
|
||||
|
||||
@@ -2,7 +2,7 @@ try {
|
||||
// XXX can't get this from updater.js because in 0.3.7 and before the
|
||||
// updater didn't have the right NODE_PATH set. At some point we can
|
||||
// remove this and just use updater.CURRENT_VERSION.
|
||||
var VERSION = "0.5.2";
|
||||
var VERSION = "0.5.3";
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
@@ -215,7 +215,7 @@ var log_to_clients = function (msg) {
|
||||
// [nodeOptions]
|
||||
// [runOnce]: boolean; default false; if true doesn't ever try to restart, and
|
||||
// forwards server exit code.
|
||||
// [settings]
|
||||
// [settingsFile]
|
||||
|
||||
var start_server = function (options) {
|
||||
// environment
|
||||
@@ -234,8 +234,12 @@ var start_server = function (options) {
|
||||
env.PORT = options.innerPort;
|
||||
env.MONGO_URL = options.mongoURL;
|
||||
env.ROOT_URL = env.ROOT_URL || ('http://localhost:' + options.outerPort);
|
||||
if (options.settings)
|
||||
env.METEOR_SETTINGS = options.settings;
|
||||
if (options.settingsFile) {
|
||||
// Re-read the settings file each time we call start_server.
|
||||
var settings = exports.getSettings(options.settingsFile);
|
||||
if (settings)
|
||||
env.METEOR_SETTINGS = settings;
|
||||
}
|
||||
|
||||
var nodeOptions = _.clone(options.nodeOptions);
|
||||
nodeOptions.push(path.join(options.bundlePath, 'main.js'));
|
||||
@@ -308,8 +312,11 @@ var kill_server = function (handle) {
|
||||
////////// Watching dependencies //////////
|
||||
|
||||
// deps is the data from dependencies.json in the bundle
|
||||
// app_dir is the root of the app
|
||||
// relativeFiles are any other files to watch, relative to the current
|
||||
// directory (eg, the --settings file)
|
||||
// on_change is only fired once
|
||||
var DependencyWatcher = function (deps, app_dir, on_change) {
|
||||
var DependencyWatcher = function (deps, app_dir, relativeFiles, on_change) {
|
||||
var self = this;
|
||||
|
||||
self.app_dir = app_dir;
|
||||
@@ -342,6 +349,10 @@ var DependencyWatcher = function (deps, app_dir, on_change) {
|
||||
});
|
||||
};
|
||||
|
||||
_.each(relativeFiles, function (file) {
|
||||
self.specific_files[file] = true;
|
||||
});
|
||||
|
||||
// Things that are never interesting.
|
||||
self.exclude_patterns = _.map((deps.exclude || []), function (pattern) {
|
||||
return new RegExp(pattern);
|
||||
@@ -507,12 +518,34 @@ var start_update_checks = function () {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Also used by "meteor deploy" in meteor.js.
|
||||
|
||||
exports.getSettings = function (filename) {
|
||||
var str;
|
||||
try {
|
||||
str = fs.readFileSync(filename, "utf8");
|
||||
} catch (e) {
|
||||
throw new Error("Could not find settings file " + filename);
|
||||
}
|
||||
if (str.length > 0x10000) {
|
||||
throw new Error("Settings file must be less than 64 KB long");
|
||||
}
|
||||
// Ensure that the string is parseable in JSON, but there's
|
||||
// no reason to use the object value of it yet.
|
||||
if (str.match(/\S/)) {
|
||||
JSON.parse(str);
|
||||
return str;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
// XXX leave a pidfile and check if we are already running
|
||||
|
||||
// This function never returns and will call process.exit() if it
|
||||
// can't continue. If you change this, remember to call
|
||||
// watcher.destroy() as appropriate.
|
||||
exports.run = function (app_dir, bundle_opts, port, once, settings) {
|
||||
exports.run = function (app_dir, bundle_opts, port, once, settingsFile) {
|
||||
var outer_port = port || 3000;
|
||||
var inner_port = outer_port + 1;
|
||||
var mongo_port = outer_port + 2;
|
||||
@@ -553,7 +586,13 @@ exports.run = function (app_dir, bundle_opts, port, once, settings) {
|
||||
if (watcher)
|
||||
watcher.destroy();
|
||||
|
||||
watcher = new DependencyWatcher(deps_info, app_dir, function () {
|
||||
var relativeFiles;
|
||||
if (settingsFile) {
|
||||
relativeFiles = [settingsFile];
|
||||
}
|
||||
|
||||
watcher = new DependencyWatcher(deps_info, app_dir, relativeFiles,
|
||||
function () {
|
||||
if (Status.crashing)
|
||||
log_to_clients({'system': "=> Modified -- restarting."});
|
||||
Status.reset();
|
||||
@@ -634,7 +673,7 @@ exports.run = function (app_dir, bundle_opts, port, once, settings) {
|
||||
},
|
||||
nodeOptions: getNodeOptionsFromEnvironment(),
|
||||
runOnce: once,
|
||||
settings: settings
|
||||
settingsFile: settingsFile
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -528,11 +528,9 @@ In this release, Minimongo has some limitations:
|
||||
* `$elemMatch` is not supported in selectors.
|
||||
* `$pull` in modifiers can only accept certain kinds
|
||||
of selectors.
|
||||
* In selectors, dot notation and ordinal indexing may not work correctly.
|
||||
* In selectors, dot notation may not work correctly.
|
||||
* `$` to denote the matched array position is not
|
||||
supported in modifier.
|
||||
* Sort does not support subkeys (you can sort on `a`,
|
||||
but not `a.b`).
|
||||
* `findAndModify`, upsert, aggregate functions, and
|
||||
map/reduce aren't supported.
|
||||
* The supported types are String, Number, Boolean, Array,
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</div>
|
||||
<div id="main">
|
||||
<div id="top"></div>
|
||||
<h1 class="main-headline">Meteor 0.5.2</h1>
|
||||
<h1 class="main-headline">Meteor 0.5.3</h1>
|
||||
{{> introduction }}
|
||||
{{> concepts }}
|
||||
{{> api }}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
METEOR_VERSION = "0.5.2";
|
||||
METEOR_VERSION = "0.5.3";
|
||||
|
||||
Meteor.startup(function () {
|
||||
// XXX this is broken by the new multi-page layout. Also, it was
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</body>
|
||||
|
||||
<template name="radio">
|
||||
<span class="radio"><input id="{{key}}:{{value}}" {{maybeChecked}} type="radio" name="{{key}}" value="{{value}}" />{{! no whitespace}}<label for="{{key}}:{{value}}">{{label}}</label></span>
|
||||
<span class="radio"><input id="{{key}}:{{value}}" {{{maybeChecked}}} type="radio" name="{{key}}" value="{{value}}" />{{! no whitespace}}<label for="{{key}}:{{value}}">{{label}}</label></span>
|
||||
</template>
|
||||
|
||||
<template name="button">
|
||||
|
||||
@@ -4,12 +4,12 @@ Meteor.http = Meteor.http || {};
|
||||
(function() {
|
||||
|
||||
Meteor.http._encodeParams = function(params) {
|
||||
self = this;
|
||||
var buf = [];
|
||||
_.each(params, function(value, key) {
|
||||
if (buf.length)
|
||||
buf.push('&');
|
||||
buf.push(self._encodeString(key), '=', self._encodeString(value));
|
||||
buf.push(Meteor.http._encodeString(key), '=',
|
||||
Meteor.http._encodeString(value));
|
||||
});
|
||||
return buf.join('').replace(/%20/g, '+');
|
||||
};
|
||||
|
||||
@@ -222,7 +222,8 @@ testAsyncMulti("httpcall - methods", [
|
||||
test.equal(result.statusCode, 200);
|
||||
var data = result.data;
|
||||
test.equal(data.body, {greeting: "Hello World!"});
|
||||
test.equal(data.headers['content-type'], 'application/json');
|
||||
// nb: some browsers include a charset here too.
|
||||
test.matches(data.headers['content-type'], /^application\/json\b/);
|
||||
}));
|
||||
|
||||
Meteor.http.call(
|
||||
@@ -235,7 +236,8 @@ testAsyncMulti("httpcall - methods", [
|
||||
test.equal(result.statusCode, 200);
|
||||
var data = result.data;
|
||||
test.equal(data.body, {greeting: "Hello World!"});
|
||||
test.equal(data.headers['content-type'], 'text/stupid');
|
||||
// nb: some browsers include a charset here too.
|
||||
test.matches(data.headers['content-type'], /^text\/stupid\b/);
|
||||
}));
|
||||
}
|
||||
]);
|
||||
|
||||
@@ -798,6 +798,7 @@ Tinytest.add("minimongo - selector_compiler", function (test) {
|
||||
match({"dogs.0.name": "Fido"}, {dogs: [{name: "Fido"}, {name: "Rex"}]});
|
||||
match({"dogs.1.name": "Rex"}, {dogs: [{name: "Fido"}, {name: "Rex"}]});
|
||||
nomatch({"dogs.1.name": "Fido"}, {dogs: [{name: "Fido"}, {name: "Rex"}]});
|
||||
match({"room.1b": "bla"}, {room: {"1b": "bla"}});
|
||||
|
||||
// XXX still needs tests:
|
||||
// - $elemMatch
|
||||
|
||||
@@ -398,7 +398,7 @@ LocalCollection._exprForKeypathPredicate = function (keypath, value, literals) {
|
||||
while (keyparts.length) {
|
||||
var part = keyparts.pop();
|
||||
var thisPartIsNumber = false;
|
||||
if (/^\d+/.test(part)) {
|
||||
if (/^\d+$/.test(part)) {
|
||||
part = +part;
|
||||
thisPartIsNumber = true;
|
||||
}
|
||||
|
||||
@@ -715,10 +715,12 @@ _.extend(LiveResultsSet.prototype, {
|
||||
--self._addHandleTasksScheduledButNotPerformed;
|
||||
|
||||
// Send initial adds.
|
||||
_.each(self._results, function (doc, i) {
|
||||
handle._added(LocalCollection._deepcopy(doc),
|
||||
self._ordered ? i : undefined);
|
||||
});
|
||||
if (handle._added) {
|
||||
_.each(self._results, function (doc, i) {
|
||||
handle._added(LocalCollection._deepcopy(doc),
|
||||
self._ordered ? i : undefined);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -421,16 +421,19 @@ if (Meteor.isServer) {
|
||||
var run = test.runId();
|
||||
var coll = new Meteor.Collection("cursorDedup-"+run);
|
||||
|
||||
var observer = function () {
|
||||
var observer = function (noAdded) {
|
||||
var output = [];
|
||||
var handle = coll.find({foo: 22}).observe({
|
||||
added: function (doc) {
|
||||
output.push({added: doc._id});
|
||||
},
|
||||
var callbacks = {
|
||||
changed: function (newDoc) {
|
||||
output.push({changed: newDoc._id});
|
||||
}
|
||||
});
|
||||
};
|
||||
if (!noAdded) {
|
||||
callbacks.added = function (doc) {
|
||||
output.push({added: doc._id});
|
||||
};
|
||||
}
|
||||
var handle = coll.find({foo: 22}).observe(callbacks);
|
||||
return {output: output, handle: handle};
|
||||
};
|
||||
|
||||
@@ -510,7 +513,13 @@ if (Meteor.isServer) {
|
||||
test.length(o2.output, 0);
|
||||
// White-box: Different LiveResultsSet.
|
||||
test.isTrue(liveResultsSet !== o3.handle._liveResultsSet);
|
||||
|
||||
// Start another handle with no added callback. Regression test for #589.
|
||||
var o4 = observer(true);
|
||||
|
||||
o3.handle.stop();
|
||||
o4.handle.stop();
|
||||
|
||||
onComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -374,10 +374,15 @@ Spark._Patcher._copyAttributes = function(tgt, src) {
|
||||
tgt._sparkOriginalRenderedChecked[0];
|
||||
var srcOriginalChecked = !!src._sparkOriginalRenderedChecked &&
|
||||
src._sparkOriginalRenderedChecked[0];
|
||||
// For radio buttons, we previously saved the checkedness in an expando
|
||||
// property before doing some DOM operations that could wipe it out. For
|
||||
// checkboxes, we can just use the checked property directly.
|
||||
var tgtCurrentChecked = tgt._currentChecked ?
|
||||
tgt._currentChecked[0] : tgt.checked;
|
||||
if (tgtOriginalChecked === srcOriginalChecked) {
|
||||
finalChecked = !!tgt.checked;
|
||||
finalChecked = tgtCurrentChecked;
|
||||
} else {
|
||||
finalChecked = !!srcOriginalChecked;
|
||||
finalChecked = srcOriginalChecked;
|
||||
tgt._sparkOriginalRenderedChecked = [finalChecked];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +132,9 @@ Tinytest.add("spark - patch - copyAttributes", function(test) {
|
||||
buf.push('<', tagName);
|
||||
_.each(kv, function(v,k) {
|
||||
allAttrNames[k] = true;
|
||||
buf.push(' ', k, '="', v, '"');
|
||||
buf.push(' ', k);
|
||||
if (v !== 'NO_VALUE')
|
||||
buf.push('="', v, '"');
|
||||
});
|
||||
buf.push('></', tagName, '>');
|
||||
var nodeHtml = buf.join('');
|
||||
@@ -160,18 +162,20 @@ Tinytest.add("spark - patch - copyAttributes", function(test) {
|
||||
check: function() {
|
||||
_.each(lastAttrs, function(v,k) {
|
||||
var actualAttr;
|
||||
var expectedAttr = v || "";
|
||||
if (k === "style") {
|
||||
actualAttr = node.style.cssText;
|
||||
} else if (k === "class") {
|
||||
actualAttr = node.className;
|
||||
} else if (k === "checked") {
|
||||
actualAttr = String(node.getAttribute(k) || "");
|
||||
if (expectedAttr === "NO_VALUE")
|
||||
expectedAttr = "checked";
|
||||
if (actualAttr === "true")
|
||||
actualAttr = "checked"; // save IE's butt
|
||||
} else {
|
||||
actualAttr = String(node.getAttribute(k) || "");
|
||||
}
|
||||
var expectedAttr = v || "";
|
||||
test.equal(actualAttr, expectedAttr, k);
|
||||
});
|
||||
},
|
||||
@@ -228,6 +232,12 @@ Tinytest.add("spark - patch - copyAttributes", function(test) {
|
||||
c.copy({type:'checkbox', name:'foo', checked:'checked'});
|
||||
c.check();
|
||||
test.equal(c.node().checked, true);
|
||||
c.copy({type:'checkbox', name:'foo'});
|
||||
c.check();
|
||||
test.equal(c.node().checked, false);
|
||||
c.copy({type:'checkbox', name:'foo', checked:'NO_VALUE'});
|
||||
c.check();
|
||||
test.equal(c.node().checked, true);
|
||||
|
||||
c.copy({type:'checkbox', name:'bar'});
|
||||
test.expect_fail(); // changing "name" on a form control won't take in IE
|
||||
|
||||
@@ -318,7 +318,7 @@ _.extend(Spark._Renderer.prototype, {
|
||||
});
|
||||
_.each(DomUtils.findAll(ret, 'input[type=checkbox], input[type=radio]'),
|
||||
function (node) {
|
||||
node._sparkOriginalRenderedChecked = [node.checked];
|
||||
node._sparkOriginalRenderedChecked = [!!node.checked];
|
||||
});
|
||||
|
||||
return ret;
|
||||
@@ -583,6 +583,18 @@ Spark.renderToRange = function (range, htmlFunc) {
|
||||
notes.originalRange = landmarkRange;
|
||||
});
|
||||
|
||||
// Once we render the new fragment, as soon as it is placed into the DOM (even
|
||||
// temporarily), if any radio buttons in the new framgent are checked, any
|
||||
// radio buttons with the same name in the entire document will be unchecked
|
||||
// (since only one radio button of a given name can be checked at a time). So
|
||||
// we save the current checked value of all radio buttons in an expando.
|
||||
var radios = DomUtils.findAllClipped(
|
||||
range.containerNode(), 'input[type=radio]',
|
||||
range.firstNode(), range.lastNode());
|
||||
_.each(radios, function (node) {
|
||||
node._currentChecked = [!!node.checked];
|
||||
});
|
||||
|
||||
var frag = renderer.materialize(htmlFunc);
|
||||
|
||||
DomUtils.wrapFragmentForContainer(frag, range.containerNode());
|
||||
|
||||
@@ -2640,8 +2640,12 @@ testAsyncMulti(
|
||||
|
||||
Tinytest.add("spark - controls - radio", function(test) {
|
||||
var R = ReactiveVar("");
|
||||
var R2 = ReactiveVar("");
|
||||
var change_buf = [];
|
||||
var div = OnscreenDiv(renderWithPreservation(function() {
|
||||
// Re-render when R2 is changed, even though it doesn't affect HTML.
|
||||
R2.get();
|
||||
|
||||
var buf = [];
|
||||
buf.push("Band: ");
|
||||
_.each(["AM", "FM", "XM"], function(band) {
|
||||
@@ -2688,6 +2692,12 @@ Tinytest.add("spark - controls - radio", function(test) {
|
||||
test.equal(_.pluck(btns, 'checked'), [true, false, false]);
|
||||
test.equal(div.text(), "Band: AM");
|
||||
|
||||
R2.set("change");
|
||||
Meteor.flush();
|
||||
test.length(change_buf, 0);
|
||||
test.equal(_.pluck(btns, 'checked'), [true, false, false]);
|
||||
test.equal(div.text(), "Band: AM");
|
||||
|
||||
clickElement(btns[1]);
|
||||
test.equal(change_buf, ['FM']);
|
||||
change_buf.length = 0;
|
||||
|
||||
@@ -137,6 +137,14 @@ _.extend(TestCaseResults.prototype, {
|
||||
this.fail({type: "instanceOf"}); // XXX what other data?
|
||||
},
|
||||
|
||||
matches: function (actual, regexp, message) {
|
||||
if (regexp.test(actual))
|
||||
this.ok();
|
||||
else
|
||||
this.fail({type: "matches", message: message,
|
||||
actual: actual, regexp: regexp.toString()});
|
||||
},
|
||||
|
||||
// XXX nodejs assert.throws can take an expected error, as a class,
|
||||
// regular expression, or predicate function..
|
||||
throws: function (f) {
|
||||
|
||||
Reference in New Issue
Block a user