');
+});
+
+// /files/* is accessed via req.params[0]
+// but here we name it :file
+app.get('/files/:file(*)', function (req, res, next?) {
+ var file = req.params.file
+ , path = __dirname + '/files/' + file;
+
+ res.download(path);
+});
+
+// error handling middleware. Because it's
+// below our routes, you will be able to
+// "intercept" errors, otherwise Connect
+// will respond with 500 "Internal Server Error".
+app.use(function (err, req, res, next) {
+ // special-case 404s,
+ // remember you could
+ // render a 404 template here
+ if (404 == err.status) {
+ res.statusCode = 404;
+ res.send('Cant find that file, sorry!');
+ } else {
+ next(err);
+ }
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express started on port 3000');
+}
+
+///////////////////
+
+// Register ejs as .html. If we did
+// not call this, we would need to
+// name our views foo.ejs instead
+// of foo.html. The __express method
+// is simply a function that engines
+// use to hook into the Express view
+// system by default, so if we want
+// to change "foo.ejs" to "foo.html"
+// we simply pass _any_ function, in this
+// case `ejs.__express`.
+
+app.engine('.html', require('ejs').__express);
+
+// Optional since express defaults to CWD/views
+
+app.set('views', __dirname + '/views');
+
+// Without this you would need to
+// supply the extension to res.render()
+// ex: res.render('users.html').
+app.set('view engine', 'html');
+
+app.get('/', function (req, res) {
+ res.render('users', {
+ users: users,
+ title: "EJS example",
+ header: "Some users"
+ });
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express app started on port 3000');
+}
+
+////////////////////
+
+var test: any;
+
+if (!test) app.use(express.logger('dev'));
+app.use(app.router);
+
+// the error handler is strategically
+// placed *below* the app.router; if it
+// were above it would not receive errors
+// from app.get() etc
+app.use(error);
+
+// error handling middleware have an arity of 4
+// instead of the typical (req, res, next),
+// otherwise they behave exactly like regular
+// middleware, you may have several of them,
+// in different orders etc.
+
+function error(err, req, res, next) {
+ // log it
+ if (!test) console.error(err.stack);
+
+ // respond with 500 "Internal Server Error".
+ res.send(500);
+}
+
+app.get('/', function (req, res) {
+ // Caught and passed down to the errorHandler middleware
+ throw new Error('something broke!');
+});
+
+app.get('/next', function (req, res, next) {
+ // We can also pass exceptions to next()
+ process.nextTick(function () {
+ next(new Error('oh no!'));
+ });
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express started on port 3000');
+}
+
+/////////////////////
+
+var silent: any;
+
+// general config
+app.set('views', __dirname + '/views');
+app.set('view engine', 'jade');
+
+// our custom "verbose errors" setting
+// which we can use in the templates
+// via settings['verbose errors']
+app.enable('verbose errors');
+
+// disable them in production
+// use $ NODE_ENV=production node examples/error-pages
+if ('production' == app.settings.env) {
+ app.disable('verbose errors');
+}
+
+app.use(express.favicon());
+
+silent || app.use(express.logger('dev'));
+
+// "app.router" positions our routes
+// above the middleware defined below,
+// this means that Express will attempt
+// to match & call routes _before_ continuing
+// on, at which point we assume it's a 404 because
+// no route has handled the request.
+
+app.use(app.router);
+
+// Since this is the last non-error-handling
+// middleware use()d, we assume 404, as nothing else
+// responded.
+
+// $ curl http://localhost:3000/notfound
+// $ curl http://localhost:3000/notfound -H "Accept: application/json"
+// $ curl http://localhost:3000/notfound -H "Accept: text/plain"
+
+app.use(function (req, res, next) {
+ res.status(404);
+
+ // respond with html page
+ if (req.accepts('html')) {
+ res.render('404', { url: req.url });
+ return;
+ }
+
+ // respond with json
+ if (req.accepts('json')) {
+ res.send({ error: 'Not found' });
+ return;
+ }
+
+ // default to plain-text. send()
+ res.type('txt').send('Not found');
+});
+
+// error-handling middleware, take the same form
+// as regular middleware, however they require an
+// arity of 4, aka the signature (err, req, res, next).
+// when connect has an error, it will invoke ONLY error-handling
+// middleware.
+
+// If we were to next() here any remaining non-error-handling
+// middleware would then be executed, or if we next(err) to
+// continue passing the error, only error-handling middleware
+// would remain being executed, however here
+// we simply respond with an error page.
+
+app.use(function (err, req, res, next) {
+ // we may use properties of the error object
+ // here and next(err) appropriately, or if
+ // we possibly recovered from the error, simply next().
+ res.status(err.status || 500);
+ res.render('500', { error: err });
+});
+
+// Routes
+
+app.get('/', function (req, res) {
+ res.render('index.jade');
+});
+
+app.get('/404', function (req, res, next) {
+ // trigger a 404 since no other middleware
+ // will match /404 after this one, and we're not
+ // responding here
+ next();
+});
+
+app.get('/403', function (req, res, next) {
+ // trigger a 403 error
+ var err = new Error('not allowed!');
+ err.status = 403;
+ next(err);
+});
+
+app.get('/500', function (req, res, next) {
+ // trigger a generic (500) error
+ next(new Error('keyboard cat!'));
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ //silent || console.log('Express started on port 3000');
+}
+
+///////////////
+
+var fs: any;
+var md: any;
+
+app.set('view engine', 'jade');
+app.set('views', __dirname + '/views');
+
+function User(name) {
+ this.private = 'heyyyy';
+ this.secret = 'something';
+ this.name = name;
+ this.id = 123;
+}
+
+// You'll probably want to do
+// something like this so you
+// dont expose "secret" data.
+
+User.prototype.toJSON = function () {
+ return {
+ id: this.id,
+ name: this.name
+ }
+};
+
+app.use(express.logger('dev'));
+
+// earlier on expose an object
+// that we can tack properties on.
+// all res.locals props are exposed
+// to the templates, so "expose" will
+// be present.
+
+app.use(function (req, res, next) {
+ res.locals.expose = {};
+ // you could alias this as req or res.expose
+ // to make it shorter and less annoying
+ next();
+});
+
+// pretend we loaded a user
+
+app.use(function (req, res, next) {
+ req.user = new User('Tobi');
+ next();
+});
+
+app.get('/', function (req, res) {
+ res.redirect('/user');
+});
+
+app.get('/user', function (req, res) {
+ // we only want to expose the user
+ // to the client for this route:
+ res.locals.expose.user = req.user;
+ res.render('page');
+});
+
+app.listen(3000);
+console.log('app listening on port 3000');
+
+///////////////////////
+
+app.get('/', function (req, res) {
+ res.send('Hello World');
+});
+
+app.listen(3000);
+console.log('Express started on port 3000');
+
+////////////////////
+
+// register .md as an engine in express view system
+
+app.engine('md', function (path, options, fn) {
+ fs.readFile(path, 'utf8', function (err, str) {
+ if (err) return fn(err);
+ try {
+ var html = md(str);
+ html = html.replace(/\{([^}]+)\}/g, function (_, name) {
+ return options[name] || '';
+ })
+ fn(null, html);
+ } catch (err) {
+ fn(err);
+ }
+ });
+})
+
+app.set('views', __dirname + '/views');
+
+// make it the default so we dont need .md
+app.set('view engine', 'md');
+
+app.get('/', function (req, res) {
+ res.render('index', { title: 'Markdown Example' });
+})
+
+app.get('/fail', function (req, res) {
+ res.render('missing', { title: 'Markdown Example' });
+})
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express started on port 3000');
+}
+
+///////////////////////
+
+var mformat: any;
+
+// bodyParser in connect 2.x uses node-formidable to parse
+// the multipart form data.
+app.use(express.bodyParser())
+
+app.get('/', function (req, res) {
+ res.send('');
+});
+
+app.post('/', function (req, res, next) {
+ // the uploaded file can be found as `req.files.image` and the
+ // title field as `req.body.title`
+ res.send(mformat('\nuploaded %s (%d Kb) to %s as %s'
+ , req.files.image.name
+ , req.files.image.size / 1024 | 0
+ , req.files.image.path
+ , req.body.title));
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express started on port 3000');
+}
+
+//////////////////
+
+
+// first:
+// $ npm install redis online
+// $ redis-server
+
+/**
+ * Module dependencies.
+ */
+
+var online: any;
+var redis: any;
+var db: any;
+
+// online
+
+online = online(db);
+
+// activity tracking, in this case using
+// the UA string, you would use req.user.id etc
+
+app.use(function (req, res, next) {
+ // fire-and-forget
+ online.add(req.headers['user-agent']);
+ next();
+});
+
+/**
+ * List helper.
+ */
+
+function list(ids) {
+ return '
' + ids.map(function (id) {
+ return '
' + id + '
';
+ }).join('') + '
';
+}
+
+/**
+ * GET users online.
+ */
+
+app.get('/', function (req, res, next) {
+ online.last(5, function (err, ids) {
+ if (err) return next(err);
+ res.send('
Users online: ' + ids.length + '
' + list(ids));
+ });
+});
+
+app.listen(3000);
+console.log('listening on port 3000');
+
+///////////////////
+
+// Convert :to and :from to integers
+
+app.param(['to', 'from'], function (req, res, next, num, name) {
+ req.params[name] = num = parseInt(num, 10);
+ if (isNaN(num)) {
+ next(new Error('failed to parseInt ' + num));
+ } else {
+ next();
+ }
+});
+
+// Load user by id
+
+app.param('user', function (req, res, next, id) {
+ if (req.user = users[id]) {
+ next();
+ } else {
+ next(new Error('failed to find user'));
+ }
+});
+
+/**
+ * GET index.
+ */
+
+app.get('/', function (req, res) {
+ res.send('Visit /user/0 or /users/0-2');
+});
+
+/**
+ * GET :user.
+ */
+
+app.get('/user/:user', function (req, res, next) {
+ res.send('user ' + req.user.name);
+});
+
+/**
+ * GET users :from - :to.
+ */
+
+app.get('/users/:from-:to', function (req, res, next) {
+ var from = req.params.from
+ , to = req.params.to
+ , names = users.map(function (user) { return user.name; });
+ res.send('users ' + names.slice(from, to).join(', '));
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express started on port 3000');
+}
+
+//////////////////
+
+// Ad-hoc example resource method
+
+app.resource = function (path, obj) {
+ this.get(path, obj.index);
+ this.get(path + '/:a..:b.:format?', function (req, res) {
+ var a = parseInt(req.params.a, 10)
+ , b = parseInt(req.params.b, 10)
+ , format = req.params.format;
+ obj.range(req, res, a, b, format);
+ });
+ this.get(path + '/:id', obj.show);
+ this.del(path + '/:id', obj.destroy);
+};
+
+// Fake controller.
+
+var FUser = {
+ index: function (req, res) {
+ res.send(users);
+ },
+ show: function (req, res) {
+ res.send(users[req.params.id] || { error: 'Cannot find user' });
+ },
+ destroy: function (req, res) {
+ var id = req.params.id;
+ var destroyed = id in users;
+ delete users[id];
+ res.send(destroyed ? 'destroyed' : 'Cannot find user');
+ },
+ range: function (req, res, a, b, format) {
+ var range = users.slice(a, b + 1);
+ switch (format) {
+ case 'json':
+ res.send(range);
+ break;
+ case 'html':
+ default:
+ var html = '
' + range.map(function (user) {
+ return '
' + user.name + '
';
+ }).join('\n') + '
';
+ res.send(html);
+ break;
+ }
+ }
+};
+
+// curl http://localhost:3000/users -- responds with all users
+// curl http://localhost:3000/users/1 -- responds with user 1
+// curl http://localhost:3000/users/4 -- responds with error
+// curl http://localhost:3000/users/1..3 -- responds with several users
+// curl -X DELETE http://localhost:3000/users/1 -- deletes the user
+
+app.resource('/users', FUser);
+
+app.get('/', function (req, res) {
+ res.send([
+ '
Examples:
'
+ , '
GET /users
'
+ , '
GET /users/1
'
+ , '
GET /users/3
'
+ , '
GET /users/1..3
'
+ , '
GET /users/1..3.json
'
+ , '
DELETE /users/4
'
+ , '
'
+ ].join('\n'));
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express started on port 3000');
+}
+
+/////////////////////
+
+
+var verbose: any;
+
+app.map = function (a, route) {
+ route = route || '';
+ for (var key in a) {
+ switch (typeof a[key]) {
+ // { '/path': { ... }}
+ case 'object':
+ app.map(a[key], route + key);
+ break;
+ // get: function(){ ... }
+ case 'function':
+ if (verbose) console.log('%s %s', key, route);
+ app[key](route, a[key]);
+ break;
+ }
+ }
+};
+
+var users2 = {
+ list: function (req, res) {
+ res.send('user list');
+ },
+
+ get: function (req, res) {
+ res.send('user ' + req.params.uid);
+ },
+
+ del: function (req, res) {
+ res.send('delete users');
+ }
+};
+
+var pets2 = {
+ list: function (req, res) {
+ res.send('user ' + req.params.uid + '\'s pets');
+ },
+
+ del: function (req, res) {
+ res.send('delete ' + req.params.uid + '\'s pet ' + req.params.pid);
+ }
+};
+
+app.map({
+ '/users': {
+ get: users2.list,
+ del: users2.del,
+ '/:uid': {
+ get: users.get ,
+ '/pets': {
+ get: pets2.list,
+ '/:pid': {
+ del: pets2.del
+ }
+ }
+ }
+ }
+});
+
+app.listen(3000);
+
+///////////////////////////
+
+// Example requests:
+// curl http://localhost:3000/user/0
+// curl http://localhost:3000/user/0/edit
+// curl http://localhost:3000/user/1
+// curl http://localhost:3000/user/1/edit (unauthorized since this is not you)
+// curl -X DELETE http://localhost:3000/user/0 (unauthorized since you are not an admin)
+
+function loadUser(req, res, next) {
+ // You would fetch your user from the db
+ var user = users[req.params.id];
+ if (user) {
+ req.user = user;
+ next();
+ } else {
+ next(new Error('Failed to load user ' + req.params.id));
+ }
+}
+
+function andRestrictToSelf(req, res, next) {
+ // If our authenticated user is the user we are viewing
+ // then everything is fine :)
+ if (req.authenticatedUser.id == req.user.id) {
+ next();
+ } else {
+ // You may want to implement specific exceptions
+ // such as UnauthorizedError or similar so that you
+ // can handle these can be special-cased in an error handler
+ // (view ./examples/pages for this)
+ next(new Error('Unauthorized'));
+ }
+}
+
+function andRestrictTo(role) {
+ return function (req, res, next) {
+ if (req.authenticatedUser.role == role) {
+ next();
+ } else {
+ next(new Error('Unauthorized'));
+ }
+ }
+}
+
+// Middleware for faux authentication
+// you would of course implement something real,
+// but this illustrates how an authenticated user
+// may interact with middleware
+
+app.use(function (req, res, next) {
+ req.authenticatedUser = users[0];
+ next();
+});
+
+app.get('/', function (req, res) {
+ res.redirect('/user/0');
+});
+
+app.get('/user/:id', loadUser, function (req, res) {
+ res.send('Viewing user ' + req.user.name);
+});
+
+app.get('/user/:id/edit', loadUser, andRestrictToSelf, function (req, res) {
+ res.send('Editing user ' + req.user.name);
+});
+
+app.del('/user/:id', loadUser, andRestrictTo('admin'), function (req, res) {
+ res.send('Deleted user ' + req.user.name);
+});
+
+app.listen(3000);
+console.log('Express app started on port 3000');
+
+/////////////////////////
+
+app.set('view engine', 'jade');
+app.set('views', __dirname);
+
+// populate search
+
+db.sadd('ferret', 'tobi');
+db.sadd('ferret', 'loki');
+db.sadd('ferret', 'jane');
+db.sadd('cat', 'manny');
+db.sadd('cat', 'luna');
+
+/**
+ * GET the search page.
+ */
+
+app.get('/', function (req, res) {
+ res.render('search');
+});
+
+/**
+ * GET search for :query.
+ */
+
+app.get('/search/:query?', function (req, res) {
+ var query = req.params.query;
+ db.smembers(query, function (err, vals) {
+ if (err) return res.send(500);
+ res.send(vals);
+ });
+});
+
+/**
+ * GET client javascript. Here we use sendfile()
+ * because serving __dirname with the static() middleware
+ * would also mean serving our server "index.js" and the "search.jade"
+ * template.
+ */
+
+app.get('/client.js', function (req, res) {
+ res.sendfile(__dirname + '/client.js');
+});
+
+app.listen(3000);
+console.log('app listening on port 3000');
+
+///////////////////
+
+app.use(express.logger('dev'));
+
+// Required by session() middleware
+// pass the secret for signed cookies
+// (required by session())
+app.use(express.cookieParser('keyboard cat'));
+
+// Populates req.session
+app.use(express.session());
+
+app.get('/', function (req, res) {
+ var body = '';
+ if (req.session.views) {
+ ++req.session.views;
+ } else {
+ req.session.views = 1;
+ body += '
First time visiting? view this page in several browsers :)
';
+ }
+ res.send(body + '
viewed ' + req.session.views + ' times.
');
+});
+
+app.listen(3000);
+console.log('Express app started on port 3000');
+
+////////////////////////
+
+// log requests
+app.use(express.logger('dev'));
+
+// express on its own has no notion
+// of a "file". The express.static()
+// middleware checks for a file matching
+// the `req.path` within the directory
+// that you pass it. In this case "GET /js/app.js"
+// will look for "./public/js/app.js".
+
+app.use(express.static(__dirname + '/public'));
+
+// if you wanted to "prefix" you may use
+// the mounting feature of Connect, for example
+// "GET /static/js/app.js" instead of "GET /js/app.js".
+// The mount-path "/static" is simply removed before
+// passing control to the express.static() middleware,
+// thus it serves the file correctly by ignoring "/static"
+app.use('/static', express.static(__dirname + '/public'));
+
+// if for some reason you want to serve files from
+// several directories, you can use express.static()
+// multiple times! Here we're passing "./public/css",
+// this will allow "GET /style.css" instead of "GET /css/style.css":
+app.use(express.static(__dirname + '/public/css'));
+
+// this examples does not have any routes, however
+// you may `app.use(app.router)` before or after these
+// static() middleware. If placed before them your routes
+// will be matched BEFORE file serving takes place. If placed
+// after as shown here then file serving is performed BEFORE
+// any routes are hit:
+app.use(app.router);
+
+app.listen(3000);
+console.log('listening on port 3000');
+console.log('try:');
+console.log(' GET /hello.txt');
+console.log(' GET /js/app.js');
+console.log(' GET /css/style.css');
+
+//////////////////
+
+/*
+edit /etc/vhosts:
+
+127.0.0.1 foo.example.com
+127.0.0.1 bar.example.com
+127.0.0.1 example.com
+*/
+
+// Main app
+
+var main = express();
+
+main.use(express.logger('dev'));
+
+main.get('/', function (req, res) {
+ res.send('Hello from main app!')
+});
+
+main.get('/:sub', function (req, res) {
+ res.send('requsted ' + req.params.sub);
+});
+
+// Redirect app
+
+var redirect = express();
+
+redirect.all('*', function (req, res) {
+ console.log(req.subdomains);
+ res.redirect('http://example.com:3000/' + req.subdomains[0]);
+});
+
+app.use(express.vhost('*.example.com', redirect))
+app.use(express.vhost('example.com', main));
+
+app.listen(3000);
+console.log('Express app started on port 3000');
+
+////////////////////
+
+// create an error with .status. we
+// can then use the property in our
+// custom error handler (Connect repects this prop as well)
+
+function merror(status, msg) {
+ var err = new Error(msg);
+ err.status = status;
+ return err;
+}
+
+// if we wanted to supply more than JSON, we could
+// use something similar to the content-negotiation
+// example.
+
+// here we validate the API key,
+// by mounting this middleware to /api
+// meaning only paths prefixed with "/api"
+// will cause this middleware to be invoked
+
+app.use('/api', function (req, res, next) {
+ var key = req.query['api-key'];
+
+ // key isnt present
+ if (!key) return next(merror(400, 'api key required'));
+
+ // key is invalid
+ if (!~apiKeys.indexOf(key)) return next(merror(401, 'invalid api key'));
+
+ // all good, store req.key for route access
+ req.key = key;
+ next();
+});
+
+// position our routes above the error handling middleware,
+// and below our API middleware, since we want the API validation
+// to take place BEFORE our routes
+app.use(app.router);
+
+// middleware with an arity of 4 are considered
+// error handling middleware. When you next(err)
+// it will be passed through the defined middleware
+// in order, but ONLY those with an arity of 4, ignoring
+// regular middleware.
+app.use(function (err, req, res, next) {
+ // whatever you want here, feel free to populate
+ // properties on `err` to treat it differently in here.
+ res.send(err.status || 500, { error: err.message });
+});
+
+// our custom JSON 404 middleware. Since it's placed last
+// it will be the last middleware called, if all others
+// invoke next() and do not respond.
+app.use(function (req, res) {
+ res.send(404, { error: "Lame, can't find that" });
+});
+
+// map of valid api keys, typically mapped to
+// account info with some sort of database like redis.
+// api keys do _not_ serve as authentication, merely to
+// track API usage or help prevent malicious behavior etc.
+
+var apiKeys = ['foo', 'bar', 'baz'];
+
+// these two objects will serve as our faux database
+
+var repos = [
+ { name: 'express', url: 'http://github.com/visionmedia/express' }
+ , { name: 'stylus', url: 'http://github.com/learnboost/stylus' }
+ , { name: 'cluster', url: 'http://github.com/learnboost/cluster' }
+];
+
+var userRepos = {
+ tobi: [repos[0], repos[1]]
+ , loki: [repos[1]]
+ , jane: [repos[2]]
+};
+
+// we now can assume the api key is valid,
+// and simply expose the data
+
+app.get('/api/users', function (req, res, next) {
+ res.send(users);
+});
+
+app.get('/api/repos', function (req, res, next) {
+ res.send(repos);
+});
+
+app.get('/api/user/:name/repos', function (req, res, next) {
+ var name = req.params.name
+ , user = userRepos[name];
+
+ if (user) res.send(user);
+ else next();
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express server listening on port 3000');
+}
+
+//////
function test_general() {
@@ -97,7 +1337,7 @@ function test_general() {
}
function test_request() {
- var req: Express.ServerRequest;
+ var req: ExpressServerRequest;
req.params.name;
req.params[0];
req.query.q;
@@ -130,7 +1370,7 @@ function test_request() {
}
function test_response() {
- var res: Express.ServerResponse;
+ var res: ExpressServerResponse;
res.status(404).sendfile('path/to/404.png');
res.set('Content-Type', 'text/plain');
res.set({
diff --git a/express/express.d.ts b/express/express.d.ts
index c8fe6bec31..8e19ab0049 100644
--- a/express/express.d.ts
+++ b/express/express.d.ts
@@ -1,218 +1,1954 @@
-// Type definitions for Express 3.0
+// Type definitions for Express 3.1
// Project: http://expressjs.com
// Definitions by: Boris Yankov
-// Definitions: https://github.com/borisyankov/DefinitelyTyped
+// DefinitelyTyped: https://github.com/borisyankov/DefinitelyTyped
-/*
-USAGE
+/* =================== USAGE ===================
-///
-import express = module('express')
-var app = express()
-...
+ import express = module('express');
+ var app = express();
-MIDDLEWARE
+ =============================================== */
-express exports lots of middleware, like .static, .session, etc, but use connect so you don't have to escape
-var connect = require('connect')
-connect.session({})
+///
-*/
+interface Route {
+ path: string;
-///
+ method: string;
-// do not reference this. use module('express') instead
-declare module _express {
+ callbacks: Function[];
- import http = module("http");
+ regexp: any;
- export interface Handler {
- (req: ServerRequest, res: ServerResponse, next?: Function): void;
- }
+ /**
+ * Check if this route matches `path`, if so
+ * populate `.params`.
+ */
+ match(path: string): bool;
+}
+declare var Route: {
+ /**
+ * Initialize `Route` with the given HTTP `method`, `path`,
+ * and an array of `callbacks` and `options`.
+ *
+ * Options:
+ *
+ * - `sensitive` enable case-sensitive routes
+ * - `strict` enable strict matching for trailing slashes
+ *
+ * @param method
+ * @param path
+ * @param callbacks
+ * @param options
+ */
+ new (method: string, path: string, callbacks: Function[], options: any): Route;
+}
- export interface Errback { (err: Error): void; }
+interface Handler {
+ (req: ExpressServerRequest, res: ExpressServerResponse, next?: Function): void;
+}
- export interface CookieOptions {
- maxAge?: number;
- signed?: bool;
- expires?: Date;
- httpOnly?: bool;
- path?: string;
- domain?: string;
- secure?: bool;
- }
+interface CookieOptions {
+ maxAge?: number;
+ signed?: bool;
+ expires?: Date;
+ httpOnly?: bool;
+ path?: string;
+ domain?: string;
+ secure?: bool;
+}
- export interface ExpressSettings {
- env?: string;
- views?: string;
- }
+interface Errback { (err: Error): void; }
- export interface ServerApplication {
- settings: ExpressSettings;
- locals: any;
- routes: any;
+interface ExpressSession {
+ /**
+ * Update reset `.cookie.maxAge` to prevent
+ * the cookie from expiring when the
+ * session is still active.
+ *
+ * @return {Session} for chaining
+ * @api public
+ */
+ touch(): ExpressSession;
- (): ServerApplication;
+ /**
+ * Reset `.maxAge` to `.originalMaxAge`.
+ */
+ resetMaxAge(): ExpressSession;
- router: Handler;
+ /**
+ * Save the session data with optional callback `fn(err)`.
+ */
+ save(fn: Function): ExpressSession;
- use(route: string, callback: Function): ServerApplication;
- use(route: string, server: ServerApplication): ServerApplication;
- use(callback: Function): ServerApplication;
- use(server: ServerApplication): ServerApplication;
+ /**
+ * Re-loads the session data _without_ altering
+ * the maxAge properties. Invokes the callback `fn(err)`,
+ * after which time if no exception has occurred the
+ * `req.session` property will be a new `Session` object,
+ * although representing the same session.
+ */
+ reload(fn: Function): ExpressSession;
- engine(ext: string, callback: Function): ServerApplication;
+ /**
+ * Destroy `this` session.
+ */
+ destroy(fn: Function): ExpressSession;
- param(param: Function): ServerApplication;
- param(name: string, callback: Function): ServerApplication;
- param(name: string, expressParam: any): ServerApplication;
- param(name: any[], callback: Function): ServerApplication;
+ /**
+ * Regenerate this request's session.
+ */
+ regenerate(fn: Function): ExpressSession;
- set(name: string): ServerApplication;
- set(name: string, val: any): ServerApplication;
+ user: any;
- enabled(name: string): bool;
- disabled(name: string): bool;
+ error: string;
- enable(name: string): ServerApplication;
- disable(name: string): ServerApplication;
+ success: string;
- configure(env: string, callback: () => void ): ServerApplication;
- configure(...params: any[]): ServerApplication; // covering this case: (...env: string[], callback: () => void)
- configure(callback: () => void ): ServerApplication;
+ views: any;
+}
+declare var ExpressSession: {
+ /**
+ * Create a new `Session` with the given request and `data`.
+ */
+ new (req: ExpressServerRequest, data: any): ExpressSession;
+}
- all(path: string, ...callbacks: Function[]): void;
+interface ExpressServerRequest {
- render(view: string, callback: (err: Error, html) => void ): void;
- render(view: string, optionss: any, callback: (err: Error, html) => void ): void;
+ session: ExpressSession;
- listen(port: number, hostname: string, backlog: number, callback: Function): void;
- listen(port: number, callback: Function): void;
- listen(path: string, callback?: Function): void;
- listen(handle: any, listeningListener?: Function): void;
+ /**
+ * Return request header.
+ *
+ * The `Referrer` header field is special-cased,
+ * both `Referrer` and `Referer` are interchangeable.
+ *
+ * Examples:
+ *
+ * req.get('Content-Type');
+ * // => "text/plain"
+ *
+ * req.get('content-type');
+ * // => "text/plain"
+ *
+ * req.get('Something');
+ * // => undefined
+ *
+ * Aliased as `req.header()`.
+ *
+ * @param name
+ */
+ get (name: string): string;
- get(name: string): any;
- get(path: RegExp, handler: Handler): void;
- get(path: string, ...callbacks: Handler[]): void;
+ header(name: string): string;
- post(path: RegExp, handler: Handler ): void;
- post(path: string, ...callbacks: Handler[]): void;
+ /**
+ * Check if the given `type(s)` is acceptable, returning
+ * the best match when true, otherwise `undefined`, in which
+ * case you should respond with 406 "Not Acceptable".
+ *
+ * The `type` value may be a single mime type string
+ * such as "application/json", the extension name
+ * such as "json", a comma-delimted list such as "json, html, text/plain",
+ * or an array `["json", "html", "text/plain"]`. When a list
+ * or array is given the _best_ match, if any is returned.
+ *
+ * Examples:
+ *
+ * // Accept: text/html
+ * req.accepts('html');
+ * // => "html"
+ *
+ * // Accept: text/*, application/json
+ * req.accepts('html');
+ * // => "html"
+ * req.accepts('text/html');
+ * // => "text/html"
+ * req.accepts('json, text');
+ * // => "json"
+ * req.accepts('application/json');
+ * // => "application/json"
+ *
+ * // Accept: text/*, application/json
+ * req.accepts('image/png');
+ * req.accepts('png');
+ * // => undefined
+ *
+ * // Accept: text/*;q=.5, application/json
+ * req.accepts(['html', 'json']);
+ * req.accepts('html, json');
+ * // => "json"
+ */
+ accepts(type: string): string;
- put(path: RegExp, handler: Handler ): void;
- put(path: string, ...callbacks: Handler[]): void;
+ accepts(type: string[]): string;
- del(path: RegExp, handler: Handler ): void;
- del(path: string, ...callbacks: Handler[]): void;
- }
+ /**
+ * Check if the given `charset` is acceptable,
+ * otherwise you should respond with 406 "Not Acceptable".
+ *
+ * @param charset
+ */
+ acceptsCharset(charset: string): bool;
- export interface ServerRequest extends http.ServerRequest {
+ /**
+ * Check if the given `lang` is acceptable,
+ * otherwise you should respond with 406 "Not Acceptable".
+ *
+ * @param lang
+ */
+ acceptsLanguage(lang: string): bool;
- accepted: any[];
- acceptedLanguages: string[];
- acceptedCharsets: string[];
+ /**
+ * Parse Range header field,
+ * capping to the given `size`.
+ *
+ * Unspecified ranges such as "0-" require
+ * knowledge of your resource length. In
+ * the case of a byte range this is of course
+ * the total number of bytes. If the Range
+ * header field is not given `null` is returned,
+ * `-1` when unsatisfiable, `-2` when syntactically invalid.
+ *
+ * NOTE: remember that ranges are inclusive, so
+ * for example "Range: users=0-3" should respond
+ * with 4 users when available, not 3.
+ *
+ * @param size
+ */
+ range(size: number): Array;
- params: any;
- query: any;
- body: any;
- files: any;
+ /**
+ * Return an array of Accepted media types
+ * ordered from highest quality to lowest.
+ *
+ * Examples:
+ *
+ * [ { value: 'application/json',
+ * quality: 1,
+ * type: 'application',
+ * subtype: 'json' },
+ * { value: 'text/html',
+ * quality: 0.5,
+ * type: 'text',
+ * subtype: 'html' } ]
+ */
+ accepted: Array;
- route: any;
- cookies: any;
- signedCookies: any;
+ /**
+ * Return an array of Accepted languages
+ * ordered from highest quality to lowest.
+ *
+ * Examples:
+ *
+ * Accept-Language: en;q=.5, en-us
+ * ['en-us', 'en']
+ */
+ acceptedLanguages: Array;
- get(field: string): string;
- header(field: string): string;
+ /**
+ * Return an array of Accepted charsets
+ * ordered from highest quality to lowest.
+ *
+ * Examples:
+ *
+ * Accept-Charset: iso-8859-5;q=.2, unicode-1-1;q=0.8
+ * ['unicode-1-1', 'iso-8859-5']
+ */
+ acceptedCharsets: Array;
- accepts(types: string): any;
- accepts(types: string[]): any;
- acceptsCharset(charset: string): bool;
- acceptsLanguage(lang: string): bool;
+ /**
+ * Return the value of param `name` when present or `defaultValue`.
+ *
+ * - Checks route placeholders, ex: _/user/:id_
+ * - Checks body params, ex: id=12, {"id":12}
+ * - Checks query string params, ex: ?id=12
+ *
+ * To utilize request bodies, `req.body`
+ * should be an object. This can be done by using
+ * the `connect.bodyParser()` middleware.
+ *
+ * @param name
+ * @param defaultValue
+ */
+ param(name: string, defaultValue?: any): string;
- range(size: number): number[];
+ /**
+ * Check if the incoming request contains the "Content-Type"
+ * header field, and it contains the give mime `type`.
+ *
+ * Examples:
+ *
+ * // With Content-Type: text/html; charset=utf-8
+ * req.is('html');
+ * req.is('text/html');
+ * req.is('text/*');
+ * // => true
+ *
+ * // When Content-Type is application/json
+ * req.is('json');
+ * req.is('application/json');
+ * req.is('application/*');
+ * // => true
+ *
+ * req.is('html');
+ * // => false
+ *
+ * @param type
+ */
+ is(type: string): bool;
- param(name: string, defaultValue?: any): string;
- is(type: string): bool;
+ /**
+ * Return the protocol string "http" or "https"
+ * when requested with TLS. When the "trust proxy"
+ * setting is enabled the "X-Forwarded-Proto" header
+ * field will be trusted. If you're running behind
+ * a reverse proxy that supplies https for you this
+ * may be enabled.
+ */
+ protocol: string;
- protocol: string;
- secure: bool;
- ip: string;
- ips: string[];
- auth: any;
- subdomains: string[];
- path: string;
- host: string;
- fresh: bool;
- stale: bool;
- xhr: bool;
- }
+ /**
+ * Short-hand for:
+ *
+ * req.protocol == 'https'
+ */
+ secure: bool;
- export interface ServerResponse extends http.ServerResponse {
+ /**
+ * Return the remote address, or when
+ * "trust proxy" is `true` return
+ * the upstream addr.
+ */
+ ip: string;
- charset: string;
- locals: any;
+ /**
+ * When "trust proxy" is `true`, parse
+ * the "X-Forwarded-For" ip address list.
+ *
+ * For example if the value were "client, proxy1, proxy2"
+ * you would receive the array `["client", "proxy1", "proxy2"]`
+ * where "proxy2" is the furthest down-stream.
+ */
+ ips: string[];
- status(code: number): ServerResponse;
- links(links: any): ServerResponse;
+ /**
+ * Return basic auth credentials.
+ *
+ * Examples:
+ *
+ * // http://tobi:hello@example.com
+ * req.auth
+ * // => { username: 'tobi', password: 'hello' }
+ */
+ auth: any;
- send(status: number): ServerResponse;
- send(bodyOrStatus: any): ServerResponse;
- send(status: number, body: any): ServerResponse;
- json(status: number): ServerResponse;
- json(bodyOrStatus: any): ServerResponse;
- json(status: number, body: any): ServerResponse;
- jsonp(status: number): ServerResponse;
- jsonp(bodyOrStatus: any): ServerResponse;
- jsonp(status: number, body: any): ServerResponse;
+ /**
+ * Return subdomains as an array.
+ *
+ * Subdomains are the dot-separated parts of the host before the main domain of
+ * the app. By default, the domain of the app is assumed to be the last two
+ * parts of the host. This can be changed by setting "subdomain offset".
+ *
+ * For example, if the domain is "tobi.ferrets.example.com":
+ * If "subdomain offset" is not set, req.subdomains is `["ferrets", "tobi"]`.
+ * If "subdomain offset" is 3, req.subdomains is `["tobi"]`.
+ */
+ subdomains: string[];
- sendfile(path: string): void;
- sendfile(path: string, options: any): void;
- sendfile(path: string, fn: Errback): void;
- sendfile(path: string, options: any, fn: Errback): void;
- download(path: string): void;
- download(path: string, filename: string): void;
- download(path: string, fn: Errback): void;
- download(path: string, filename: string, fn: Errback): void;
+ /**
+ * Short-hand for `url.parse(req.url).pathname`.
+ */
+ path: string;
- type(type: string): ServerResponse;
- contentType(type: string): ServerResponse;
+ /**
+ * Parse the "Host" header field hostname.
+ */
+ host: string;
- format(object: any): ServerResponse;
- attachment(filename?: string): ServerResponse;
+ /**
+ * Check if the request is fresh, aka
+ * Last-Modified and/or the ETag
+ * still match.
+ */
+ fresh: bool;
- set(field: any): void;
- set(field: string, value: string): void;
- header(field: any): void;
- header(field: string, value: string): void;
+ /**
+ * Check if the request is stale, aka
+ * "Last-Modified" and / or the "ETag" for the
+ * resource has changed.
+ */
+ stale: bool;
- get(field: string): string;
+ /**
+ * Check if the request was an _XMLHttpRequest_.
+ */
+ xhr: bool;
- clearCookie(name: string, options?: any): ServerResponse;
- cookie(name: string, value: any, options?: CookieOptions): ServerResponse;
+ //body: { username: string; password: string; remember: bool; title: string; };
+ body: any;
- redirect(url: string): void;
- redirect(status: number, url: string): void;
- redirect(url: string, status: number): void;
+ //cookies: { string; remember: bool; };
+ cookies: any;
- render(view: string, options: any): void;
- render(view: string, callback: (err: Error, html: any) => void ): void;
- render(view: string, options: any, callback: (err: Error, html: any) => void ): void;
- }
+ method: string;
+
+ params: any;
+
+ user: any;
+
+ files: any;
+
+ /**
+ * Clear cookie `name`.
+ *
+ * @param name
+ * @param options
+ */
+ clearCookie(name: string, options?: any): ExpressServerResponse;
+
+ query: any;
+
+ route: any;
+
+ signedCookies: any;
+
+ originalUrl: string;
+}
+
+interface ExpressServerResponse {
+ /**
+ * Set status `code`.
+ *
+ * @param code
+ */
+ status(code: number): ExpressServerResponse;
+
+ /**
+ * Set Link header field with the given `links`.
+ *
+ * Examples:
+ *
+ * res.links({
+ * next: 'http://api.example.com/users?page=2',
+ * last: 'http://api.example.com/users?page=5'
+ * });
+ *
+ * @param links
+ */
+ links(links: any): ExpressServerResponse;
+
+ /**
+ * Send a response.
+ *
+ * Examples:
+ *
+ * res.send(new Buffer('wahoo'));
+ * res.send({ some: 'json' });
+ * res.send('
some html
');
+ * res.send(404, 'Sorry, cant find that');
+ * res.send(404);
+ */
+ send(status: number): ExpressServerResponse;
+
+ send(bodyOrStatus: any): ExpressServerResponse;
+
+ send(status: number, body: any): ExpressServerResponse;
+
+
+ /**
+ * Send JSON response.
+ *
+ * Examples:
+ *
+ * res.json(null);
+ * res.json({ user: 'tj' });
+ * res.json(500, 'oh noes!');
+ * res.json(404, 'I dont have that');
+ */
+ json(status: number): ExpressServerResponse;
+
+ json(bodyOrStatus: any): ExpressServerResponse;
+
+ json(status: number, body: any): ExpressServerResponse;
+
+ /**
+ * Send JSON response with JSONP callback support.
+ *
+ * Examples:
+ *
+ * res.jsonp(null);
+ * res.jsonp({ user: 'tj' });
+ * res.jsonp(500, 'oh noes!');
+ * res.jsonp(404, 'I dont have that');
+ */
+ jsonp(status: number): ExpressServerResponse;
+
+ jsonp(bodyOrStatus: any): ExpressServerResponse;
+
+ jsonp(status: number, body: any): ExpressServerResponse;
+
+ /**
+ * Transfer the file at the given `path`.
+ *
+ * Automatically sets the _Content-Type_ response header field.
+ * The callback `fn(err)` is invoked when the transfer is complete
+ * or when an error occurs. Be sure to check `res.sentHeader`
+ * if you wish to attempt responding, as the header and some data
+ * may have already been transferred.
+ *
+ * Options:
+ *
+ * - `maxAge` defaulting to 0
+ * - `root` root directory for relative filenames
+ *
+ * Examples:
+ *
+ * The following example illustrates how `res.sendfile()` may
+ * be used as an alternative for the `static()` middleware for
+ * dynamic situations. The code backing `res.sendfile()` is actually
+ * the same code, so HTTP cache support etc is identical.
+ *
+ * app.get('/user/:uid/photos/:file', function(req, res){
+ * var uid = req.params.uid
+ * , file = req.params.file;
+ *
+ * req.user.mayViewFilesFrom(uid, function(yes){
+ * if (yes) {
+ * res.sendfile('/uploads/' + uid + '/' + file);
+ * } else {
+ * res.send(403, 'Sorry! you cant see that.');
+ * }
+ * });
+ * });
+ */
+ sendfile(path: string): void;
+
+ sendfile(path: string, options: any): void;
+
+ sendfile(path: string, fn: Errback): void;
+
+ sendfile(path: string, options: any, fn: Errback): void;
+
+ /**
+ * Transfer the file at the given `path` as an attachment.
+ *
+ * Optionally providing an alternate attachment `filename`,
+ * and optional callback `fn(err)`. The callback is invoked
+ * when the data transfer is complete, or when an error has
+ * ocurred. Be sure to check `res.headerSent` if you plan to respond.
+ *
+ * This method uses `res.sendfile()`.
+ */
+ download(path: string): void;
+
+ download(path: string, filename: string): void;
+
+ download(path: string, fn: Errback): void;
+
+ download(path: string, filename: string, fn: Errback): void;
+
+ /**
+ * Set _Content-Type_ response header with `type` through `mime.lookup()`
+ * when it does not contain "/", or set the Content-Type to `type` otherwise.
+ *
+ * Examples:
+ *
+ * res.type('.html');
+ * res.type('html');
+ * res.type('json');
+ * res.type('application/json');
+ * res.type('png');
+ *
+ * @param type
+ */
+ contentType(type: string): ExpressServerResponse;
+
+ /**
+ * Set _Content-Type_ response header with `type` through `mime.lookup()`
+ * when it does not contain "/", or set the Content-Type to `type` otherwise.
+ *
+ * Examples:
+ *
+ * res.type('.html');
+ * res.type('html');
+ * res.type('json');
+ * res.type('application/json');
+ * res.type('png');
+ *
+ * @param type
+ */
+ type(type: string): ExpressServerResponse;
+
+ /**
+ * Respond to the Acceptable formats using an `obj`
+ * of mime-type callbacks.
+ *
+ * This method uses `req.accepted`, an array of
+ * acceptable types ordered by their quality values.
+ * When "Accept" is not present the _first_ callback
+ * is invoked, otherwise the first match is used. When
+ * no match is performed the server responds with
+ * 406 "Not Acceptable".
+ *
+ * Content-Type is set for you, however if you choose
+ * you may alter this within the callback using `res.type()`
+ * or `res.set('Content-Type', ...)`.
+ *
+ * res.format({
+ * 'text/plain': function(){
+ * res.send('hey');
+ * },
+ *
+ * 'text/html': function(){
+ * res.send('
hey
');
+ * },
+ *
+ * 'appliation/json': function(){
+ * res.send({ message: 'hey' });
+ * }
+ * });
+ *
+ * In addition to canonicalized MIME types you may
+ * also use extnames mapped to these types:
+ *
+ * res.format({
+ * text: function(){
+ * res.send('hey');
+ * },
+ *
+ * html: function(){
+ * res.send('
hey
');
+ * },
+ *
+ * json: function(){
+ * res.send({ message: 'hey' });
+ * }
+ * });
+ *
+ * By default Express passes an `Error`
+ * with a `.status` of 406 to `next(err)`
+ * if a match is not made. If you provide
+ * a `.default` callback it will be invoked
+ * instead.
+ *
+ * @param obj
+ */
+ format(obj: any): ExpressServerResponse;
+
+ /**
+ * Set _Content-Disposition_ header to _attachment_ with optional `filename`.
+ *
+ * @param filename
+ */
+ attachment(filename?: string): ExpressServerResponse;
+
+ /**
+ * Set header `field` to `val`, or pass
+ * an object of header fields.
+ *
+ * Examples:
+ *
+ * res.set('Foo', ['bar', 'baz']);
+ * res.set('Accept', 'application/json');
+ * res.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' });
+ *
+ * Aliased as `res.header()`.
+ */
+ set (field: any): void;
+
+ set (field: string, value?: string): void;
+
+ header(field: any): void;
+
+ header(field: string, value?: string): void;
+
+ /**
+ * Get value for header `field`.
+ *
+ * @param field
+ */
+ get (field: string): string;
+
+ /**
+ * Clear cookie `name`.
+ *
+ * @param name
+ * @param options
+ */
+ clearCookie(name: string, options?: any): ExpressServerResponse;
+
+ /**
+ * Set cookie `name` to `val`, with the given `options`.
+ *
+ * Options:
+ *
+ * - `maxAge` max-age in milliseconds, converted to `expires`
+ * - `signed` sign the cookie
+ * - `path` defaults to "/"
+ *
+ * Examples:
+ *
+ * // "Remember Me" for 15 minutes
+ * res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });
+ *
+ * // save as above
+ * res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })
+ */
+ cookie(name: string, val: string, options: CookieOptions);
+
+ cookie(name: string, val: any, options: CookieOptions);
+
+ cookie(name: string, val: any);
+
+ /**
+ * Set the location header to `url`.
+ *
+ * The given `url` can also be the name of a mapped url, for
+ * example by default express supports "back" which redirects
+ * to the _Referrer_ or _Referer_ headers or "/".
+ *
+ * Examples:
+ *
+ * res.location('/foo/bar').;
+ * res.location('http://example.com');
+ * res.location('../login'); // /blog/post/1 -> /blog/login
+ *
+ * Mounting:
+ *
+ * When an application is mounted and `res.location()`
+ * is given a path that does _not_ lead with "/" it becomes
+ * relative to the mount-point. For example if the application
+ * is mounted at "/blog", the following would become "/blog/login".
+ *
+ * res.location('login');
+ *
+ * While the leading slash would result in a location of "/login":
+ *
+ * res.location('/login');
+ *
+ * @param url
+ */
+ location(url: string);
+
+ /**
+ * Redirect to the given `url` with optional response `status`
+ * defaulting to 302.
+ *
+ * The resulting `url` is determined by `res.location()`, so
+ * it will play nicely with mounted apps, relative paths,
+ * `"back"` etc.
+ *
+ * Examples:
+ *
+ * res.redirect('/foo/bar');
+ * res.redirect('http://example.com');
+ * res.redirect(301, 'http://example.com');
+ * res.redirect('http://example.com', 301);
+ * res.redirect('../login'); // /blog/post/1 -> /blog/login
+ */
+ redirect(url: string): void;
+
+ redirect(status: number, url: string): void;
+
+ redirect(url: string, status: number): void;
+
+ /**
+ * Render `view` with the given `options` and optional callback `fn`.
+ * When a callback function is given a response will _not_ be made
+ * automatically, otherwise a response of _200_ and _text/html_ is given.
+ *
+ * Options:
+ *
+ * - `cache` boolean hinting to the engine it should cache
+ * - `filename` filename of the view being rendered
+ */
+ render(view: string): void;
+
+ render(view: string, options: any): void;
+
+ render(view: string, callback: (err: Error, html: any) => void ): void;
+
+ render(view: string, options: any, callback: (err: Error, html: any) => void ): void;
+
+ locals: any;
+
+ charset: string;
+}
+
+interface ExpressApplication {
+ /**
+ * Initialize the server.
+ *
+ * - setup default configuration
+ * - setup default middleware
+ * - setup route reflection methods
+ */
+ init();
+
+ /**
+ * Initialize application configuration.
+ */
+ defaultConfiguration();
+
+ /**
+ * Proxy `connect#use()` to apply settings to
+ * mounted applications.
+ **/
+ use(route: string, callback?: Function): ExpressApplication;
+
+ use(route: string, server: ExpressApplication): ExpressApplication;
+
+ use(callback: Function): ExpressApplication;
+
+ use(server: ExpressApplication): ExpressApplication;
+
+ /**
+ * Register the given template engine callback `fn`
+ * as `ext`.
+ *
+ * By default will `require()` the engine based on the
+ * file extension. For example if you try to render
+ * a "foo.jade" file Express will invoke the following internally:
+ *
+ * app.engine('jade', require('jade').__express);
+ *
+ * For engines that do not provide `.__express` out of the box,
+ * or if you wish to "map" a different extension to the template engine
+ * you may use this method. For example mapping the EJS template engine to
+ * ".html" files:
+ *
+ * app.engine('html', require('ejs').renderFile);
+ *
+ * In this case EJS provides a `.renderFile()` method with
+ * the same signature that Express expects: `(path, options, callback)`,
+ * though note that it aliases this method as `ejs.__express` internally
+ * so if you're using ".ejs" extensions you dont need to do anything.
+ *
+ * Some template engines do not follow this convention, the
+ * [Consolidate.js](https://github.com/visionmedia/consolidate.js)
+ * library was created to map all of node's popular template
+ * engines to follow this convention, thus allowing them to
+ * work seamlessly within Express.
+ */
+ engine(ext: string, fn: Function): ExpressApplication;
+
+ /**
+ * Map the given param placeholder `name`(s) to the given callback(s).
+ *
+ * Parameter mapping is used to provide pre-conditions to routes
+ * which use normalized placeholders. For example a _:user_id_ parameter
+ * could automatically load a user's information from the database without
+ * any additional code,
+ *
+ * The callback uses the samesignature as middleware, the only differencing
+ * being that the value of the placeholder is passed, in this case the _id_
+ * of the user. Once the `next()` function is invoked, just like middleware
+ * it will continue on to execute the route, or subsequent parameter functions.
+ *
+ * app.param('user_id', function(req, res, next, id){
+ * User.find(id, function(err, user){
+ * if (err) {
+ * next(err);
+ * } else if (user) {
+ * req.user = user;
+ * next();
+ * } else {
+ * next(new Error('failed to load user'));
+ * }
+ * });
+ * });
+ *
+ * @param name
+ * @param fn
+ */
+ param(name: string, fn: Function): ExpressApplication;
+
+ param(name: Array, fn: Function): ExpressApplication;
+
+ /**
+ * Assign `setting` to `val`, or return `setting`'s value.
+ *
+ * app.set('foo', 'bar');
+ * app.get('foo');
+ * // => "bar"
+ *
+ * Mounted servers inherit their parent server's settings.
+ *
+ * @param setting
+ * @param val
+ */
+ set (setting: string, val: string): ExpressApplication;
+
+ /**
+ * Return the app's absolute pathname
+ * based on the parent(s) that have
+ * mounted it.
+ *
+ * For example if the application was
+ * mounted as "/admin", which itself
+ * was mounted as "/blog" then the
+ * return value would be "/blog/admin".
+ */
+ path(): string;
+
+ /**
+ * Check if `setting` is enabled (truthy).
+ *
+ * app.enabled('foo')
+ * // => false
+ *
+ * app.enable('foo')
+ * app.enabled('foo')
+ * // => true
+ */
+ enabled(setting: string): bool;
+
+ /**
+ * Check if `setting` is disabled.
+ *
+ * app.disabled('foo')
+ * // => true
+ *
+ * app.enable('foo')
+ * app.disabled('foo')
+ * // => false
+ *
+ * @param setting
+ */
+ disabled(setting: string): bool;
+
+ /**
+ * Enable `setting`.
+ *
+ * @param setting
+ */
+ enable(setting: string): ExpressApplication;
+
+ /**
+ * Disable `setting`.
+ *
+ * @param setting
+ */
+ disable(setting: string): ExpressApplication;
+
+ /**
+ * Configure callback for zero or more envs,
+ * when no `env` is specified that callback will
+ * be invoked for all environments. Any combination
+ * can be used multiple times, in any order desired.
+ *
+ * Examples:
+ *
+ * app.configure(function(){
+ * // executed for all envs
+ * });
+ *
+ * app.configure('stage', function(){
+ * // executed staging env
+ * });
+ *
+ * app.configure('stage', 'production', function(){
+ * // executed for stage and production
+ * });
+ *
+ * Note:
+ *
+ * These callbacks are invoked immediately, and
+ * are effectively sugar for the following:
+ *
+ * var env = process.env.NODE_ENV || 'development';
+ *
+ * switch (env) {
+ * case 'development':
+ * ...
+ * break;
+ * case 'stage':
+ * ...
+ * break;
+ * case 'production':
+ * ...
+ * break;
+ * }
+ *
+ * @param env
+ * @param fn
+ */
+ configure(env: string, fn: Function): ExpressApplication;
+
+ configure(env0: string, env1: string, fn: Function): ExpressApplication;
+
+ configure(env0: string, env1: string, env2: string, fn: Function): ExpressApplication;
+
+ configure(env0: string, env1: string, env2: string, env3: string, fn: Function): ExpressApplication;
+
+ configure(env0: string, env1: string, env2: string, env3: string, env4: string, fn: Function): ExpressApplication;
+
+ configure(fn: Function): ExpressApplication;
+
+ /**
+ * Special-cased "all" method, applying the given route `path`,
+ * middleware, and callback to _every_ HTTP method.
+ *
+ * @param path
+ * @param fn
+ */
+ all(path: string, fn?: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): ExpressApplication;
+
+ all(path: string, ...callbacks: Function[]): void;
+
+ /**
+ * Render the given view `name` name with `options`
+ * and a callback accepting an error and the
+ * rendered template string.
+ *
+ * Example:
+ *
+ * app.render('email', { name: 'Tobi' }, function(err, html){
+ * // ...
+ * })
+ *
+ * @param name
+ * @param options or fn
+ * @param fn
+ */
+ render(name: string, options: string, fn: Function);
+
+ render(name: string, fn: Function);
+
+ get (name: string): any;
+
+ get (name: string, handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ ...handlers: any[]): any;
+
+ get (name: RegExp): any;
+
+ get (name: RegExp, handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ ...handlers: any[]): any;
+
+ post(name: string): any;
+
+ post(name: string, handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ post(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ post(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ post(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ post(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ ...handlers: any[]): any;
+
+ post(name: RegExp): any;
+
+ post(name: RegExp, handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ post(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ post(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ post(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ post(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ ...handlers: any[]): any;
+
+ put(name: string): any;
+
+ put(name: string, handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ put(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ put(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ put(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ put(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ ...handlers: any[]): any;
+
+ put(name: RegExp): any;
+
+ put(name: RegExp, handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ put(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ put(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ put(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ put(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ ...handlers: any[]): any;
+
+ del(name: string): any;
+
+ del(name: string, handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ del(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ del(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ del(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ del(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ ...handlers: any[]): any;
+
+ del(name: RegExp): any;
+
+ del(name: RegExp, handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ del(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ del(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ del(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ del(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ ...handlers: any[]): any;
+
+ /**
+ * Listen for connections.
+ *
+ * A node `http.Server` is returned, with this
+ * application (which is a `Function`) as its
+ * callback. If you wish to create both an HTTP
+ * and HTTPS server you may do so with the "http"
+ * and "https" modules as shown here:
+ *
+ * var http = require('http')
+ * , https = require('https')
+ * , express = require('express')
+ * , app = express();
+ *
+ * http.createServer(app).listen(80);
+ * https.createServer({ ... }, app).listen(443);
+ */
+ listen(port: number, hostname: string, backlog: number, callback: Function): void;
+
+ listen(port: number, callback: Function): void;
+
+ listen(path: string, callback?: Function): void;
+
+ listen(handle: any, listeningListener?: Function): void;
+
+ render(view: string, callback: (err: Error, html) => void ): void;
+
+ render(view: string, optionss: any, callback: (err: Error, html) => void ): void;
+
+ route: Route;
+
+ router: string;
+
+ settings: any;
+
+ resource: any;
+
+ map: any;
+
+ locals: any;
+}
+
+interface Express extends ExpressApplication {
+ /**
+ * Framework version.
+ */
+ version: string;
+
+ /**
+ * Expose mime.
+ */
+ mime: string;
+
+ (): ExpressApplication;
+
+ /**
+ * Create an express application.
+ */
+ createApplication(): ExpressApplication;
+
+ createServer(): ExpressApplication;
+
+ application: any;
+
+ request: ExpressServerRequest;
+
+ response: ExpressServerResponse;
}
declare module "express" {
- export function (): _express.ServerApplication;
- export function createServer(): ServerApplication;
- export function static(path: string): any;
- export var listen;
+ export function (): Express;
- // Connect middleware
+ /**
+ * Body parser:
+ *
+ * Parse request bodies, supports _application/json_,
+ * _application/x-www-form-urlencoded_, and _multipart/form-data_.
+ *
+ * This is equivalent to:
+ *
+ * app.use(connect.json());
+ * app.use(connect.urlencoded());
+ * app.use(connect.multipart());
+ *
+ * Examples:
+ *
+ * connect()
+ * .use(connect.bodyParser())
+ * .use(function(req, res) {
+ * res.end('viewing user ' + req.body.user.name);
+ * });
+ *
+ * $ curl -d 'user[name]=tj' http://local/
+ * $ curl -d '{"user":{"name":"tj"}}' -H "Content-Type: application/json" http://local/
+ *
+ * View [json](json.html), [urlencoded](urlencoded.html), and [multipart](multipart.html) for more info.
+ *
+ * @param options
+ */
export function bodyParser(options?: any): Handler;
- export function errorHandler(opts?: any): Handler;
- export function methodOverride(): Handler;
- export interface ServerApplication extends _express.ServerApplication {}
- export interface ServerRequest extends _express.ServerRequest {}
- export interface ServerResponse extends _express.ServerResponse {}
- export interface Handler extends _express.Handler {}
-}
+ /**
+ * Error handler:
+ *
+ * Development error handler, providing stack traces
+ * and error message responses for requests accepting text, html,
+ * or json.
+ *
+ * Text:
+ *
+ * By default, and when _text/plain_ is accepted a simple stack trace
+ * or error message will be returned.
+ *
+ * JSON:
+ *
+ * When _application/json_ is accepted, connect will respond with
+ * an object in the form of `{ "error": error }`.
+ *
+ * HTML:
+ *
+ * When accepted connect will output a nice html stack trace.
+ */
+ export function errorHandler(opts?: any): Handler;
+
+ /**
+ * Method Override:
+ *
+ * Provides faux HTTP method support.
+ *
+ * Pass an optional `key` to use when checking for
+ * a method override, othewise defaults to _\_method_.
+ * The original method is available via `req.originalMethod`.
+ *
+ * @param key
+ */
+ export function methodOverride(key?: string): Handler;
+
+ /**
+ * Cookie parser:
+ *
+ * Parse _Cookie_ header and populate `req.cookies`
+ * with an object keyed by the cookie names. Optionally
+ * you may enabled signed cookie support by passing
+ * a `secret` string, which assigns `req.secret` so
+ * it may be used by other middleware.
+ *
+ * Examples:
+ *
+ * connect()
+ * .use(connect.cookieParser('optional secret string'))
+ * .use(function(req, res, next){
+ * res.end(JSON.stringify(req.cookies));
+ * })
+ *
+ * @param secret
+ */
+ export function cookieParser(secret?: string): Handler;
+
+ /**
+ * Session:
+ *
+ * Setup session store with the given `options`.
+ *
+ * Session data is _not_ saved in the cookie itself, however
+ * cookies are used, so we must use the [cookieParser()](cookieParser.html)
+ * middleware _before_ `session()`.
+ *
+ * Examples:
+ *
+ * connect()
+ * .use(connect.cookieParser())
+ * .use(connect.session({ secret: 'keyboard cat', key: 'sid', cookie: { secure: true }}))
+ *
+ * Options:
+ *
+ * - `key` cookie name defaulting to `connect.sid`
+ * - `store` session store instance
+ * - `secret` session cookie is signed with this secret to prevent tampering
+ * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }`
+ * - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto")
+ *
+ * Cookie option:
+ *
+ * By default `cookie.maxAge` is `null`, meaning no "expires" parameter is set
+ * so the cookie becomes a browser-session cookie. When the user closes the
+ * browser the cookie (and session) will be removed.
+ *
+ * ## req.session
+ *
+ * To store or access session data, simply use the request property `req.session`,
+ * which is (generally) serialized as JSON by the store, so nested objects
+ * are typically fine. For example below is a user-specific view counter:
+ *
+ * connect()
+ * .use(connect.favicon())
+ * .use(connect.cookieParser())
+ * .use(connect.session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))
+ * .use(function(req, res, next){
+ * var sess = req.session;
+ * if (sess.views) {
+ * res.setHeader('Content-Type', 'text/html');
+ * res.write('
views: ' + sess.views + '
');
+ * res.write('
expires in: ' + (sess.cookie.maxAge / 1000) + 's
');
+ * res.end();
+ * sess.views++;
+ * } else {
+ * sess.views = 1;
+ * res.end('welcome to the session demo. refresh!');
+ * }
+ * }
+ * )).listen(3000);
+ *
+ * ## Session#regenerate()
+ *
+ * To regenerate the session simply invoke the method, once complete
+ * a new SID and `Session` instance will be initialized at `req.session`.
+ *
+ * req.session.regenerate(function(err){
+ * // will have a new session here
+ * });
+ *
+ * ## Session#destroy()
+ *
+ * Destroys the session, removing `req.session`, will be re-generated next request.
+ *
+ * req.session.destroy(function(err){
+ * // cannot access session here
+ * });
+ *
+ * ## Session#reload()
+ *
+ * Reloads the session data.
+ *
+ * req.session.reload(function(err){
+ * // session updated
+ * });
+ *
+ * ## Session#save()
+ *
+ * Save the session.
+ *
+ * req.session.save(function(err){
+ * // session saved
+ * });
+ *
+ * ## Session#touch()
+ *
+ * Updates the `.maxAge` property. Typically this is
+ * not necessary to call, as the session middleware does this for you.
+ *
+ * ## Session#cookie
+ *
+ * Each session has a unique cookie object accompany it. This allows
+ * you to alter the session cookie per visitor. For example we can
+ * set `req.session.cookie.expires` to `false` to enable the cookie
+ * to remain for only the duration of the user-agent.
+ *
+ * ## Session#maxAge
+ *
+ * Alternatively `req.session.cookie.maxAge` will return the time
+ * remaining in milliseconds, which we may also re-assign a new value
+ * to adjust the `.expires` property appropriately. The following
+ * are essentially equivalent
+ *
+ * var hour = 3600000;
+ * req.session.cookie.expires = new Date(Date.now() + hour);
+ * req.session.cookie.maxAge = hour;
+ *
+ * For example when `maxAge` is set to `60000` (one minute), and 30 seconds
+ * has elapsed it will return `30000` until the current request has completed,
+ * at which time `req.session.touch()` is called to reset `req.session.maxAge`
+ * to its original value.
+ *
+ * req.session.cookie.maxAge;
+ * // => 30000
+ *
+ * Session Store Implementation:
+ *
+ * Every session store _must_ implement the following methods
+ *
+ * - `.get(sid, callback)`
+ * - `.set(sid, session, callback)`
+ * - `.destroy(sid, callback)`
+ *
+ * Recommended methods include, but are not limited to:
+ *
+ * - `.length(callback)`
+ * - `.clear(callback)`
+ *
+ * For an example implementation view the [connect-redis](http://github.com/visionmedia/connect-redis) repo.
+ *
+ * @param options
+ */
+ export function session(options?: any): Handler;
+
+ /**
+ * Hash the given `sess` object omitting changes
+ * to `.cookie`.
+ *
+ * @param sess
+ */
+ export function hash(sess: string): string;
+
+ /**
+ * Static:
+ *
+ * Static file server with the given `root` path.
+ *
+ * Examples:
+ *
+ * var oneDay = 86400000;
+ *
+ * connect()
+ * .use(connect.static(__dirname + '/public'))
+ *
+ * connect()
+ * .use(connect.static(__dirname + '/public', { maxAge: oneDay }))
+ *
+ * Options:
+ *
+ * - `maxAge` Browser cache maxAge in milliseconds. defaults to 0
+ * - `hidden` Allow transfer of hidden files. defaults to false
+ * - `redirect` Redirect to trailing "/" when the pathname is a dir. defaults to true
+ *
+ * @param root
+ * @param options
+ */
+ export function static (root: string, options?: any): Handler;
+
+ /**
+ * Basic Auth:
+ *
+ * Enfore basic authentication by providing a `callback(user, pass)`,
+ * which must return `true` in order to gain access. Alternatively an async
+ * method is provided as well, invoking `callback(user, pass, callback)`. Populates
+ * `req.user`. The final alternative is simply passing username / password
+ * strings.
+ *
+ * Simple username and password
+ *
+ * connect(connect.basicAuth('username', 'password'));
+ *
+ * Callback verification
+ *
+ * connect()
+ * .use(connect.basicAuth(function(user, pass){
+ * return 'tj' == user & 'wahoo' == pass;
+ * }))
+ *
+ * Async callback verification, accepting `fn(err, user)`.
+ *
+ * connect()
+ * .use(connect.basicAuth(function(user, pass, fn){
+ * User.authenticate({ user: user, pass: pass }, fn);
+ * }))
+ *
+ * @param callback or username
+ * @param realm
+ */
+ export function basicAuth(callback: Function, realm: string);
+
+ export function basicAuth(callback: string, realm: string);
+
+ export function basicAuth(callback: Function);
+
+ /**
+ * Compress:
+ *
+ * Compress response data with gzip/deflate.
+ *
+ * Filter:
+ *
+ * A `filter` callback function may be passed to
+ * replace the default logic of:
+ *
+ * exports.filter = function(req, res){
+ * return /json|text|javascript/.test(res.getHeader('Content-Type'));
+ * };
+ *
+ * Options:
+ *
+ * All remaining options are passed to the gzip/deflate
+ * creation functions. Consult node's docs for additional details.
+ *
+ * - `chunkSize` (default: 16*1024)
+ * - `windowBits`
+ * - `level`: 0-9 where 0 is no compression, and 9 is slow but best compression
+ * - `memLevel`: 1-9 low is slower but uses less memory, high is fast but uses more
+ * - `strategy`: compression strategy
+ *
+ * @param options
+ */
+ export function compress(options?: any): Handler;
+
+ /**
+ * Cookie Session:
+ *
+ * Cookie session middleware.
+ *
+ * var app = connect();
+ * app.use(connect.cookieParser());
+ * app.use(connect.cookieSession({ secret: 'tobo!', cookie: { maxAge: 60 * 60 * 1000 }}));
+ *
+ * Options:
+ *
+ * - `key` cookie name defaulting to `connect.sess`
+ * - `secret` prevents cookie tampering
+ * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }`
+ * - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto")
+ *
+ * Clearing sessions:
+ *
+ * To clear the session simply set its value to `null`,
+ * `cookieSession()` will then respond with a 1970 Set-Cookie.
+ *
+ * req.session = null;
+ *
+ * @param options
+ */
+ export function cookieSession(options?: any): Handler;
+
+ /**
+ * Anti CSRF:
+ *
+ * CRSF protection middleware.
+ *
+ * By default this middleware generates a token named "_csrf"
+ * which should be added to requests which mutate
+ * state, within a hidden form field, query-string etc. This
+ * token is validated against the visitor's `req.session._csrf`
+ * property.
+ *
+ * The default `value` function checks `req.body` generated
+ * by the `bodyParser()` middleware, `req.query` generated
+ * by `query()`, and the "X-CSRF-Token" header field.
+ *
+ * This middleware requires session support, thus should be added
+ * somewhere _below_ `session()` and `cookieParser()`.
+ *
+ * Options:
+ *
+ * - `value` a function accepting the request, returning the token
+ *
+ * @param options
+ */
+ export function csrf(options: any);
+
+ /**
+ * Directory:
+ *
+ * Serve directory listings with the given `root` path.
+ *
+ * Options:
+ *
+ * - `hidden` display hidden (dot) files. Defaults to false.
+ * - `icons` display icons. Defaults to false.
+ * - `filter` Apply this filter function to files. Defaults to false.
+ *
+ * @param root
+ * @param options
+ */
+ export function directory(root: string, options?: any): Handler;
+
+ /**
+ * Favicon:
+ *
+ * By default serves the connect favicon, or the favicon
+ * located by the given `path`.
+ *
+ * Options:
+ *
+ * - `maxAge` cache-control max-age directive, defaulting to 1 day
+ *
+ * Examples:
+ *
+ * Serve default favicon:
+ *
+ * connect()
+ * .use(connect.favicon())
+ *
+ * Serve favicon before logging for brevity:
+ *
+ * connect()
+ * .use(connect.favicon())
+ * .use(connect.logger('dev'))
+ *
+ * Serve custom favicon:
+ *
+ * connect()
+ * .use(connect.favicon('public/favicon.ico))
+ *
+ * @param path
+ * @param options
+ */
+ export function favicon(path?: string, options?: any);
+
+ /**
+ * JSON:
+ *
+ * Parse JSON request bodies, providing the
+ * parsed object as `req.body`.
+ *
+ * Options:
+ *
+ * - `strict` when `false` anything `JSON.parse()` accepts will be parsed
+ * - `reviver` used as the second "reviver" argument for JSON.parse
+ * - `limit` byte limit disabled by default
+ *
+ * @param options
+ */
+ export function json(options?: any): Handler;
+
+ /**
+ * Limit:
+ *
+ * Limit request bodies to the given size in `bytes`.
+ *
+ * A string representation of the bytesize may also be passed,
+ * for example "5mb", "200kb", "1gb", etc.
+ *
+ * connect()
+ * .use(connect.limit('5.5mb'))
+ * .use(handleImageUpload)
+ */
+ export function limit(bytes: number): Handler;
+
+ export function limit(bytes: string): Handler;
+
+ /**
+ * Logger:
+ *
+ * Log requests with the given `options` or a `format` string.
+ *
+ * Options:
+ *
+ * - `format` Format string, see below for tokens
+ * - `stream` Output stream, defaults to _stdout_
+ * - `buffer` Buffer duration, defaults to 1000ms when _true_
+ * - `immediate` Write log line on request instead of response (for response times)
+ *
+ * Tokens:
+ *
+ * - `:req[header]` ex: `:req[Accept]`
+ * - `:res[header]` ex: `:res[Content-Length]`
+ * - `:http-version`
+ * - `:response-time`
+ * - `:remote-addr`
+ * - `:date`
+ * - `:method`
+ * - `:url`
+ * - `:referrer`
+ * - `:user-agent`
+ * - `:status`
+ *
+ * Formats:
+ *
+ * Pre-defined formats that ship with connect:
+ *
+ * - `default` ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'
+ * - `short` ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms'
+ * - `tiny` ':method :url :status :res[content-length] - :response-time ms'
+ * - `dev` concise output colored by response status for development use
+ *
+ * Examples:
+ *
+ * connect.logger() // default
+ * connect.logger('short')
+ * connect.logger('tiny')
+ * connect.logger({ immediate: true, format: 'dev' })
+ * connect.logger(':method :url - :referrer')
+ * connect.logger(':req[content-type] -> :res[content-type]')
+ * connect.logger(function(tokens, req, res){ return 'some format string' })
+ *
+ * Defining Tokens:
+ *
+ * To define a token, simply invoke `connect.logger.token()` with the
+ * name and a callback function. The value returned is then available
+ * as ":type" in this case.
+ *
+ * connect.logger.token('type', function(req, res){ return req.headers['content-type']; })
+ *
+ * Defining Formats:
+ *
+ * All default formats are defined this way, however it's public API as well:
+ *
+ * connect.logger.format('name', 'string or function')
+ */
+ export function logger(options: string): Handler;
+
+ export function logger(options: Function): Handler;
+
+ export function logger(options?: any): Handler;
+
+ /**
+ * Compile `fmt` into a function.
+ *
+ * @param fmt
+ */
+ export function compile(fmt: string): Handler;
+
+ /**
+ * Define a token function with the given `name`,
+ * and callback `fn(req, res)`.
+ *
+ * @param name
+ * @param fn
+ */
+ export function token(name: string, fn: Function): any;
+
+ /**
+ * Define a `fmt` with the given `name`.
+ */
+ export function format(name: string, str: string): any;
+
+ export function format(name: string, str: Function): any;
+
+ /**
+ * Query:
+ *
+ * Automatically parse the query-string when available,
+ * populating the `req.query` object.
+ *
+ * Examples:
+ *
+ * connect()
+ * .use(connect.query())
+ * .use(function(req, res){
+ * res.end(JSON.stringify(req.query));
+ * });
+ *
+ * The `options` passed are provided to qs.parse function.
+ */
+ export function query(options: any): Handler;
+
+ /**
+ * Reponse time:
+ *
+ * Adds the `X-Response-Time` header displaying the response
+ * duration in milliseconds.
+ */
+ export function responseTime(): Handler;
+
+ /**
+ * Static cache:
+ *
+ * Enables a memory cache layer on top of
+ * the `static()` middleware, serving popular
+ * static files.
+ *
+ * By default a maximum of 128 objects are
+ * held in cache, with a max of 256k each,
+ * totalling ~32mb.
+ *
+ * A Least-Recently-Used (LRU) cache algo
+ * is implemented through the `Cache` object,
+ * simply rotating cache objects as they are
+ * hit. This means that increasingly popular
+ * objects maintain their positions while
+ * others get shoved out of the stack and
+ * garbage collected.
+ *
+ * Benchmarks:
+ *
+ * static(): 2700 rps
+ * node-static: 5300 rps
+ * static() + staticCache(): 7500 rps
+ *
+ * Options:
+ *
+ * - `maxObjects` max cache objects [128]
+ * - `maxLength` max cache object length 256kb
+ */
+ export function staticCache(options: any): Handler;
+
+ /**
+ * Timeout:
+ *
+ * Times out the request in `ms`, defaulting to `5000`. The
+ * method `req.clearTimeout()` is added to revert this behaviour
+ * programmatically within your application's middleware, routes, etc.
+ *
+ * The timeout error is passed to `next()` so that you may customize
+ * the response behaviour. This error has the `.timeout` property as
+ * well as `.status == 408`.
+ */
+ export function timeout(ms: number): Handler;
+
+ /**
+ * Vhost:
+ *
+ * Setup vhost for the given `hostname` and `server`.
+ *
+ * connect()
+ * .use(connect.vhost('foo.com', fooApp))
+ * .use(connect.vhost('bar.com', barApp))
+ * .use(connect.vhost('*.com', mainApp))
+ *
+ * The `server` may be a Connect server or
+ * a regular Node `http.Server`.
+ *
+ * @param hostname
+ * @param server
+ */
+ export function vhost(hostname: string, server: any): Handler;
+
+ export function urlencoded(): any;
+
+ export function multipart(): any;
+}
\ No newline at end of file
diff --git a/fabricjs/fabricjs.d.ts b/fabricjs/fabricjs.d.ts
index ec4559e945..256e4cb41b 100644
--- a/fabricjs/fabricjs.d.ts
+++ b/fabricjs/fabricjs.d.ts
@@ -758,6 +758,7 @@ declare module fabric {
fromURL(url: string): IImage;
fromURL(url: string, callback: (image: IImage) => any): IImage;
fromURL(url: string, callback: (image: IImage) => any, objObjects: IObjectOptions): IImage;
+ new (element: HTMLImageElement, objObjects: IObjectOptions): IImage;
prototype: any;
filters:
diff --git a/filesystem/filesystem-tests.ts b/filesystem/filesystem-tests.ts
new file mode 100644
index 0000000000..8f175db98d
--- /dev/null
+++ b/filesystem/filesystem-tests.ts
@@ -0,0 +1,49 @@
+///
+// http://www.w3.org/TR/file-system-api/
+
+// 2. Introduction
+declare function getAsText(file:File): void;
+declare function writeDataToLogFile(fileWriter:FileWriterSync): void;
+
+function useAsyncFS(fs:FileSystem):void {
+ // see getAsText example in [FILE-API-ED].
+ fs.root.getFile("already_there.txt", null, function (f:FileEntry): void{
+
+ // In the example of the specification, there is a following code:
+ //
+ // getAsText(f.file());
+ //
+ // It seems wrong because f is ASYNCRONOUS file system.
+ f.file(getAsText);
+
+ });
+
+ // But now we can also write to the file; see [FILE-WRITER-ED].
+ fs.root.getFile("logFile", {create: true}, function (f:FileEntry): void{
+ f.createWriter(writeDataToLogFile);
+ });
+}
+window.requestFileSystem(window.TEMPORARY, 1024 * 1024, function(fs:FileSystem): void{
+ useAsyncFS(fs);
+});
+
+// In a worker:
+
+var tempFS:FileSystemSync = window.requestFileSystemSync(window.TEMPORARY, 1024 * 1024);
+var logFile:FileEntrySync = tempFS.root.getFile("logFile", {create: true});
+var writer:FileWriterSync = logFile.createWriter();
+writer.seek(writer.length);
+writeDataToLogFile(writer);
+
+
+// 5.2 The Flags dictionary
+var fsSync:FileSystemSync = window.requestFileSystemSync(window.TEMPORARY, 1024 * 1024);
+// Get the data directory, creating it if it doesn't exist.
+var dataDir:DirectoryEntrySync = fsSync.root.getDirectory("data", {create: true});
+
+// Create the lock file, if and only if it doesn't exist.
+try {
+ var lockFile:FileEntrySync = dataDir.getFile("lockfile.txt", {create: true, exclusive: true});
+} catch (ex) {
+ // It already exists, or something else went wrong.
+}
diff --git a/filesystem/filesystem.d.ts b/filesystem/filesystem.d.ts
new file mode 100644
index 0000000000..90b159f752
--- /dev/null
+++ b/filesystem/filesystem.d.ts
@@ -0,0 +1,528 @@
+// Type Definitions for File API: Directories and System (File System API)
+// Project: http://www.w3.org/TR/file-system-api/
+// Definitions by: Kon
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+///
+
+interface LocalFileSystem {
+
+ /**
+ * Used for storage with no guarantee of persistence.
+ */
+ TEMPORARY:number;
+
+ /**
+ * Used for storage that should not be removed by the user agent without application or user permission.
+ */
+ PERSISTENT:number;
+
+ /**
+ * Requests a filesystem in which to store application data.
+ * @param type Whether the filesystem requested should be persistent, as defined above. Use one of TEMPORARY or PERSISTENT.
+ * @param size This is an indicator of how much storage space, in bytes, the application expects to need.
+ * @param successCallback The callback that is called when the user agent provides a filesystem.
+ * @param errorCallback A callback that is called when errors happen, or when the request to obtain the filesystem is denied.
+ */
+ requestFileSystem(type:number, size:number, successCallback:FileSystemCallback, errorCallback?:ErrorCallback):void;
+
+ /**
+ * Allows the user to look up the Entry for a file or directory referred to by a local URL.
+ * @param url A URL referring to a local file in a filesystem accessable via this API.
+ * @param successCallback A callback that is called to report the Entry to which the supplied URL refers.
+ * @param errorCallback A callback that is called when errors happen, or when the request to obtain the Entry is denied.
+ */
+ resolveLocalFileSystemURL(url:string, successCallback:EntryCallback, errorCallback?:ErrorCallback):void;
+
+ /**
+ * see requestFileSystem.
+ */
+ webkitRequestFileSystem(type:number, size:number, successCallback:FileSystemCallback, errorCallback?:ErrorCallback):void;
+}
+
+interface LocalFileSystemSync {
+ /**
+ * Used for storage with no guarantee of persistence.
+ */
+ TEMPORARY:number;
+
+ /**
+ * Used for storage that should not be removed by the user agent without application or user permission.
+ */
+ PERSISTENT:number;
+
+ /**
+ * Requests a filesystem in which to store application data.
+ * @param type Whether the filesystem requested should be persistent, as defined above. Use one of TEMPORARY or PERSISTENT.
+ * @param size This is an indicator of how much storage space, in bytes, the application expects to need.
+ */
+ requestFileSystemSync(type:number, size:number):FileSystemSync;
+
+ /**
+ * Allows the user to look up the Entry for a file or directory referred to by a local URL.
+ * @param url A URL referring to a local file in a filesystem accessable via this API.
+ */
+ resolveLocalFileSystemSyncURL(url:string):EntrySync;
+
+ /**
+ * see requestFileSystemSync
+ */
+ webkitRequestFileSystemSync(type:number, size:number):FileSystemSync;
+}
+
+interface Metadata {
+ /**
+ * This is the time at which the file or directory was last modified.
+ * @readonly
+ */
+ modificationTime:Date;
+
+ /**
+ * The size of the file, in bytes. This must return 0 for directories.
+ * @readonly
+ */
+ size:number;
+}
+
+interface Flags {
+ /**
+ * Used to indicate that the user wants to create a file or directory if it was not previously there.
+ */
+ create?:bool;
+
+ /**
+ * By itself, exclusive must have no effect. Used with create, it must cause getFile and getDirectory to fail if the target path already exists.
+ */
+ exclusive?:bool;
+}
+
+/**
+ * This interface represents a file system.
+ */
+interface FileSystem{
+ /**
+ * This is the name of the file system. The specifics of naming filesystems is unspecified, but a name must be unique across the list of exposed file systems.
+ * @readonly
+ */
+ name: string;
+
+ /**
+ * The root directory of the file system.
+ * @readonly
+ */
+ root:any;
+}
+
+interface Entry {
+
+ /**
+ * Entry is a file.
+ */
+ isFile:bool;
+
+ /**
+ * Entry is a directory.
+ */
+ isDirectory:bool;
+
+ /**
+ * Look up metadata about this entry.
+ * @param successCallback A callback that is called with the time of the last modification.
+ * @param errorCallback ErrorCallback A callback that is called when errors happen.
+ */
+ getMetadata(successCallback:MetadataCallback, errorCallback?:ErrorCallback):void;
+
+ /**
+ * The name of the entry, excluding the path leading to it.
+ */
+ name:string;
+
+ /**
+ * The full absolute path from the root to the entry.
+ */
+ fullPath:string;
+
+ /**
+ * The file system on which the entry resides.
+ */
+ filesystem:FileSystem;
+
+ /**
+ * Move an entry to a different location on the file system. It is an error to try to:
+ *
+ *
+ *
move a directory inside itself or to any child at any depth;
+ *
move an entry into its parent if a name different from its current one isn't provided;
+ *
move a file to a path occupied by a directory;
+ *
move a directory to a path occupied by a file;
+ *
move any element to a path occupied by a directory which is not empty.
+ *
+ *
+ * A move of a file on top of an existing file must attempt to delete and replace that file.
+ * A move of a directory on top of an existing empty directory must attempt to delete and replace that directory.
+ */
+ moveTo(parent:DirectoryEntry, newName?:string, successCallback?:EntryCallback, errorCallback?:ErrorCallback):string;
+
+ /**
+ * Copy an entry to a different location on the file system. It is an error to try to:
+ *
+ *
+ *
copy a directory inside itself or to any child at any depth;
+ *
copy an entry into its parent if a name different from its current one isn't provided;
+ *
copy a file to a path occupied by a directory;
+ *
copy a directory to a path occupied by a file;
+ *
copy any element to a path occupied by a directory which is not empty.
+ *
A copy of a file on top of an existing file must attempt to delete and replace that file.
+ *
A copy of a directory on top of an existing empty directory must attempt to delete and replace that directory.
+ *
+ *
+ * Directory copies are always recursive--that is, they copy all contents of the directory.
+ */
+ copyTo(parent:DirectoryEntry, newName?:string, successCallback?:EntryCallback, errorCallback?:ErrorCallback):string;
+
+ /**
+ * Returns a URL that can be used to identify this entry. Unlike the URN defined in [FILE-API-ED], it has no specific expiration; as it describes a location on disk, it should be valid at least as long as that location exists.
+ */
+ toURL():string;
+
+ /**
+ * Deletes a file or directory. It is an error to attempt to delete a directory that is not empty. It is an error to attempt to delete the root directory of a filesystem.
+ * @param successCallback A callback that is called on success.
+ * @param errorCallback A callback that is called when errors happen.
+ */
+ remove(successCallback:VoidCallback, errorCallback?:ErrorCallback):void;
+
+ /**
+ * Look up the parent DirectoryEntry containing this Entry. If this Entry is the root of its filesystem, its parent is itself.
+ * @param successCallback A callback that is called to return the parent Entry.
+ * @param errorCallback A callback that is called when errors happen.
+ */
+ getParent(successCallback:EntryCallback, errorCallback?:ErrorCallback):void;
+}
+
+/**
+ * This interface represents a directory on a file system.
+ */
+interface DirectoryEntry extends Entry {
+ /**
+ * Creates a new DirectoryReader to read Entries from this Directory.
+ */
+ createReader():DirectoryReader;
+
+ /**
+ * Creates or looks up a file.
+ * @param path Either an absolute path or a relative path from this DirectoryEntry to the file to be looked up or created. It is an error to attempt to create a file whose immediate parent does not yet exist.
+ * @param options
+ *
+ *
If create and exclusive are both true, and the path already exists, getFile must fail.
+ *
If create is true, the path doesn't exist, and no other error occurs, getFile must create it as a zero-length file and return a corresponding FileEntry.
+ *
If create is not true and the path doesn't exist, getFile must fail.
+ *
If create is not true and the path exists, but is a directory, getFile must fail.
+ *
Otherwise, if no other error occurs, getFile must return a FileEntry corresponding to path.
+ *
+ * @param successCallback A callback that is called to return the File selected or created.
+ * @param errorCallback A callback that is called when errors happen.
+ */
+ getFile(path:string, options?:Flags, successCallback?:EntryCallback, errorCallback?:ErrorCallback):void;
+
+ /**
+ * Creates or looks up a directory.
+ * @param path Either an absolute path or a relative path from this DirectoryEntry to the directory to be looked up or created. It is an error to attempt to create a directory whose immediate parent does not yet exist.
+ * @param options
+ *
+ *
If create and exclusive are both true and the path already exists, getDirectory must fail.
+ *
If create is true, the path doesn't exist, and no other error occurs, getDirectory must create and return a corresponding DirectoryEntry.
+ *
If create is not true and the path doesn't exist, getDirectory must fail.
+ *
If create is not true and the path exists, but is a file, getDirectory must fail.
+ *
Otherwise, if no other error occurs, getDirectory must return a DirectoryEntry corresponding to path.
+ *
+ * @param successCallback A callback that is called to return the DirectoryEntry selected or created.
+ * @param errorCallback A callback that is called when errors happen.
+ *
+ */
+ getDirectory(path:string, options?:Flags, successCallback?:EntryCallback, errorCallback?:ErrorCallback):void;
+
+ /**
+ * Deletes a directory and all of its contents, if any. In the event of an error [e.g. trying to delete a directory that contains a file that cannot be removed], some of the contents of the directory may be deleted. It is an error to attempt to delete the root directory of a filesystem.
+ * @param successCallback A callback that is called on success.
+ * @param errorCallback A callback that is called when errors happen.
+ */
+ removeRecursively(successCallback:VoidCallback, errorCallback?:ErrorCallback):void;
+}
+
+/**
+ * This interface lets a user list files and directories in a directory. If there are no additions to or deletions from a directory between the first and last call to readEntries, and no errors occur, then:
+ *
+ *
A series of calls to readEntries must return each entry in the directory exactly once.
+ *
Once all entries have been returned, the next call to readEntries must produce an empty array.
+ *
If not all entries have been returned, the array produced by readEntries must not be empty.
+ *
The entries produced by readEntries must not include the directory itself ["."] or its parent [".."].
+ *
+ */
+interface DirectoryReader {
+ /**
+ * Read the next block of entries from this directory.
+ * @param successCallback Called once per successful call to readEntries to deliver the next previously-unreported set of Entries in the associated Directory. If all Entries have already been returned from previous invocations of readEntries, successCallback must be called with a zero-length array as an argument.
+ * @param errorCallback A callback indicating that there was an error reading from the Directory.
+ */
+ readEntries(successCallback:EntriesCallback, errorCallback?:ErrorCallback):void;
+}
+
+/**
+ * This interface represents a file on a file system.
+ */
+interface FileEntry extends Entry {
+ /**
+ * Creates a new FileWriter associated with the file that this FileEntry represents.
+ * @param successCallback A callback that is called with the new FileWriter.
+ * @param errorCallback A callback that is called when errors happen.
+ */
+ createWriter(successCallback:FileWriterCallback, errorCallback?:ErrorCallback):void;
+
+ /**
+ * Returns a File that represents the current state of the file that this FileEntry represents.
+ * @param successCallback A callback that is called with the File.
+ * @param errorCallback A callback that is called when errors happen.
+ */
+ file(successCallback:FileCallback, errorCallback?:ErrorCallback):void;
+}
+
+/**
+ * When requestFileSystem() succeeds, the following callback is made.
+ */
+interface FileSystemCallback {
+ /**
+ * @param filesystem The file systems to which the app is granted access.
+ */
+ (filesystem:FileSystem):void;
+}
+
+/**
+ * This interface is the callback used to look up Entry objects.
+ */
+interface EntryCallback {
+ /**
+ * @param entry
+ */
+ (entry:Entry):void;
+}
+
+/**
+ * When readEntries() succeeds, the following callback is made.
+ */
+interface EntriesCallback {
+ (entries:Entry[]):void;
+}
+
+/**
+ * This interface is the callback used to look up file and directory metadata.
+ */
+interface MetadataCallback {
+ (metadata:Metadata):void;
+}
+
+/**
+ * This interface is the callback used to create a FileWriter.
+ */
+interface FileWriterCallback {
+ (fileWriter:FileWriter):void;
+}
+
+/**
+ * This interface is the callback used to obtain a File.
+ */
+interface FileCallback {
+ (file:File):void;
+}
+
+/**
+ * This interface is the generic callback used to indicate success of an asynchronous method.
+ */
+interface VoidCallback {
+ ():void;
+}
+
+/**
+ * When an error occurs, the following callback is made.
+ */
+interface ErrorCallback {
+ (err:DOMError):void;
+}
+
+
+/**
+ * This interface represents a file system.
+ */
+interface FileSystemSync {
+ /**
+ * This is the name of the file system. The specifics of naming filesystems is unspecified, but a name must be unique across the list of exposed file systems.
+ */
+ name:string;
+
+ /**
+ * root The root directory of the file system.
+ */
+ root:DirectoryEntrySync;
+}
+
+/**
+ * An abstract interface representing entries in a file system, each of which may be a FileEntrySync or DirectoryEntrySync.
+ */
+interface EntrySync{
+ /**
+ * EntrySync is a file.
+ * @readonly
+ */
+ isFile:bool;
+
+ /**
+ * EntrySync is a directory.
+ * @readonly
+ */
+ isDirectory:bool;
+
+ /**
+ * Look up metadata about this entry.
+ */
+ getMetadata():Metadata;
+
+ /**
+ * The name of the entry, excluding the path leading to it.
+ */
+ name:string;
+
+ /**
+ * The full absolute path from the root to the entry.
+ */
+ fullPath:string;
+
+ /**
+ * The file system on which the entry resides.
+ */
+ filesystem:FileSystemSync;
+
+ /**
+ * Move an entry to a different location on the file system. It is an error to try to:
+ *
+ *
move a directory inside itself or to any child at any depth;
+ *
move an entry into its parent if a name different from its current one isn't provided;
+ *
move a file to a path occupied by a directory;
+ *
move a directory to a path occupied by a file;
+ *
move any element to a path occupied by a directory which is not empty.
+ *
+ * A move of a file on top of an existing file must attempt to delete and replace that file. A move of a directory on top of an existing empty directory must attempt to delete and replace that directory.
+ * @param parent The directory to which to move the entry.
+ * @param newName The new name of the entry. Defaults to the EntrySync's current name if unspecified.
+ */
+ moveTo(parent:DirectoryEntrySync, newName?:string):EntrySync;
+
+ /**
+ * Copy an entry to a different location on the file system. It is an error to try to:
+ *
+ *
copy a directory inside itself or to any child at any depth;
+ *
copy an entry into its parent if a name different from its current one isn't provided;
+ *
copy a file to a path occupied by a directory;
+ *
copy a directory to a path occupied by a file;
+ *
copy any element to a path occupied by a directory which is not empty.
+ *
+ * A copy of a file on top of an existing file must attempt to delete and replace that file.
+ * A copy of a directory on top of an existing empty directory must attempt to delete and replace that directory.
+ * Directory copies are always recursive--that is, they copy all contents of the directory.
+ */
+ copyTo(parent:DirectoryEntrySync, newName?:string):EntrySync;
+
+ /**
+ * Returns a URL that can be used to identify this entry. Unlike the URN defined in [FILE-API-ED], it has no specific expiration; as it describes a location on disk, it should be valid at least as long as that location exists.
+ */
+ toURL():string;
+
+ /**
+ * Deletes a file or directory. It is an error to attempt to delete a directory that is not empty. It is an error to attempt to delete the root directory of a filesystem.
+ */
+ remove ():void;
+
+ /**
+ * Look up the parent DirectoryEntrySync containing this Entry. If this EntrySync is the root of its filesystem, its parent is itself.
+ */
+ getParent():DirectoryEntrySync;
+}
+
+/**
+ * This interface represents a directory on a file system.
+ */
+interface DirectoryEntrySync extends EntrySync {
+ /**
+ * Creates a new DirectoryReaderSync to read EntrySyncs from this DirectorySync.
+ */
+ createReader():DirectoryReaderSync;
+
+ /**
+ * Creates or looks up a directory.
+ * @param path Either an absolute path or a relative path from this DirectoryEntrySync to the file to be looked up or created. It is an error to attempt to create a file whose immediate parent does not yet exist.
+ * @param options
+ *
+ *
If create and exclusive are both true and the path already exists, getFile must fail.
+ *
If create is true, the path doesn't exist, and no other error occurs, getFile must create it as a zero-length file and return a corresponding FileEntry.
+ *
If create is not true and the path doesn't exist, getFile must fail.
+ *
If create is not true and the path exists, but is a directory, getFile must fail.
+ *
Otherwise, if no other error occurs, getFile must return a FileEntrySync corresponding to path.
+ *
+ */
+ getFile(path:string, options?:Flags):FileEntrySync;
+
+ /**
+ * Creates or looks up a directory.
+ * @param path Either an absolute path or a relative path from this DirectoryEntrySync to the directory to be looked up or created. It is an error to attempt to create a directory whose immediate parent does not yet exist.
+ * @param options
+ *
+ *
If create and exclusive are both true and the path already exists, getDirectory must fail.
+ *
If create is true, the path doesn't exist, and no other error occurs, getDirectory must create and return a corresponding DirectoryEntry.
+ *
If create is not true and the path doesn't exist, getDirectory must fail.
+ *
If create is not true and the path exists, but is a file, getDirectory must fail.
+ *
Otherwise, if no other error occurs, getDirectory must return a DirectoryEntrySync corresponding to path.
+ *
+ */
+ getDirectory(path:string, options?:Flags):DirectoryEntrySync;
+
+ /**
+ * Deletes a directory and all of its contents, if any. In the event of an error [e.g. trying to delete a directory that contains a file that cannot be removed], some of the contents of the directory may be deleted. It is an error to attempt to delete the root directory of a filesystem.
+ */
+ removeRecursively():void;
+}
+
+/**
+ * This interface lets a user list files and directories in a directory. If there are no additions to or deletions from a directory between the first and last call to readEntries, and no errors occur, then:
+ *
+ *
A series of calls to readEntries must return each entry in the directory exactly once.
+ *
Once all entries have been returned, the next call to readEntries must produce an empty array.
+ *
If not all entries have been returned, the array produced by readEntries must not be empty.
+ *
The entries produced by readEntries must not include the directory itself ["."] or its parent [".."].
+ *
+ */
+interface DirectoryReaderSync {
+ /**
+ * Read the next block of entries from this directory.
+ */
+ readEntries():EntrySync[];
+}
+
+/**
+ * This interface represents a file on a file system.
+ */
+interface FileEntrySync extends EntrySync {
+ /**
+ * Creates a new FileWriterSync associated with the file that this FileEntrySync represents.
+ */
+ createWriter():FileWriterSync;
+
+ /**
+ * Returns a File that represents the current state of the file that this FileEntrySync represents.
+ */
+ file():File;
+}
+
+interface Window extends LocalFileSystem, LocalFileSystemSync{
+}
+
+interface WorkerGlobalScope extends LocalFileSystem, LocalFileSystemSync{
+}
diff --git a/filewriter/filewriter-tests.ts b/filewriter/filewriter-tests.ts
new file mode 100644
index 0000000000..f70e76087d
--- /dev/null
+++ b/filewriter/filewriter-tests.ts
@@ -0,0 +1,16 @@
+///
+
+// http://www.w3.org/TR/file-writer-api/
+function writeFile(writer:FileWriter): void{
+ function done(evt:Event): void{
+ alert("Write completed.");
+ }
+ function error(evt:Event): void{
+ alert("Write failed:" + evt);
+ }
+
+ var b:Blob = new Blob();
+ writer.onwrite = done;
+ writer.onerror = error;
+ writer.write(b);
+}
\ No newline at end of file
diff --git a/filewriter/filewriter.d.ts b/filewriter/filewriter.d.ts
new file mode 100644
index 0000000000..2257ee9eb8
--- /dev/null
+++ b/filewriter/filewriter.d.ts
@@ -0,0 +1,176 @@
+// Type Definitions for File API: Writer
+// Project: http://www.w3.org/TR/file-writer-api/
+// Definitions by: Kon
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+/**
+ * This interface provides methods to monitor the asynchronous writing of blobs to disk using progress events [PROGRESS-EVENTS] and event handler attributes.
+ * This interface is specified to be used within the context of the global object (Window [HTML5]) and within Web Workers (WorkerUtils [WEBWORKERS-ED]).
+ */
+interface FileSaver extends EventTarget {
+ /**
+ * When the abort method is called, user agents must run the steps below:
+ *
+ *
If readyState == DONE or readyState == INIT, terminate this overall series of steps without doing anything else.
+ *
Set readyState to DONE.
+ *
If there are any tasks from the object's FileSaver task source in one of the task queues, then remove those tasks.
+ *
Terminate the write algorithm being processed.
+ *
Set the error attribute to a DOMError object of type "AbortError".
+ *
Fire a progress event called abort
+ *
Fire a progress event called writeend
+ *
Terminate this algorithm.
+ *
+ */
+ abort():void;
+
+ /**
+ * The blob is being written.
+ * @readonly
+ */
+ INIT:number;
+
+ /**
+ * The object has been constructed, but there is no pending write.
+ * @readonly
+ */
+ WRITING:number;
+
+ /**
+ * The entire Blob has been written to the file, an error occurred during the write, or the write was aborted using abort(). The FileSaver is no longer writing the blob.
+ * @readonly
+ */
+ DONE:number;
+
+ /**
+ * The FileSaver object can be in one of 3 states. The readyState attribute, on getting, must return the current state, which must be one of the following values:
+ *
+ *
INIT
+ *
WRITING
+ *
DONE
+ *
+ * @readonly
+ */
+ readyState:number;
+
+ /**
+ * The last error that occurred on the FileSaver.
+ * @readonly
+ */
+ error:DOMError;
+
+ /**
+ * Handler for writestart events
+ */
+ onwritestart:Function;
+
+ /**
+ * Handler for progress events.
+ */
+ onprogress:Function;
+
+ /**
+ * Handler for write events.
+ */
+ onwrite:Function;
+
+ /**
+ * Handler for abort events.
+ */
+ onabort:Function;
+
+ /**
+ * Handler for error events.
+ */
+ onerror:Function;
+
+ /**
+ * Handler for writeend events.
+ */
+ onwriteend:Function;
+}
+
+var FileSaver: {
+ /**
+ * When the FileSaver constructor is called, the user agent must return a new FileSaver object with readyState set to INIT.
+ * This constructor must be visible when the script's global object is either a Window object or an object implementing the WorkerUtils interface.
+ */
+ new(data:Blob): FileSaver;
+}
+
+/**
+ * This interface expands on the FileSaver interface to allow for multiple write actions, rather than just saving a single Blob.
+ */
+interface FileWriter extends FileSaver {
+ /**
+ * The byte offset at which the next write to the file will occur. This must be no greater than length.
+ * A newly-created FileWriter must have position set to 0.
+ */
+ position:number;
+
+ /**
+ * The length of the file. If the user does not have read access to the file, this must be the highest byte offset at which the user has written.
+ */
+ length:number;
+
+ /**
+ * Write the supplied data to the file at position.
+ * @param data The blob to write.
+ */
+ write(data:Blob):void;
+
+ /**
+ * Seek sets the file position at which the next write will occur.
+ * @param offset If nonnegative, an absolute byte offset into the file. If negative, an offset back from the end of the file.
+ */
+ seek(offset:number):void;
+
+ /**
+ * Changes the length of the file to that specified. If shortening the file, data beyond the new length must be discarded. If extending the file, the existing data must be zero-padded up to the new length.
+ * @param size The size to which the length of the file is to be adjusted, measured in bytes.
+ */
+ truncate(size:number):void;
+}
+
+/**
+ * This interface lets users write, truncate, and append to files using simple synchronous calls.
+ * This interface is specified to be used only within Web Workers (WorkerUtils [WEBWORKERS]).
+ */
+interface FileWriterSync {
+ /**
+ * The byte offset at which the next write to the file will occur. This must be no greater than length.
+ */
+ position:number;
+
+ /**
+ * The length of the file. If the user does not have read access to the file, this must be the highest byte offset at which the user has written.
+ */
+ length:number;
+
+ /**
+ * Write the supplied data to the file at position. Upon completion, position will increase by data.size.
+ * @param data The blob to write.
+ */
+ write(data:Blob):void;
+
+ /**
+ * Seek sets the file position at which the next write will occur.
+ * @param offset An absolute byte offset into the file. If offset is greater than length, length is used instead. If offset is less than zero, length is added to it, so that it is treated as an offset back from the end of the file. If it is still less than zero, zero is used.
+ */
+ seek(offset:number):void;
+
+ /**
+ * Changes the length of the file to that specified. If shortening the file, data beyond the new length must be discarded. If extending the file, the existing data must be zero-padded up to the new length.
+ * Upon successful completion:
+ *
+ *
length must be equal to size.
+ *
position must be the lesser of
+ *
+ *
its pre-truncate value,
+ *
size.
+ *
+ *
+ *
+ * @param size The size to which the length of the file is to be adjusted, measured in bytes.
+ */
+ truncate(size:number):void;
+}
diff --git a/flexSlider/flexSlider-tests.ts b/flexSlider/flexSlider-tests.ts
new file mode 100644
index 0000000000..8651102422
--- /dev/null
+++ b/flexSlider/flexSlider-tests.ts
@@ -0,0 +1,84 @@
+///
+
+// Can also be used with $(document).ready()
+$(window).load(function() {
+ $('.flexslider').flexslider({
+ animation: "slide"
+ });
+});
+
+// Can also be used with $(document).ready()
+$(window).load(function() {
+ $('.flexslider').flexslider({
+ animation: "slide",
+ controlNav: "thumbnails"
+ });
+});
+
+$(window).load(function() {
+ // The slider being synced must be initialized first
+ $('#carousel').flexslider({
+ animation: "slide",
+ controlNav: false,
+ animationLoop: false,
+ slideshow: false,
+ itemWidth: 210,
+ itemMargin: 5,
+ asNavFor: '#slider'
+ });
+
+ $('#slider').flexslider({
+ animation: "slide",
+ controlNav: false,
+ animationLoop: false,
+ slideshow: false,
+ sync: "#carousel"
+ });
+});
+
+$(window).load(function() {
+ $('.flexslider').flexslider({
+ animation: "slide",
+ animationLoop: false,
+ itemWidth: 210,
+ itemMargin: 5
+ });
+});
+
+// Can also be used with $(document).ready()
+$(window).load(function() {
+ $('.flexslider').flexslider({
+ animation: "slide",
+ animationLoop: false,
+ itemWidth: 210,
+ itemMargin: 5,
+ minItems: 2,
+ maxItems: 4
+ });
+});
+
+// Can also be used with $(document).ready()
+$(window).load(function() {
+
+ // Vimeo API nonsense
+ var player = document.getElementById('player_1');
+ $(player).on('ready', ready);
+
+ function addEvent(element, eventName, callback) {
+ if (element.addEventListener) {
+ element.addEventListener(eventName, callback, false)
+ } else {
+ element.attachEvent(eventName, callback, false);
+ }
+ }
+
+ function ready(player_id) {
+ var froogaloop = $(player_id);
+ froogaloop.on('play', function(data) {
+ $('.flexslider').flexslider("pause");
+ });
+ froogaloop.on('pause', function(data) {
+ $('.flexslider').flexslider("play");
+ });
+ }
+});
\ No newline at end of file
diff --git a/flexSlider/flexSlider.d.ts b/flexSlider/flexSlider.d.ts
new file mode 100644
index 0000000000..290cc1c459
--- /dev/null
+++ b/flexSlider/flexSlider.d.ts
@@ -0,0 +1,90 @@
+// Type definitions for FlexSlider 2 jquery plugin
+// Project: https://github.com/woothemes/FlexSlider
+// Definitions by: Diullei Gomes
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+///
+
+interface SliderObject { //Object: The slider element itself
+ container: Object; //Object: The ul.slides within the slider
+ slides: Object; //Object: The slides of the slider
+ count: number; //Int: The total number of slides in the slider
+ currentSlide: number; //Int: The slide currently being shown
+ animatingTo: number; //Int: Useful in .before(), the slide currently animating to
+ animating: bool; //Boolean: is slider animating?
+ atEnd: bool; //Boolean: is the slider at either end?
+ manualPause: bool; //Boolean: force slider to stay paused during pauseOnHover event
+ controlNav: Object; //Object: The slider controlNav
+ directionNav: Object; //Object: The slider directionNav
+ controlsContainer: Object; //Object: The controlsContainer element of the slider
+ manualControls: Object; //Object: The manualControls element of the slider
+ flexAnimate(target, pause?); //Function: Move slider - (target, pause) parameters
+ pause(); //Function: Pause slider slideshow interval
+ resume(); //Function: Resume slider slideshow interval
+ canAdvance(target); //Function: returns boolean if slider can advance - (target) parameter
+ getTarget(dir); //Function: get target given a direction - "next" or "prev" parameter
+}
+
+interface FlexSliderOptions {
+ namespace?: string; //{NEW} String: Prefix string attached to the class of every element generated by the plugin
+ selector?: string; //{NEW} Selector: Must match a simple pattern. '{container} > {slide}' -- Ignore pattern at your own peril
+ animation?: string; //String: Select your animation type, "fade" or "slide"
+ easing?: string; //{NEW} String: Determines the easing method used in jQuery transitions. jQuery easing plugin is supported!
+ direction?: string; //String: Select the sliding direction, "horizontal" or "vertical"
+ reverse?: bool; //{NEW} Boolean: Reverse the animation direction
+ animationLoop?: bool; //Boolean: Should the animation loop? If bool; directionNav will received "disable" classes at either end
+ smoothHeight?: bool; //{NEW} Boolean: Allow height of the slider to animate smoothly in horizontal mode
+ startAt?: number; //Integer: The slide that the slider should start on. Array notation (0 = first slide)
+ slideshow?: bool; //Boolean: Animate slider automatically
+ slideshowSpeed?: number; //Integer: Set the speed of the slideshow cycling, in milliseconds
+ animationSpeed?: number; //Integer: Set the speed of animations, in milliseconds
+ initDelay?: number; //{NEW} Integer: Set an initialization delay, in milliseconds
+ randomize?: bool; //Boolean: Randomize slide order
+
+ // Usability features
+ pauseOnAction?: bool; //Boolean: Pause the slideshow when interacting with control elements, highly recommended.
+ pauseOnHover?: bool; //Boolean: Pause the slideshow when hovering over slider, then resume when no longer hovering
+ useCSS?: bool; //{NEW} Boolean: Slider will use CSS3 transitions if available
+ touch?: bool; //{NEW} Boolean: Allow touch swipe navigation of the slider on touch-enabled devices
+ video?: bool; //{NEW} Boolean: If using video in the slider, will prevent CSS3 3D Transforms to avoid graphical glitches
+
+ // Primary Controls
+ controlNav?: any; //Boolean: Create navigation for paging control of each clide? Note: Leave true for manualControls usage
+ directionNav?: bool; //Boolean: Create navigation for previous/next navigation? (true/false)
+ prevText?: string; //String: Set the text for the "previous" directionNav item
+ nextText?: string; //String: Set the text for the "next" directionNav item
+
+ // Secondary Navigation
+ keyboard?: bool; //Boolean: Allow slider navigating via keyboard left/right keys
+ multipleKeyboard?: bool; //{NEW} Boolean: Allow keyboard navigation to affect multiple sliders. Default behavior cuts out keyboard navigation with more than one slider present.
+ mousewheel?: bool; //{UPDATED} Boolean: Requires jquery.mousewheel.js (https://github.com/brandonaaron/jquery-mousewheel) - Allows slider navigating via mousewheel
+ pausePlay?: bool; //Boolean: Create pause/play dynamic element
+ pauseText?: string; //String: Set the text for the "pause" pausePlay item
+ playText?: string; //String: Set the text for the "play" pausePlay item
+
+ // Special properties
+ controlsContainer?: string; //{UPDATED} Selector: USE CLASS SELECTOR. Declare which container the navigation elements should be appended too. Default container is the FlexSlider element. Example use would be ".flexslider-container". Property is ignored if given element is not found.
+ manualControls?: string; //Selector: Declare custom control navigation. Examples would be ".flex-control-nav li" or "#tabs-nav li img", etc. The number of elements in your controlNav should match the number of slides/tabs.
+ sync?: string; //{NEW} Selector: Mirror the actions performed on this slider with another slider. Use with care.
+ asNavFor?: string; //{NEW} Selector: Internal property exposed for turning the slider into a thumbnail navigation for another slider
+
+ // Carousel Options
+ itemWidth?: number; //{NEW} Integer: Box-model width of individual carousel items, including horizontal borders and padding.
+ itemMargin?: number; //{NEW} Integer: Margin between carousel items.
+ minItems?: number; //{NEW} Integer: Minimum number of carousel items that should be visible. Items will resize fluidly when below this.
+ maxItems?: number; //{NEW} Integer: Maxmimum number of carousel items that should be visible. Items will resize fluidly when above this limit.
+ move?: number; //{NEW} Integer: Number of carousel items that should move on animation. If number; slider will move all visible items.
+
+ // Callback API
+ start?: (slider: SliderObject) => any; //Callback: function(slider) - Fires when the slider loads the first slide
+ before?: (slider: SliderObject) => any; //Callback: function(slider) - Fires asynchronously with each slider animation
+ after?: () => any; //Callback: function(slider) - Fires after each slider animation completes
+ end?: () => any; //Callback: function(slider) - Fires when the slider reaches the last slide (asynchronous)
+ added?: () => any; //{NEW} Callback: function(slider) - Fires after a slide is added
+ removed?: () => any;
+}
+
+
+interface JQuery {
+ flexslider(options?: FlexSliderOptions);
+}
diff --git a/foundation/foundation.d.ts b/foundation/foundation.d.ts
index e36d48952d..fba9752ddd 100644
--- a/foundation/foundation.d.ts
+++ b/foundation/foundation.d.ts
@@ -31,10 +31,33 @@ interface RevealOptions {
animationSpeed?: number;
closeOnBackgroundClick?: bool;
dismissModalClass?: string;
+ /**
+ * The class of the modals background.
+ */
+ bgClass?: string;
open?: () => void;
opened?: () => void;
close?: () => void;
closed?: () => void;
+ /**
+ * The modals background object.
+ */
+ bg: JQuery;
+ /**
+ * The css property for when the modal is opened and closed.
+ */
+ css: {
+ open: {
+ opacity?: number;
+ visibility?: string;
+ display: string;
+ };
+ close: {
+ opacity: number;
+ visibility: string;
+ display: string;
+ };
+ };
}
interface JoyrideOptions {
diff --git a/gamepad/gamepad-tests.ts b/gamepad/gamepad-tests.ts
new file mode 100644
index 0000000000..7491d7970e
--- /dev/null
+++ b/gamepad/gamepad-tests.ts
@@ -0,0 +1,72 @@
+///
+
+
+()=>{
+ function runAnimation()
+ {
+ window.requestAnimationFrame(runAnimation);
+
+ var gamepads = navigator.getGamepads();
+
+ for (var i = 0; i < gamepads.length; ++i)
+ {
+ var pad = gamepads[i];
+ // todo; simple demo of displaying pad.axes and pad.buttons
+ }
+ }
+
+ window.requestAnimationFrame(runAnimation);
+};
+
+()=>{
+ window.addEventListener('GamepadConnected', (e: GamepadEvent)=>{
+ console.log('Gamepad ' + e.gamepad.index + ' connected!');
+ }, false);
+ window.addEventListener('GamepadDisconnected', (e: GamepadEvent)=>{
+ console.log('Gamepad ' + e.gamepad.index + ' disconnected!');
+ }, false);
+ window.addEventListener('webkitGamepadConnected', (e: GamepadEvent)=>{
+ console.log('Gamepad ' + e.gamepad.index + ' connected!');
+ }, false);
+ window.addEventListener('webkitGamepadDisconnected', (e: GamepadEvent)=>{
+ console.log('Gamepad ' + e.gamepad.index + ' disconnected!');
+ }, false);
+ window.addEventListener('mozGamepadConnected', (e: GamepadEvent)=>{
+ console.log('Gamepad ' + e.gamepad.index + ' connected!');
+ }, false);
+ window.addEventListener('mozGamepadDisconnected', (e: GamepadEvent)=>{
+ console.log('Gamepad ' + e.gamepad.index + ' disconnected!');
+ }, false);
+
+ var requestAnimationFrame = window.requestAnimationFrame || window["mozRequestAnimationFrame"];
+ var getGamepads = navigator.getGamepads || navigator.webkitGetGamepads;
+ if(getGamepads){
+ function runAnimation()
+ {
+ requestAnimationFrame.call(window, runAnimation);
+
+ var gamepads: GamepadList = getGamepads.call(navigator);
+ for(var i = 0; i < gamepads.length; i++){
+ var pad: Gamepad = gamepads[i];
+ if(pad){
+ for (var k = 0; k < pad.buttons.length; k++)
+ {
+ var button = pad.buttons[k];
+ if(button !== 0){
+ console.log('pad[' + pad.index + ']: ' + 'time=' + pad.timestamp + ' id="' + pad.id + '" button[' + k + '] = ' + button);
+ }
+ }
+ for (var k = 0; k < pad.axes.length; k++)
+ {
+ var axis = pad.axes[k];
+ if(Math.abs(axis) > 0.1){
+ console.log('pad[' + pad.index + ']: ' + 'time=' + pad.timestamp + ' id="' + pad.id + '" axis[' + k + '] = ' + axis);
+ }
+ }
+ }
+ }
+ }
+
+ runAnimation();
+ }
+}();
\ No newline at end of file
diff --git a/gamepad/gamepad.d.ts b/gamepad/gamepad.d.ts
new file mode 100644
index 0000000000..833b714344
--- /dev/null
+++ b/gamepad/gamepad.d.ts
@@ -0,0 +1,78 @@
+// Type definitions for Gamepad API
+// Project: http://www.w3.org/TR/gamepad/
+// Definitions by: Kon
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+/**
+ * This interface defines an individual gamepad device.
+ */
+interface Gamepad{
+ /**
+ * An identification string for the gamepad. This string identifies the brand or style of connected gamepad device. Typically, this will include the USB vendor and a product ID.
+ * @readonly
+ */
+ id:string;
+
+ /**
+ * The index of the gamepad in the Navigator. When multiple gamepads are connected to a user agent, indices must be assigned on a first-come, first-serve basis, starting at zero. If a gamepad is disconnected, previously assigned indices must not be reassigned to gamepads that continue to be connected. However, if a gamepad is disconnected, and subsequently the same or a different gamepad is then connected, index entries must be reused.
+ * @readonly
+ */
+ index:number;
+
+ /**
+ * Last time the data for this gamepad was updated. Timestamp is a monotonically increasing value that allows the author to determine if the axes and button data have been updated from the hardware, relative to a previously saved timestamp.
+ * @readonly
+ */
+ timestamp:number;
+
+ /**
+ * Array of values for all axes of the gamepad. All axis values must be linearly normalized to the range [-1.0 .. 1.0]. As appropriate, -1.0 should correspond to "up" or "left", and 1.0 should correspond to "down" or "right". Axes that are drawn from a 2D input device should appear next to each other in the axes array, X then Y. It is recommended that axes appear in decreasing order of importance, such that element 0 and 1 typically represent the X and Y axis of a directional stick.
+ * @readonly
+ */
+ axes:number[];
+
+ /**
+ * Array of values for all buttons of the gamepad. All button values must be linearly normalized to the range [0.0 .. 1.0]. 0.0 must mean fully unpressed, and 1.0 must mean fully pressed. It is recommended that buttons appear in decreasing importance such that the primary button, secondary button, tertiary button, and so on appear as elements 0, 1, 2, ... in the buttons array.
+ * @readonly
+ */
+ buttons:number[];
+}
+
+/**
+ *
+ */
+interface GamepadEvent extends Event{
+ /**
+ * The single gamepad attribute provides access to the associated gamepad data for this event.
+ * @readonly
+ */
+ gamepad:Gamepad;
+}
+
+interface GamepadList{
+ [index: number]: Gamepad;
+ length: number;
+}
+
+interface Navigator{
+ /**
+ * The currently connected and interacted-with gamepads. Gamepads must only appear in the list if they are currently connected to the user agent, and have been interacted with by the user. Otherwise, they must not appear in the list to avoid a malicious page from fingerprinting the user based on connected devices.
+ * @readonly
+ */
+ getGamepads(): Gamepad[];
+
+ webkitGetGamepads(): GamepadList;
+
+ // Not supported yet :(
+ // mozGetGamepads(): Gamepad[];
+}
+
+/*
+ * @event gamepadconnected
+ * A user agent must dispatch this event type to indicate the user has connected a gamepad. If a gamepad was already connected when the page was loaded, the gamepadconnected event will be dispatched when the user presses a button or moves an axis.
+ */
+
+/*
+ * @event gamepaddisconnected
+ * When a gamepad is disconnected from the user agent, if the user agent has previously dispatched a gamepadconnected event, a gamepaddisconnected event must be dispatched.
+ */
\ No newline at end of file
diff --git a/gamequery/gamequery-tests.ts b/gamequery/gamequery-tests.ts
new file mode 100644
index 0000000000..857a05a484
--- /dev/null
+++ b/gamequery/gamequery-tests.ts
@@ -0,0 +1,282 @@
+///
+
+//Original examples: https://github.com/onaluf/gameQuery/tree/master/tests/human
+
+$(function () {
+ var simpleVerticalAnimation = new $.gameQuery.Animation({ imageURL: "sv.png", type: $.gameQuery.ANIMATION_VERTICAL, numberOfFrame: 4, delta: 32, rate: 300 });
+ var simpleHorizontalAnimation = new $.gameQuery.Animation({ imageURL: "sh.png", type: $.gameQuery.ANIMATION_HORIZONTAL, numberOfFrame: 4, delta: 32, rate: 300 });
+
+ var multiVerticalAnimation = new $.gameQuery.Animation({ imageURL: "mv.png", type: $.gameQuery.ANIMATION_VERTICAL | $.gameQuery.ANIMATION_MULTI, numberOfFrame: 4, delta: 32, rate: 300, distance: 32 });
+ var multiHorizontalAnimation = new $.gameQuery.Animation({ imageURL: "mh.png", type: $.gameQuery.ANIMATION_HORIZONTAL | $.gameQuery.ANIMATION_MULTI, numberOfFrame: 4, delta: 32, rate: 300, distance: 32 });
+
+ var simpleOffsetVerticalAnimation = new $.gameQuery.Animation({ imageURL: "sov.png", type: $.gameQuery.ANIMATION_VERTICAL, offsetx: 100, offsety: 100, numberOfFrame: 4, delta: 32, rate: 300 });
+ var simpleOffsetHorizontalAnimation = new $.gameQuery.Animation({ imageURL: "soh.png", type: $.gameQuery.ANIMATION_HORIZONTAL, offsetx: 100, offsety: 100, numberOfFrame: 4, delta: 32, rate: 300 });
+
+ var multiOffsetVerticalAnimation = new $.gameQuery.Animation({ imageURL: "mov.png", type: $.gameQuery.ANIMATION_VERTICAL | $.gameQuery.ANIMATION_MULTI, offsetx: 100, offsety: 100, numberOfFrame: 4, delta: 32, rate: 300, distance: 32 });
+ var multiOffsetHorizontalAnimation = new $.gameQuery.Animation({ imageURL: "moh.png", type: $.gameQuery.ANIMATION_HORIZONTAL | $.gameQuery.ANIMATION_MULTI, offsetx: 100, offsety: 100, numberOfFrame: 4, delta: 32, rate: 300, distance: 32 });
+
+ var pingpongAnimation = new $.gameQuery.Animation({ imageURL: "rebound.png", type: $.gameQuery.ANIMATION_HORIZONTAL | $.gameQuery.ANIMATION_PINGPONG, numberOfFrame: 9, delta: 64, rate: 60 });
+ var multiPingpongAnimation = new $.gameQuery.Animation({ imageURL: "reboundm.png", type: $.gameQuery.ANIMATION_HORIZONTAL | $.gameQuery.ANIMATION_PINGPONG | $.gameQuery.ANIMATION_MULTI, numberOfFrame: 9, delta: 64, rate: 60, distance: 64 });
+
+ var callbackAnim = new $.gameQuery.Animation({ imageURL: "sv.png", type: $.gameQuery.ANIMATION_VERTICAL | $.gameQuery.ANIMATION_ONCE | $.gameQuery.ANIMATION_CALLBACK, numberOfFrame: 4, delta: 32, rate: 300 });
+ var counter = 0;
+ $("#playground").playground({ height: 64, width: 500 });
+
+ $.playground()
+ .addSprite("simpleVertical", { animation: simpleVerticalAnimation, posx: 0 })
+ .addSprite("simpleHorizontal", { animation: simpleHorizontalAnimation, posx: 34 })
+ .addSprite("multiVertical", { animation: multiVerticalAnimation, posx: 75 })
+ .addSprite("multiHorizontal", { animation: multiHorizontalAnimation, posx: 109 })
+ .addSprite("simpleOffsetVertical", { animation: simpleOffsetVerticalAnimation, posx: 150 })
+ .addSprite("simpleOffsetHorizontal", { animation: simpleOffsetHorizontalAnimation, posx: 184 })
+ .addSprite("multiOffsetVertical", { animation: multiOffsetVerticalAnimation, posx: 225 })
+ .addSprite("multiOffsetHorizontal", { animation: multiOffsetHorizontalAnimation, posx: 259 })
+ .addSprite("pingpong", { animation: pingpongAnimation, posx: 286, width: 64, height: 64 })
+ .addSprite("multiPingpong", { animation: multiPingpongAnimation, posx: 350, width: 64, height: 64 })
+ .addSprite("callback", {
+ animation: callbackAnim, posx: 414, callback: function () {
+ counter++;
+ if (counter > 1) {
+ $("#callback").remove();
+ }
+ }
+ });
+
+ $("#multiVertical").setAnimation(1);
+ $("#multiHorizontal").setAnimation(1);
+ $("#multiOffsetVertical").setAnimation(1);
+ $("#multiOffsetHorizontal").setAnimation(1);
+ $("#multiPingpong").setAnimation(1);
+
+ $.playground().startGame();
+});
+$(function () {
+
+ var red = new $.gameQuery.Animation({
+ imageURL: "red.png",
+ type: $.gameQuery.ANIMATION_HORIZONTAL
+ });
+ var blue = new $.gameQuery.Animation({
+ imageURL: "blue.png",
+ type: $.gameQuery.ANIMATION_HORIZONTAL
+ });
+
+ $("#playground").playground({ height: 450, width: 350 });
+
+ // no group, no translation, no transformation
+ $.playground()
+ .addSprite("a1", { animation: red, width: 30, height: 30, posx: 0, posy: 0 })
+ .addSprite("b1", { animation: red, width: 30, height: 30, posx: 15, posy: 15 });
+
+ // one group, no translation, no transformation
+ $.playground()
+ .addSprite("a2", { animation: red, width: 30, height: 30, posx: 0, posy: 50 })
+ .addGroup("g1", { width: 100, height: 100, posx: -55, posy: -5 })
+ .addSprite("b2", { animation: red, width: 30, height: 30, posx: 70, posy: 70 });
+
+ // no group, absolute translation, no rotation
+ $.playground()
+ .addSprite("a3", { animation: red, width: 30, height: 30, posx: 0, posy: 100 })
+ .addSprite("b3", { animation: red, width: 30, height: 30, posx: 100, posy: 131 });
+ $("#b3").x(15).y(115);
+
+ // no group, relative translation, scale
+ $.playground()
+ .addSprite("a4", { animation: red, width: 30, height: 30, posx: 0, posy: 150 })
+ .addSprite("b4", { animation: red, width: 30, height: 30, posx: 100, posy: 181 });
+ $("#b4").x(-85, true).y(-16, true);
+
+ // no group, no translation, flip
+ $.playground()
+ .addSprite("a5", { animation: red, width: 30, height: 30, posx: 0, posy: 200 })
+ .addSprite("b5", { animation: red, width: 30, height: 30, posx: 15, posy: 215 });
+ $("#a5").flipv();
+ $("#b5").fliph();
+
+ // no group, no translation, rotation
+ $.playground()
+ .addSprite("a6", { animation: red, width: 30, height: 30, posx: 0, posy: 250 })
+ .addSprite("b6", { animation: red, width: 30, height: 30, posx: 30, posy: 265 });
+ $("#b6").rotate(45);
+
+ // no group, no translation, scale
+ $.playground()
+ .addSprite("a7", { animation: red, width: 30, height: 30, posx: 0, posy: 300 })
+ .addSprite("b7", { animation: red, width: 30, height: 30, posx: 30, posy: 315 });
+ $("#b7").scale(1.5);
+
+ // no group, no translation, override
+ $.playground()
+ .addSprite("a8", { animation: red, width: 30, height: 30, posx: 0, posy: 370 })
+ .addSprite("b8", { animation: red, width: 30, height: 30, posx: 40, posy: 385 });
+
+
+
+ // now we try to turn every b* sprites blue
+ $("#a1").collision().each(function () {
+ $(this).setAnimation(blue);
+ });
+
+ $("#a2").collision().each(function () {
+ $(this).setAnimation(blue);
+ });
+
+ $("#a3").collision().each(function () {
+ $(this).setAnimation(blue);
+ });
+
+ $("#a4").collision().each(function () {
+ $(this).setAnimation(blue);
+ });
+
+ $("#a5").collision().each(function () {
+ $(this).setAnimation(blue);
+ });
+
+ $("#a6").collision().each(function () {
+ $(this).setAnimation(blue);
+ });
+
+ $("#a7").collision().each(function () {
+ $(this).setAnimation(blue);
+ });
+
+ $("#a8").collision({ x: 35 }).each(function () {
+ $(this).setAnimation(blue);
+ });
+
+ $.playground().startGame();
+});
+
+$(function () {
+ var multiAnimation = new $.gameQuery.Animation({
+ imageURL: "m.png",
+ type: $.gameQuery.ANIMATION_HORIZONTAL | $.gameQuery.ANIMATION_MULTI,
+ numberOfFrame: 3,
+ delta: 10,
+ distance: 10,
+ rate: 300
+ });
+
+ var multiAnimationPingpong = new $.gameQuery.Animation({
+ imageURL: "m.png",
+ type: $.gameQuery.ANIMATION_HORIZONTAL | $.gameQuery.ANIMATION_MULTI | $.gameQuery.ANIMATION_PINGPONG,
+ numberOfFrame: 3,
+ delta: 10,
+ distance: 10,
+ rate: 300
+ });
+ var animations = [];
+ animations[0] = new $.gameQuery.Animation({
+ imageURL: "s1.png",
+ type: $.gameQuery.ANIMATION_HORIZONTAL,
+ numberOfFrame: 3,
+ delta: 10,
+ rate: 300
+ });
+ animations[1] = new $.gameQuery.Animation({
+ imageURL: "s2.png",
+ type: $.gameQuery.ANIMATION_HORIZONTAL,
+ numberOfFrame: 3,
+ delta: 10,
+ rate: 300
+ });
+ animations[2] = new $.gameQuery.Animation({
+ imageURL: "s3.png",
+ type: $.gameQuery.ANIMATION_HORIZONTAL,
+ numberOfFrame: 3,
+ delta: 10,
+ rate: 300
+ });
+
+ var animationsPingpong = [];
+ animationsPingpong[0] = new $.gameQuery.Animation({
+ imageURL: "s1.png",
+ type: $.gameQuery.ANIMATION_HORIZONTAL | $.gameQuery.ANIMATION_PINGPONG,
+ numberOfFrame: 3,
+ delta: 10,
+ rate: 300
+ });
+ animationsPingpong[1] = new $.gameQuery.Animation({
+ imageURL: "s2.png",
+ type: $.gameQuery.ANIMATION_HORIZONTAL | $.gameQuery.ANIMATION_PINGPONG,
+ numberOfFrame: 3,
+ delta: 10,
+ rate: 300
+ });
+ animationsPingpong[2] = new $.gameQuery.Animation({
+ imageURL: "s3.png",
+ type: $.gameQuery.ANIMATION_HORIZONTAL | $.gameQuery.ANIMATION_PINGPONG,
+ numberOfFrame: 3,
+ delta: 10,
+ rate: 300
+ });
+
+ var tileDef = [[1, 2, 3], [2, 3, 1], [3, 1, 2]];
+ var tileFun = function (i, j) { return 1 + (i + j) % 3; };
+ $("#playground").playground({ height: 64, width: 350 });
+
+ $.playground()
+ .addTilemap("multiArray", tileDef, multiAnimation, { width: 10, height: 10, sizex: 3, sizey: 3, posx: 0 }).end()
+ .addTilemap("multiFunction", tileFun, multiAnimation, { width: 10, height: 10, sizex: 3, sizey: 3, posx: 40 }).end()
+ .addTilemap("arrayArray", tileDef, animations, { width: 10, height: 10, sizex: 3, sizey: 3, posx: 80 }).end()
+ .addTilemap("arrayFunction", tileFun, animations, { width: 10, height: 10, sizex: 3, sizey: 3, posx: 120 }).end()
+ .addTilemap("multiArrayPingpong", tileDef, multiAnimationPingpong, { width: 10, height: 10, sizex: 3, sizey: 3, posx: 160 }).end()
+ .addTilemap("arrayArrayPingpong", tileDef, animationsPingpong, { width: 10, height: 10, sizex: 3, sizey: 3, posx: 200 }).end()
+ .addGroup("testGroup", { height: 30, width: 30, posx: -40 }).addTilemap("outside", tileDef, multiAnimation, { width: 10, height: 10, sizex: 3, sizey: 3, posx: 0 });
+ $("#testGroup").x(240);
+ $.playground().startGame();
+});
+
+$(function () {
+ var multiAnimation = new $.gameQuery.Animation({
+ imageURL: "m.png",
+ type: $.gameQuery.ANIMATION_HORIZONTAL | $.gameQuery.ANIMATION_MULTI,
+ numberOfFrame: 3,
+ delta: 10,
+ distance: 10,
+ rate: 300
+ });
+
+ var tileDef = [[1, 2, 3, 1, 2, 3, 1, 2, 3],
+ [2, 3, 1, 2, 3, 1, 2, 3, 1],
+ [3, 1, 2, 3, 1, 2, 3, 1, 2]];
+
+ $("#playground").playground({ height: 60, width: 90 });
+
+ $.playground()
+ .addGroup("testGroup1", { height: 60, width: 180, posx: 0 })
+ .addTilemap("map1", tileDef, multiAnimation, { width: 10, height: 10, sizex: 9, sizey: 3, posx: 0 }).end()
+ .addTilemap("map2", tileDef, multiAnimation, { width: 10, height: 10, sizex: 9, sizey: 3, posx: 90 }).end()
+ .end()
+ .addGroup("testGroup2", { height: 60, width: 90, posy: 60 })
+ .addTilemap("map3", tileDef, multiAnimation, { width: 10, height: 10, sizex: 9, sizey: 3, posx: 0 });
+
+
+ $("#testGroup1").x(-45);
+ $("#testGroup2").y(30);
+ $.playground().startGame();
+});
+
+$(function () {
+ var animation = new $.gameQuery.Animation({ imageURL: "sh.png", type: $.gameQuery.ANIMATION_HORIZONTAL, numberOfFrame: 4, delta: 32, rate: 300 });
+
+ $("#playground").playground({ height: 64, width: 480 });
+
+ $.playground()
+ .addSprite("rotate", { animation: animation, posx: 0, posy: 16 })
+ .addSprite("scale", { animation: animation, posx: 80, posy: 16 })
+ .addSprite("rotateScale", { animation: animation, posx: 160, posy: 16 })
+ .addSprite("scaleRotate", { animation: animation, posx: 240, posy: 16 })
+ .addSprite("flipH", { animation: animation, posx: 320, posy: 16 })
+ .addSprite("flipV", { animation: animation, posx: 400, posy: 16 })
+
+ $("#rotate").rotate(45);
+ $("#scale").scale(4);
+ $("#scale").scale(0.5, true);
+ $("#rotateScale").rotate(45).scale(2);
+ $("#scaleRotate").scale(2).rotate(45);
+ $("#flipV").flipv(true);
+ $("#flipH").fliph(true);
+ $.playground().startGame();
+});
\ No newline at end of file
diff --git a/gamequery/gamequery.d.ts b/gamequery/gamequery.d.ts
new file mode 100644
index 0000000000..dbb68fca4a
--- /dev/null
+++ b/gamequery/gamequery.d.ts
@@ -0,0 +1,171 @@
+// Type definitions for gameQuery 0.7.0
+// Project: http://gamequeryjs.com/
+// Definitions by: David Laubreiter
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+///
+
+interface PlaygroundOptions{
+ height?: number;
+ width?: number;
+ refreshRate?: number;
+ keyTracker?: bool;
+ mouseTracker?: bool;
+ position?: string;
+ disableCollision?: bool;
+}
+
+interface Coordinate3D{
+ x: number;
+ y: number;
+ z: number;
+}
+
+interface Size{
+ w: number;
+ h: number;
+}
+
+interface SpriteOptions{
+ animation?: any;
+ height?: number;
+ width?: number;
+ posx?: number;
+ posy?: number;
+ callback?: () => any;
+}
+
+interface GroupOptions{
+ overflow?: string;
+ height?: number;
+ width?: number;
+ posx?: number;
+ posy?: number;
+}
+
+interface TileMapOptions{
+ sizex?: number;
+ sizey?: number;
+ height?: number;
+ width?: number;
+ posx?: number;
+ posy?: number;
+ buffer?: number;
+}
+
+interface AnimationOptions{
+ imageURL: string;
+ numberOfFrame?: number;
+ delta?: number;
+ rate?: number;
+ type?: number;
+ distance?: number;
+ offsetx?: number;
+ offsety?: number;
+}
+
+interface Animation{
+ imageURL: string;
+ numberOfFrame: number;
+ delta: number;
+ rate: number;
+ type: number;
+ distance: number;
+ offsetx: number;
+ offsety: number;
+
+ new (options: AnimationOptions): Animation;
+}
+
+interface GameQuery {
+ ANIMATION_VERTICAL: number;
+ ANIMATION_HORIZONTAL: number;
+ ANIMATION_ONCE: number;
+ ANIMATION_CALLBACK: number;
+ ANIMATION_MULTI: number;
+ ANIMATION_PINGPONG: number;
+
+ Animation: Animation;
+
+ keyTracker: bool[];
+
+ spriteCssClass: string;
+ groupCssClass: string;
+ tilemapCssClass: string;
+ tileCssClass: string;
+ tileTypePrefix: string;
+ tileIdPrefix: string;
+}
+
+interface JQuery{
+ playground(options?: PlaygroundOptions): JQuery;
+
+ collision(query?: any): JQuery;
+
+ startGame(callback?: () => void): JQuery;
+ pauseGame(): JQuery;
+ resumeGame(callback?: () => void ): JQuery;
+
+ registerCallback(callback: () => void , rate: number): JQuery;
+ registerCallback(callback: () => number , rate: number): JQuery;
+ registerCallback(callback: () => bool , rate: number): JQuery;
+
+ clearScenegraph(): JQuery;
+ clearAll(clearCallbacks?: bool): JQuery;
+
+ loadCallback(callback: (percent: number) => void ): JQuery;
+
+ rotate(angle: number, relative?: bool): JQuery;
+ scale(ratio: number, relative?: bool): JQuery;
+ flipv(flip?: bool): JQuery;
+ fliph(flip?: bool): JQuery;
+
+ xyz(x: number, y: number, z: number, relative?: bool): JQuery;
+ xyz(): Coordinate3D;
+
+ xy(x: number, y: number, relative?: bool): JQuery;
+ xy(): Coordinate3D;
+
+ x(value: number, relative?: bool): JQuery;
+ x(): number;
+
+ y(value: number, relative?: bool): JQuery;
+ y(): number;
+
+ z(value: number, relative?: bool): JQuery;
+ z(): number;
+
+ wh(width: number, height: number, relative?: bool): JQuery;
+ wh(): Size;
+
+ w(value: number, relative?: bool): JQuery;
+ w(): number;
+
+ h(value: number, relative?: bool): JQuery;
+ h(): number;
+
+ addSprite(name: string, options: SpriteOptions): JQuery;
+ addGroup(name: string, options: GroupOptions): JQuery;
+
+ addTilemap(name: string, tileDescription: number[][], animationList : Animation[], options: TileMapOptions) : JQuery;
+ addTilemap(name: string, tileDescription: number[][], animation : Animation, options: TileMapOptions) : JQuery;
+ addTilemap(name: string, tileDescription: (i: number, j: number) => number, animationList : Animation[], options: TileMapOptions) : JQuery;
+ addTilemap(name: string, tileDescription: (i: number, j: number) => number, animation : Animation, options: TileMapOptions) : JQuery;
+
+
+ gQ: GameQuery;
+
+ setAnimation(animation: Animation, callback?: () => any): JQuery;
+ setAnimation(animation: number, callback?: () => any): JQuery;
+ setAnimation(): JQuery;
+
+ pauseAnimation(): JQuery;
+ resumeAnimation(): JQuery;
+}
+
+interface JQueryStatic{
+ playground(): JQuery;
+
+ gQ: GameQuery;
+ gameQuery: GameQuery;
+}
diff --git a/globalize/globalize.d.ts b/globalize/globalize.d.ts
index 902236ced0..8b4a1ce97a 100644
--- a/globalize/globalize.d.ts
+++ b/globalize/globalize.d.ts
@@ -110,11 +110,11 @@ class GlobalizeStatic {
addCultureInfo(cultureName, baseCultureName, info? );
findClosestCulture(cultureSelector: string);
format(value, format, cultureSelector? );
- localize(key, cultureSelector);
+ localize(key, cultureSelector?);
parseDate(value: string, formats? , cultureSelector?: string): Date;
parseInt(value: string, radix? , cultureSelector?: string): number;
parseFloat(value: string, radix? , cultureSelector?: string): number;
}
-declare var Globalize: GlobalizeStatic;
\ No newline at end of file
+declare var Globalize: GlobalizeStatic;
diff --git a/google.analytics/ga-tests.ts b/google.analytics/ga-tests.ts
new file mode 100644
index 0000000000..03d5c2ed50
--- /dev/null
+++ b/google.analytics/ga-tests.ts
@@ -0,0 +1,76 @@
+///
+///
+
+describe("tester Google Analytics Tracker _gat object", () => {
+
+ it("can set ga script element", () => {
+ ga = document.createElement("script");
+ });
+
+ it("can set aync to true", () => {
+ ga.async = true;
+ });
+
+ it("can set src to string url", () => {
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';;
+ });
+
+ it("can set type", () => {
+ ga.type = 'text/javascript';
+ });
+
+
+});
+
+describe("tester Google Analytics Tracker _gat object", () => {
+ it("can create _createTracker", () => {
+ _gat._createTracker('UA-65432-1');
+ _gat._createTracker('UA-65432-2', 't2');
+ });
+
+ it("can create _getTrackerByName", () => {
+ _gat._getTrackerByName();
+ _gat._getTrackerByName('t2');
+ });
+
+ it("can create _anonymizeIp", () => {
+ _gat._anonymizeIp();
+ });
+
+});
+
+describe("tester Google Analytics Code _gaq object", () => {
+ it("can create _push", () => {
+ _gaq.push(['_setAccount', 'UA-XXXXXXX-YY']);
+ _gaq.push(['_gat._anonymizeIp']);
+ _gaq.push(['_trackPageview']);
+
+ _gaq.push(() => {
+ var tracker = _gat._getTrackerByName('UA-65432-1');
+ tracker._trackPageview();
+ }
+ );
+ });
+});
+
+
+describe("tester Google Analytics Code Tracker object", () => {
+ it("can create Tracker object and call methods", () => {
+ var tracker = _gat._getTrackerByName('UA-65432-1');
+ tracker._trackPageview();
+ tracker._getName();
+ tracker._getAccount();
+ tracker._getVersion();
+ tracker._getVisitorCustomVar(0);
+ tracker._setAccount();
+ tracker._setCustomVar(0, "name", "value", 1);
+ tracker._setSampleRate("80");
+ tracker._setSessionCookieTimeout(1800000);
+ tracker._setSiteSpeedSampleRate(5);
+ tracker._setVisitorCookieTimeout(63072000000);
+ tracker._trackPageLoadTime();
+ });
+});
+
+
+
diff --git a/google.analytics/ga.d.ts b/google.analytics/ga.d.ts
new file mode 100644
index 0000000000..b24bc6649e
--- /dev/null
+++ b/google.analytics/ga.d.ts
@@ -0,0 +1,41 @@
+// Type definitions for Google Analytics
+// Project: https://developers.google.com/analytics/devguides/collection/gajs/
+// Definitions by: Ronnie Haakon Hegelund
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+class Tracker {
+ _trackPageview(): void;
+ _getName(): string;
+ _getAccount(): string;
+ _getVersion(): string;
+ _getVisitorCustomVar(index: number); string;
+ _setAccount(): string;
+ _setCustomVar(index: number, name: string, value: string, opt_scope?: number): bool;
+ _setSampleRate(newRate: string): void;
+ _setSessionCookieTimeout(cookieTimeoutMillis: number): void;
+ _setSiteSpeedSampleRate(sampleRate: number): void;
+ _setVisitorCookieTimeout(milliseconds: number): void;
+ _trackPageLoadTime(): void;
+}
+
+interface GoogleAnalyticsCode {
+ push(commandArray: string[]): void;
+ push(Function): void;
+}
+
+interface GoogleAnalyticsTracker {
+ _getTracker(account: string): Tracker;
+ _createTracker(opt_account: string, opt_name?: string): Tracker;
+ _getTrackerByName(opt_name?: string): Tracker;
+ _anonymizeIp(): void;
+}
+
+interface GoogleAnalytics {
+ type: string;
+ src: string;
+ async: bool;
+}
+
+declare var ga: GoogleAnalytics;
+declare var _gaq: GoogleAnalyticsCode;
+declare var _gat: GoogleAnalyticsTracker;
diff --git a/google.feeds/google.feed.api.d.ts b/google.feeds/google.feed.api.d.ts
new file mode 100644
index 0000000000..386329f40a
--- /dev/null
+++ b/google.feeds/google.feed.api.d.ts
@@ -0,0 +1,79 @@
+//Project Google Feed Apis
+// Project: https://developers.google.com/feed/
+// Definitions by: https://github.com/RodneyJT
+
+declare module google.feeds {
+ export class feed {
+ constructor();
+ constructor(url: string);
+ findFeeds(query?: string, callback?: (result: findResult) => void ): void;
+ getElementsByTagNameNS(node: string, ns: string, localName: string): any[];
+ includeHistoricalEntries(): void;
+ load(callback?: (result: feedResult) => void ): void;
+ setNumEntries(num: number): void;
+ setResultFormat(format: string): void;
+ }
+}
+
+interface feedResult {
+ error?: feedError;
+ xmlDocument?: string;
+ feed: feedJSON;
+}
+
+interface findResult {
+ error?: feedError;
+ xmlDocument?: string;
+ findEntries: findEntry[];
+}
+
+interface feedError {
+ code: string;
+ message: string;
+}
+
+interface feedJSON {
+ feedURL: string;
+ link: string;
+ author: string;
+ description: string;
+ entries: feedEntry[];
+}
+
+interface feedEntry {
+ mediaGroup: MediaGroup[];
+ title: string;
+ link: string;
+ content: string;
+ contentSnippet: string;
+ publishedDate: string;
+ categories: string[];
+}
+
+interface findEntry {
+ title: string;
+ link: string;
+ contentSnippet: string;
+ url: string;
+}
+
+interface MediaGroup {
+ content: MediaContent[];
+}
+
+interface MediaContent {
+ url: string;
+ fileSize: number;
+ type: string;
+ medium: string;
+ isDefault: bool;
+ expression: string;
+ bitrate: number;
+ framerate: number;
+ samplingrate: number;
+ channels: string;
+ duration: number;
+ height: number;
+ width: number;
+ lang: string;
+}
diff --git a/google.geolocation/google.geolocation-tests.ts b/google.geolocation/google.geolocation-tests.ts
new file mode 100644
index 0000000000..f6574cfea4
--- /dev/null
+++ b/google.geolocation/google.geolocation-tests.ts
@@ -0,0 +1,18 @@
+// Test files for Geolocation Definition file
+///
+
+//determine if the handset has client side geo location capabilities
+var isInit: bool = geo_position_js.init();
+if(isInit){
+ geo_position_js.getCurrentPosition(success_callback, error_callback);
+} else {
+ alert("Functionality not available");
+}
+
+function success_callback(position: Position): void {
+ geo_position_js.showMap(position.coords.latitude, position.coords.longitude);
+}
+
+function error_callback(positionError: PositionError): void {
+ console.log(positionError.code);
+}
\ No newline at end of file
diff --git a/google.geolocation/google.geolocation.d.ts b/google.geolocation/google.geolocation.d.ts
new file mode 100644
index 0000000000..5260ba01e4
--- /dev/null
+++ b/google.geolocation/google.geolocation.d.ts
@@ -0,0 +1,12 @@
+// Type definitions for Google Geolocation 0.4.8
+// Project: https://code.google.com/p/geo-location-javascript/
+// Definitions by: Vincent Bortone
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+interface GeolocationStatic {
+ init(): bool;
+ getCurrentPosition(success: (position: Position) => void, error?: (positionError: PositionError) => void, opts?: PositionOptions): void;
+ showMap(latitude: number, longitude: number): void;
+}
+
+declare var geo_position_js: GeolocationStatic;
\ No newline at end of file
diff --git a/googlemaps/google.maps.d.ts b/googlemaps/google.maps.d.ts
index 340387c444..3596da3d49 100644
--- a/googlemaps/google.maps.d.ts
+++ b/googlemaps/google.maps.d.ts
@@ -1123,7 +1123,7 @@ declare module google.maps {
worldSize?: Size;
}
- export interface StreetViewService {
+ export class StreetViewService {
getPanoramaById(pano: string, callback: (streetViewPanoramaData: StreetViewPanoramaData, streetViewStatus: StreetViewStatus) => void );
getPanoramaByLocation(latlng: LatLng, radius: number, callback: (streetViewPanoramaData: StreetViewPanoramaData, streetViewStatus: StreetViewStatus) => void );
}
diff --git a/highcharts/highcharts.d.ts b/highcharts/highcharts.d.ts
index e135847103..ac10279d08 100644
--- a/highcharts/highcharts.d.ts
+++ b/highcharts/highcharts.d.ts
@@ -960,8 +960,8 @@ interface HighchartsOptions {
subtitle?: HighchartsSubtitleOptions;
title?: HighchartsTitleOptions;
tooltip?: HighchartsTooltipOptions;
- xAxis?: HighchartsAxisOptions[];
- yAxis?: HighchartsAxisOptions[];
+ xAxis?: HighchartsAxisOptions;
+ yAxis?: HighchartsAxisOptions;
}
diff --git a/jake/jake-tests.ts b/jake/jake-tests.ts
new file mode 100644
index 0000000000..410764d288
--- /dev/null
+++ b/jake/jake-tests.ts
@@ -0,0 +1,267 @@
+// https://github.com/mde/jake
+///
+
+import path = module("path");
+
+desc('This is the default task.');
+task('default', function (params) {
+ console.log('This is the default task.');
+});
+
+desc('This task has prerequisites.');
+task('hasPrereqs', ['foo', 'bar', 'baz'], function (params) {
+ console.log('Ran some prereqs first.');
+});
+
+desc('This is an asynchronous task.');
+task('asyncTask', {async: true}, function () {
+ setTimeout(complete, 1000);
+});
+
+desc('This builds a minified JS file for production.');
+file('foo-minified.js', ['bar', 'foo-bar.js', 'foo-baz.js'], function () {
+ // Code to concat and minify goes here
+});
+
+desc('This creates the bar directory for use with the foo-minified.js file-task.');
+directory('bar');
+
+desc('This is the default task.');
+task('default', function () {
+ console.log('This is the default task.');
+});
+
+namespace('foo', function () {
+ desc('This the foo:bar task');
+ task('bar', function () {
+ console.log('doing foo:bar task');
+ });
+
+ desc('This the foo:baz task');
+ task('baz', ['default', 'foo:bar'], function () {
+ console.log('doing foo:baz task');
+ });
+
+});
+
+desc('This is an awesome task.');
+task('awesome', function (a, b, c) {
+ console.log(a, b, c);
+});
+
+
+desc('This is an awesome task.');
+task('awesome', function (a, b, c) {
+ console.log(a, b, c);
+ console.log(process.env.qux, process.env.frang);
+});
+
+
+jake.addListener('complete', function () {
+ process.exit();
+});
+
+desc('Calls the foo:bar task and its prerequisites.');
+task('invokeFooBar', function () {
+ // Calls foo:bar and its prereqs
+ jake.Task['foo:bar'].invoke();
+});
+
+desc('Calls the foo:bar task and its prerequisites.');
+task('invokeFooBar', function () {
+ // Calls foo:bar and its prereqs
+ jake.Task['foo:bar'].invoke();
+ // Does nothing
+ jake.Task['foo:bar'].invoke();
+});
+
+desc('Calls the foo:bar task without its prerequisites.');
+task('executeFooBar', function () {
+ // Calls foo:bar without its prereqs
+ jake.Task['foo:baz'].execute();
+});
+
+desc('Calls the foo:bar task without its prerequisites.');
+task('executeFooBar', function () {
+ // Calls foo:bar without its prereqs
+ jake.Task['foo:baz'].execute();
+ // Can keep running this over and over
+ jake.Task['foo:baz'].execute();
+ jake.Task['foo:baz'].execute();
+});
+
+desc('Calls the foo:bar task and its prerequisites.');
+task('invokeFooBar', function () {
+ // Calls foo:bar and its prereqs
+ jake.Task['foo:bar'].invoke();
+ // Does nothing
+ jake.Task['foo:bar'].invoke();
+ // Only re-runs foo:bar, but not its prerequisites
+ jake.Task['foo:bar'].reenable();
+ jake.Task['foo:bar'].invoke();
+});
+
+desc('Calls the foo:bar task and its prerequisites.');
+task('invokeFooBar', function () {
+ // Calls foo:bar and its prereqs
+ jake.Task['foo:bar'].invoke();
+ // Does nothing
+ jake.Task['foo:bar'].invoke();
+ // Re-runs foo:bar and all of its prerequisites
+ jake.Task['foo:bar'].reenable(true);
+ jake.Task['foo:bar'].invoke();
+});
+
+desc('Passes params on to other tasks.');
+task('passParams', function () {
+ var t = jake.Task['foo:bar'];
+ // Calls foo:bar, passing along current args
+ t.invoke.apply(t, arguments);
+});
+
+desc('Calls the async foo:baz task and its prerequisites.');
+task('invokeFooBaz', {async: true}, function () {
+ var t = jake.Task['foo:baz'];
+ t.addListener('complete', function () {
+ console.log('Finished executing foo:baz');
+ // Maybe run some other code
+ // ...
+ // Complete the containing task
+ complete();
+ });
+ // Kick off foo:baz
+ t.invoke();
+});
+
+
+namespace('vronk', function () {
+ task('groo', function () {
+ var t = jake.Task['vronk:zong'];
+ t.addListener('error', function (e) {
+ console.log(e.message);
+ });
+ t.invoke();
+ });
+
+ task('zong', function () {
+ throw new Error('OMFGZONG');
+ });
+});
+
+desc('This task fails.');
+task('failTask', function () {
+ fail('Yikes. Something back happened.');
+});
+
+
+desc('This task fails with an exit-status of 42.');
+task('failTaskQuestionCustomStatus', function () {
+ fail('What is the answer?', 42);
+});
+
+
+declare var sourceDir:string;
+declare var currentDir:string;
+jake.mkdirP('app/views/layouts');
+jake.cpR(path.join(sourceDir, '/templates'), currentDir);
+jake.readdirR('pkg');
+jake.rmRf('pkg');
+
+desc('Runs the Jake tests.');
+task('test', {async: true}, function () {
+ var cmds = [
+ 'node ./tests/parseargs.js'
+ , 'node ./tests/task_base.js'
+ , 'node ./tests/file_task.js'
+ ];
+ jake.exec(cmds, function () {
+ console.log('All tests passed.');
+ complete();
+ }, {printStdout: true});
+});
+
+var ex = jake.createExec(['do_thing.sh'], {printStdout: true});
+ex.addListener('error', function (msg, code) {
+ if (code == 127) {
+ console.log("Couldn't find do_thing script, trying do_other_thing");
+ ex.append('do_other_thing.sh');
+ }
+ else {
+ fail('Fatal error: ' + msg, code);
+ }
+});
+ex.run();
+
+task('echo', {async: true}, function () {
+ jake.exec(['echo "hello"'], function () {
+ jake.logger.log('Done.');
+ complete();
+ }, {printStdout: !jake.program.opts.quiet});
+});
+
+function hoge(){
+ var t = new jake.PackageTask('fonebone', 'v0.1.2112', function () {
+ var fileList = [
+ 'Jakefile'
+ , 'README.md'
+ , 'package.json'
+ , 'lib/*'
+ , 'bin/*'
+ , 'tests/*'
+ ];
+ this.packageFiles.include(fileList);
+ this.needTarGz = true;
+ this.needTarBz2 = true;
+ });
+}
+
+var list = new jake.FileList();
+list.include('foo/*.txt');
+list.include(['bar/*.txt', 'README.md']);
+list.include('Makefile', 'package.json');
+list.exclude('foo/zoobie.txt');
+list.exclude(/foo\/src.*.txt/);
+console.log(list.toArray());
+
+
+var t = new jake.TestTask('fonebone', function () {
+ var fileList = [
+ 'tests/*'
+ , 'lib/adapters/**/test.js'
+ ];
+ this.testFiles.include(fileList);
+ this.testFiles.exclude('tests/helper.js');
+ this.testName = 'testMainAndAdapters';
+});
+
+var assert = require('assert')
+ , tests;
+
+tests = {
+ 'sync test': function () {
+ // Assert something
+ assert.ok(true);
+ }
+, 'async test': function (next) {
+ // Assert something else
+ assert.ok(true);
+ // Won't go next until this is called
+ next();
+ }
+, 'another sync test': function () {
+ // Assert something else
+ assert.ok(true);
+ }
+};
+
+//module.exports = tests;
+
+var p = new jake.NpmPublishTask('jake', [
+ 'Makefile'
+, 'Jakefile'
+, 'README.md'
+, 'package.json'
+, 'lib/*'
+, 'bin/*'
+, 'tests/*'
+]);
\ No newline at end of file
diff --git a/jake/jake.d.ts b/jake/jake.d.ts
new file mode 100644
index 0000000000..ec6f20d2bc
--- /dev/null
+++ b/jake/jake.d.ts
@@ -0,0 +1,388 @@
+// Type definitions for jake
+// Project: https://github.com/mde/jake
+// Definitions by: Kon
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+///
+
+/**
+ * Complets an asynchronous task, allowing Jake's execution to proceed to the next task
+ */
+function complete(): void;
+
+/**
+ * Creates a description for a Jake Task (or FileTask, DirectoryTask). When invoked, the description that iscreated will be associated with whatever Task is created next.
+ * @param description The description for the Task
+ */
+function desc(description:string): void;
+
+/**
+ * Creates a Jake DirectoryTask. Can be used as a prerequisite for FileTasks, or for simply ensuring a directory exists for use with a Task's action.
+ * @param name The name of the DiretoryTask
+ */
+function directory(name:string): jake.DirectoryTask;
+
+
+/**
+ * Causes Jake execution to abort with an error. Allows passing an optional error code, which will be used to set the exit-code of exiting process.
+ * @param err The error to thow when aborting execution. If this argument is an Error object, it will simply be thrown. If a String, it will be used as the error-message. (If it is a multi-line String, the first line will be used as the Error message, and the remaining lines will be used as the error-stack.)
+ */
+function fail(...err:string[]): void;
+function fail(...err:Error[]): void;
+function fail(...err:any[]): void;
+
+/**
+ * Creates a Jake FileTask.
+ * @name name The name of the Task
+ * @param prereqs Prerequisites to be run before this task
+ * @param action The action to perform for this task
+ * @param opts Perform this task asynchronously. If you flag a task with this option, you must call the global `complete` method inside the task's action, for execution to proceed to the next task.
+ */
+function file(name:string, prereqs?:string[], action?:()=>void, opts?:jake.FileTaskOptions): jake.FileTask;
+
+/**
+ * Creates a namespace which allows logical grouping of tasks, and prevents name-collisions with task-names. Namespaces can be nested inside of other namespaces.
+ * @param name The name of the namespace
+ * @param scope The enclosing scope for the namespaced tasks
+ */
+function namespace(name:string, scope:()=>void): void;
+
+/**
+ * @param name The name of the Task
+ * @param prereqs Prerequisites to be run before this task
+ * @param action The action to perform for this task
+ * @param opts
+ */
+function task(name:string, prereqs?:string[], action?:(...params:any[])=>any, opts?:jake.TaskOptions): jake.Task;
+function task(name:string, action?:(...params:any[])=>any, opts?:jake.TaskOptions): jake.Task;
+function task(name:string, opts?:jake.TaskOptions, action?:(...params:any[])=>any): jake.Task;
+
+module jake{
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // File-utils //////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ interface UtilOptions{
+ silent?: bool;
+ }
+
+ /**
+ * The jake.mkdirP utility recursively creates a set of nested directories. It will not throw an error if any of the directories already exists.
+ * https://github.com/substack/node-mkdirp
+ */
+ export function mkdirP(name:string, mode?:string, f?:(er:Error, made:any)=>void): void;
+ export function mkdirP(name:string, f?:(er:Error, made:any)=>void): void;
+
+ /**
+ * The jake.cpR utility does a recursive copy of a file or directory.
+ * Note that this command can only copy files and directories; it does not perform globbing (so arguments like '*.txt' are not possible).
+ * @param path the file/directory to copy,
+ * @param destination the destination.
+ */
+ export function cpR(path:string, destination:string, opts?:UtilOptions, callback?:()=>void): void;
+ export function cpR(path:string, destination:string, callback?:(err:Error)=>void): void;
+
+ /**
+ * The jake.readdirR utility gives you a recursive directory listing, giving you output somewhat similar to the Unix find command. It only works with a directory name, and does not perform filtering or globbing.
+ * @return an array of filepaths for all files in the 'pkg' directory, and all its subdirectories.
+ */
+ export function readdirR(name:string, opts?:UtilOptions): string[];
+
+ /**
+ * The jake.rmRf utility recursively removes a directory and all its contents.
+ */
+ export function rmRf(name:string, opts?:UtilOptions): void;
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // Running shell-commands ////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////////////////////////
+
+ interface ExecOptions{
+ /**
+ * print to stdout, default false
+ */
+
+ printStdout?:bool;
+ /**
+ * print to stderr, default false
+ */
+ printStderr?:bool;
+
+ /**
+ * stop execution on error, default true
+ */
+ breakOnError?:bool;
+ }
+ export function exec(cmds:string[], callback?:()=>void, opts?:ExecOptions);
+
+
+ /**
+ * @event cmdStart When a new command begins to run. Passes one arg, the command being run.
+ * @event cmdEnd When a command finishes. Passes one arg, the command being run.
+ * @event stdout When the stdout for the child-process recieves data. This streams the stdout data. Passes one arg, the chunk of data.
+ * @event stderr When the stderr for the child-process recieves data. This streams the stderr data. Passes one arg, the chunk of data.
+ * @event error When a shell-command
+ */
+ export interface Exec extends EventEmitter{
+ constructor(cmds:string[], callback?:()=>void, opts?:ExecOptions);
+ constructor(cmds:string[], opts?:ExecOptions, callback?:()=>void);
+ constructor(cmds:string, callback?:()=>void, opts?:ExecOptions);
+ constructor(cmds:string, opts?:ExecOptions, callback?:()=>void);
+ append(cmd:string): void;
+ run(): void;
+ }
+
+ export function createExec(cmds:string[], callback?:()=>void, opts?:ExecOptions ):Exec;
+ export function createExec(cmds:string[], opts?:ExecOptions, callback?:()=>void):Exec;
+ export function createExec(cmds:string, callback?:()=>void, opts?:ExecOptions ):Exec;
+ export function createExec(cmds:string, opts?:ExecOptions, callback?:()=>void):Exec;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Logging and output ////////////////////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ interface Logger{
+ log(value:any): void;
+ error(value:any): void;
+ }
+
+ export var logger: Logger;
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // program ////////////////////////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ export var program: {
+ opts: {
+ [name:string]: any;
+ quiet: bool;
+ };
+ taskNames: string[];
+ taskArgs: string[];
+ envVars: { [key:string]: string; };
+ };
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Tasks /////////////////////////////////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+ export interface TaskOptions{
+ /**
+ * Perform this task asynchronously. If you flag a task with this option, you must call the global `complete` method inside the task's action, for execution to proceed to the next task.
+ * @default false
+ */
+ asyc?: bool;
+ }
+
+ /**
+ * A Jake Task
+ *
+ * @event complete
+ */
+ export class Task implements EventEmitter{
+ /**
+ * @name name The name of the Task
+ * @param prereqs Prerequisites to be run before this task
+ * @param action The action to perform for this task
+ * @param opts Perform this task asynchronously. If you flag a task with this option, you must call the global `complete` method inside the task's action, for execution to proceed to the next task.
+ */
+ constructor(name:string, prereqs?:string[], action?:()=>void, opts?:TaskOptions);
+
+ /**
+ * Runs prerequisites, then this task. If the task has already been run, will not run the task again.
+ */
+ invoke(): void;
+
+ /**
+ * Runs this task, without running any prerequisites. If the task has already been run, it will still run it again.
+ */
+ reenable(): void;
+
+ addListener(event: string, listener: Function);
+ on(event: string, listener: Function);
+ once(event: string, listener: Function): void;
+ removeListener(event: string, listener: Function): void;
+ removeAllListener(event: string): void;
+ setMaxListeners(n: number): void;
+ listeners(event: string): { Function; }[];
+ emit(event: string, arg1?: any, arg2?: any): void;
+ }
+
+
+
+ export class DirectoryTask{
+ /**
+ * @param name The name of the directory to create.
+ */
+ constructor(name:string);
+ }
+
+ export interface FileTaskOptions{
+ /**
+ * Perform this task asynchronously. If you flag a task with this option, you must call the global `complete` method inside the task's action, for execution to proceed to the next task.
+ * @default false
+ */
+ asyc?: bool;
+ }
+
+ export class FileTask{
+ /**
+ * @param name The name of the Task
+ * @param prereqs Prerequisites to be run before this task
+ * @param action The action to perform to create this file
+ * @param opts Perform this task asynchronously. If you flag a task with this option, you must call the global `complete` method inside the task's action, for execution to proceed to the next task.
+ */
+ constructor(name:string, prereqs?:string[], action?:()=>void, opts?:FileTaskOptions);
+ }
+
+ interface FileFilter{
+ (filename:string): bool;
+ }
+
+ export class FileList{
+ constructor();
+
+ /**
+ * Includes file-patterns in the FileList. Should be called with one or more
+ * pattern for finding file to include in the list. Arguments should be strings
+ * for either a glob-pattern or a specific file-name, or an array of them
+ */
+ include(files:string[]): void;
+ include(...files:string[]): void;
+
+ /**
+ * Indicates whether a particular file would be filtered out by the current
+ * exclusion rules for this FileList.
+ * @param name The filename to check
+ * @return Whether or not the file should be excluded
+ */
+ shouldExclude(name:string): bool;
+
+ /**
+ * Excludes file-patterns from the FileList. Should be called with one or more
+ * pattern for finding file to include in the list. Arguments can be:
+ * 1. Strings for either a glob-pattern or a specific file-name
+ * 2. Regular expression literals
+ * 3. Functions to be run on the filename that return a true/false
+ */
+ exclude(file:string[]): void;
+ exclude(...file:string[]): void;
+ exclude(file:RegExp[]): void;
+ exclude(...file:RegExp[]): void;
+ exclude(file:FileFilter[]): void;
+ exclude(...file:FileFilter[]): void;
+
+
+ /**
+ * Populates the FileList from the include/exclude rules with a list of
+ * actual files
+ */
+ resolve(): void;
+
+ /**
+ * Convert to a plain-jane array
+ */
+ toArray(): string[];
+
+ /**
+ * Get rid of any current exclusion rules
+ */
+ clearExclude(): void;
+ }
+
+ export class PackageTask{
+ /**
+ * Instantiating a PackageTask creates a number of Jake Tasks that make packaging and distributing your software easy.
+ * @param name The name of the project
+ * @param version The current project version (will be appended to the project-name in the package-archive
+ * @param definition Defines the contents of the package, and format of the package-archive. Will be executed on the instantiated PackageTask (i.e., 'this', will be the PackageTask instance), to set the various instance-propertiess.
+ */
+ constructor(name:string, version:string, definition:()=>void);
+
+ /**
+ * Equivalent to the '-C' command for the `tar` and `jar` commands. ("Change to this directory before adding files.")
+ */
+ archiveChangeDir: string;
+
+ /**
+ * Specifies the files and directories to include in the package-archive. If unset, this will default to the main package directory -- i.e., name + version.
+ */
+ archiveContentDir: string;
+
+ /**
+ * The shell-command to use for creating jar archives.
+ */
+ jarCommand: string;
+
+ /**
+ * Can be set to point the `jar` utility at a manifest file to use in a .jar archive. If unset, one will be automatically created by the `jar` utility. This path should be relative to the root of the package directory (this.packageDir above, likely 'pkg')
+ */
+ manifestFile: string;
+
+ /**
+ * The name of the project
+ */
+ name: string;
+
+ /**
+ * If set to true, uses the `jar` utility to create a .jar archive of the pagckage
+ */
+ needJar: bool;
+
+ /**
+ * If set to true, uses the `tar` utility to create a gzip .tgz archive of the pagckage
+ */
+ needTar: bool;
+
+ /**
+ * If set to true, uses the `tar` utility to create a bzip2 .bz2 archive of the pagckage
+ */
+ needTarBz2: bool;
+
+ /**
+ * If set to true, uses the `zip` utility to create a .zip archive of the pagckage
+ */
+ needZip: bool;
+
+ /**
+ * The list of files and directories to include in the package-archive
+ */
+ packageFiles: FileList;
+
+ /**
+ * The shell-command to use for creating tar archives.
+ */
+ tarCommand: string;
+
+ /**
+ * The project version-string
+ */
+ version: string;
+
+ /**
+ * The shell-command to use for creating zip archives.
+ */
+ zipCommand: string;
+
+ }
+
+ export class TestTask{
+ constructor(name:string, definition?:()=>void);
+ }
+
+ export class NpmPublishTask{
+ constructor(name:string, packageFiles:string[]);
+ }
+
+ export function addListener(event: string, listener: Function);
+ export function on(event: string, listener: Function);
+ export function once(event: string, listener: Function): void;
+ export function removeListener(event: string, listener: Function): void;
+ export function removeAllListener(event: string): void;
+ export function setMaxListeners(n: number): void;
+ export function listeners(event: string): { Function; }[];
+ export function emit(event: string, arg1?: any, arg2?: any): void;
+}
\ No newline at end of file
diff --git a/jasmine/jasmine-tests.ts b/jasmine/jasmine-tests.ts
index 32339676a6..46507d68de 100644
--- a/jasmine/jasmine-tests.ts
+++ b/jasmine/jasmine-tests.ts
@@ -60,7 +60,7 @@ describe("Included matchers:", () => {
foo: 'foo'
};
expect(a.foo).toBeDefined();
- expect(a.bar).not.toBeDefined();
+ expect((a).bar).not.toBeDefined();
});
it("The `toBeUndefined` matcher compares against `undefined`", () => {
@@ -68,7 +68,7 @@ describe("Included matchers:", () => {
foo: 'foo'
};
expect(a.foo).not.toBeUndefined();
- expect(a.bar).toBeUndefined();
+ expect((a).bar).toBeUndefined();
});
it("The 'toBeNull' matcher compares against null", () => {
@@ -120,7 +120,7 @@ describe("Included matchers:", () => {
return 1 + 2;
};
var bar = () => {
- return a + 1;
+ //return a + 1;
};
expect(foo).not.toThrow();
expect(bar).toThrow();
@@ -439,7 +439,7 @@ describe("Asynchronous specs", () => {
currentWindowOnload(null);
}
- document.querySelector('.version').innerHTML = jasmineEnv.versionString();
+ (document.querySelector('.version')).innerHTML = jasmineEnv.versionString();
execJasmine();
};
diff --git a/jasmine/jasmine.d.ts b/jasmine/jasmine.d.ts
index 0d16559e92..05e4370040 100644
--- a/jasmine/jasmine.d.ts
+++ b/jasmine/jasmine.d.ts
@@ -7,7 +7,8 @@
declare function describe(description: string, specDefinitions: Function): void;
declare function xdescribe(description: string, specDefinitions: Function): void;
-declare function it(expectation: string, assertion: Function): void;
+declare function it(expectation: string, assertion: () => void ): void;
+declare function it(expectation: string, assertion: (done: (err?) => void) => void ): void;
declare function xit(expectation: string, assertion: Function): void;
declare function beforeEach(action: Function): void;
@@ -23,7 +24,6 @@ declare function runs(asyncMethod: Function): void;
declare function waitsFor(latchMethod: () => bool, failureMessage: string, timeout?: number): void;
declare function waits(timeout?: number): void;
-
declare module jasmine {
var Clock: Clock;
@@ -165,6 +165,8 @@ declare module jasmine {
toBeLessThan(expected): bool;
toBeGreaterThan(expected): bool;
toBeCloseTo(expected, precision): bool;
+ toContainHtml(expected: string): bool;
+ toContainText(expected: string): bool;
toThrow(expected? ): bool;
not: Matchers;
@@ -291,4 +293,6 @@ declare module jasmine {
Clock: Clock;
util: Util;
}
+
+ export var HtmlReporter: any;
}
\ No newline at end of file
diff --git a/jqrangeslider/jqrangeslider-tests.ts b/jqrangeslider/jqrangeslider-tests.ts
index 37ffeb8eff..b4e3875f84 100644
--- a/jqrangeslider/jqrangeslider-tests.ts
+++ b/jqrangeslider/jqrangeslider-tests.ts
@@ -94,7 +94,10 @@ $("#formatterExample").dateRangeSlider({
formatter: (val: Date) => {
var days = val.getDay(),
month = val.getMonth() + 1,
- year = val.getYear();
+ // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getYear#Description
+ // getYear is no longer used and has been replaced by the getFullYear method.
+ // year = val.getYear();
+ year = val.getFullYear();
return days + "/" + month + "/" + year;
}
});
diff --git a/jquery.bbq/jquery.bbq-tests.ts b/jquery.bbq/jquery.bbq-tests.ts
new file mode 100644
index 0000000000..1543ae63c8
--- /dev/null
+++ b/jquery.bbq/jquery.bbq-tests.ts
@@ -0,0 +1,1282 @@
+///
+///
+
+
+// ************** Tests to jquery JQueryParam interface
+var myObject = {
+ a: {
+ one: 1,
+ two: 2,
+ three: 3
+ },
+ b: [1,2,3]
+};
+var recursiveEncoded = $.param(myObject);
+var recursiveDecoded = decodeURIComponent($.param(myObject));
+var shallowEncoded = $.param(myObject, true);
+var shallowDecoded = decodeURIComponent(shallowEncoded);
+
+var params = { width:1680, height:1050 };
+var str = jQuery.param(params);
+$("#results").text(str);
+
+// <=1.3.2:
+$.param({ a: [2,3,4] }) // "a=2&a=3&a=4"
+// >=1.4:
+$.param({ a: [2,3,4] }) // "a[]=2&a[]=3&a[]=4"
+
+// <=1.3.2:
+$.param({ a: { b:1,c:2 }, d: [3,4,{ e:5 }] }) // "a=[object+Object]&d=3&d=4&d=[object+Object]"
+// >=1.4:
+$.param({ a: { b:1,c:2 }, d: [3,4,{ e:5 }] }) // "a[b]=1&a[c]=2&d[]=3&d[]=4&d[2][e]=5"
+// *************************************************************
+
+// Not sure why this isn't set by default in qunit.js..
+QUnit.jsDump.HTML = false;
+
+$(function(){ // START CLOSURE
+
+
+var old_jquery = $.fn.jquery < '1.4',
+ is_chrome = /chrome/i.test( navigator.userAgent ),
+ params_init = 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=1',
+ init_url,
+ ajaxcrawlable_init = $.param.fragment.ajaxCrawlable(),
+ aps = Array.prototype.slice;
+
+if ( $.param.querystring() !== params_init || $.param.fragment() !== params_init ) {
+ init_url = window.location.href;
+ init_url = $.param.querystring( init_url, params_init, 2 );
+ init_url = $.param.fragment( init_url, params_init, 2 );
+ window.location.href = init_url;
+}
+
+$('#jq_version').html( $.fn.jquery );
+
+function notice( txt? ) {
+ if ( txt ) {
+ $('#notice').html( txt );
+ } else {
+ $('#notice').hide();
+ }
+};
+
+function run_many_tests(...args: any[]) {
+ var tests = aps.call( arguments ),
+ delay = typeof tests[0] === 'number' && tests.shift(),
+ func_each = $.isFunction( tests[0] ) && tests.shift(),
+ func_done = $.isFunction( tests[0] ) && tests.shift(),
+ result;
+
+ function set_result( i, test ) {
+ result = $.isArray( test )
+ ? func_each.apply( this, test )
+ : $.isFunction( test )
+ ? test( result )
+ : '';
+ };
+
+ if ( delay ) {
+ stop();
+
+ (function loopy(){
+ //test && test.func && test.func( result );
+ if ( tests.length ) {
+ set_result( 0, tests.shift() );
+ setTimeout( loopy, delay );
+ } else {
+ func_done && func_done();
+ start();
+ }
+ })();
+
+ } else {
+ $.each( tests, set_result );
+ func_done && func_done();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+QUnit.module( 'jQuery.param' );
+
+var params_obj = { a:['4','5','6'], b:{x:['7'], y:'8', z:['9','0','true','false','undefined','']}, c:'1' },
+ params_obj_coerce = { a:[4,5,6] },//, b:{x:[7], y:8, z:[9,0,true,false,undefined,'']}, c:1 },
+ params_str = params_init,
+ params_str_old = 'a=4&a=5&a=6&b=[object+Object]&c=1',
+
+ // If a params fragment starts with ! and BBQ is not in ajaxCrawlable mode,
+ // things can get very ugly, very quickly.
+ params_obj_bang = { "!a":['4'], a:['5','6'], b:{x:['7'], y:'8', z:['9','0','true','false','undefined','']}, c:'1' },
+ params_obj_bang_coerce = { "!a":[4], a:[5,6] };//, b:{x:[7], y:8, z:[9,0,true,false,undefined,'']}, c:1 };
+
+test( 'jQuery.param.sorted', function() {
+ var tests = [
+ {
+ obj: {z:1,b:2,ab:3,bc:4,ba:5,aa:6,a1:7,x:8},
+ traditional: false,
+ expected: 'a1=7&aa=6&ab=3&b=2&ba=5&bc=4&x=8&z=1'
+ },
+ {
+ obj: {z:1,b:[6,5,4],x:2,a:[3,2,1]},
+ traditional: false,
+ expected: 'a[]=3&a[]=2&a[]=1&b[]=6&b[]=5&b[]=4&x=2&z=1',
+ expected_old: 'a=3&a=2&a=1&b=6&b=5&b=4&x=2&z=1'
+ },
+ {
+ obj: {z:1,b:[6,5,4],x:2,a:[3,2,1]},
+ traditional: true,
+ expected: 'a=3&a=2&a=1&b=6&b=5&b=4&x=2&z=1'
+ },
+ {
+ obj: {a:[[4,[5,6]],[[7,8],9]]},
+ traditional: false,
+ expected: 'a[0][]=4&a[0][1][]=5&a[0][1][]=6&a[1][0][]=7&a[1][0][]=8&a[1][]=9',
+ expected_old: 'a=4,5,6&a=7,8,9' // obviously not great, but that's the way jQuery used to roll
+ }
+ ];
+
+ if ( $.fn.jquery != '1.4.1' ) {
+ // this explodes in jQuery 1.4.1
+ tests.push({
+ obj: {z:1,'b[]':[6,5,4],x:2,'a[]':[3,2,1]},
+ obj_alt: {z:1,b:[6,5,4],x:2,a:[3,2,1]},
+ traditional: false,
+ expected: 'a[]=3&a[]=2&a[]=1&b[]=6&b[]=5&b[]=4&x=2&z=1'
+ });
+ }
+
+ expect( tests.length * 2 + 6 );
+
+ $.each( tests, function(i,test){
+ var unsorted = $.param( test.obj, test.traditional ),
+ sorted = $.param.sorted( test.obj, test.traditional );
+
+ equal( decodeURIComponent( sorted ), old_jquery && test.expected_old || test.expected, 'params should be sorted' );
+ deepEqual( $.deparam( unsorted, true ), $.deparam( sorted, true ), 'sorted params should deparam the same as unsorted params' )
+ });
+
+ equal( $.param.fragment( 'foo', '#b=2&a=1' ), 'foo#a=1&b=2', 'params should be sorted' );
+ equal( $.param.fragment( 'foo', '#b=2&a=1', 1 ), 'foo#a=1&b=2', 'params should be sorted' );
+ equal( $.param.fragment( 'foo', '#b=2&a=1', 2 ), 'foo#b=2&a=1', 'params should NOT be sorted' );
+ equal( $.param.fragment( 'foo#c=3&a=4', '#b=2&a=1' ), 'foo#a=1&b=2&c=3', 'params should be sorted' );
+ equal( $.param.fragment( 'foo#c=3&a=4', '#b=2&a=1', 1 ), 'foo#a=4&b=2&c=3', 'params should be sorted' );
+ equal( $.param.fragment( 'foo#c=3&a=4', '#b=2&a=1', 2 ), 'foo#b=2&a=1', 'params should NOT be sorted' );
+
+});
+
+test( 'jQuery.param.querystring', function() {
+ expect( 11 );
+
+ equal( $.param.querystring( 'http://example.com/' ), '', 'properly identifying params' );
+ equal( $.param.querystring( 'http://example.com/?foo' ),'foo', 'properly identifying params' );
+ equal( $.param.querystring( 'http://example.com/?foo#bar' ),'foo', 'properly identifying params' );
+ equal( $.param.querystring( 'http://example.com/?foo#bar?baz' ),'foo', 'properly identifying params' );
+ equal( $.param.querystring( 'http://example.com/#foo' ),'', 'properly identifying params' );
+ equal( $.param.querystring( 'http://example.com/#foo?bar' ),'', 'properly identifying params' );
+
+ equal( $.param.querystring(), params_str, 'params string from window.location' );
+ equal( $.param.querystring( '?' + params_str ), params_str, 'params string from url' );
+ equal( $.param.querystring( 'foo.html?' + params_str ), params_str, 'params string from url' );
+ equal( $.param.querystring( 'http://a:b@example.com:1234/foo.html?' + params_str ), params_str, 'params string from url' );
+ equal( $.param.querystring( 'http://a:b@example.com:1234/foo.html?' + params_str + '#bippity-boppity-boo' ), params_str, 'params string from url' );
+});
+
+test( 'jQuery.param.querystring - build URL', function() {
+ expect( 10 );
+
+ function fake_encode( params_str ) {
+ return '?' + $.map( params_str.split('&'), encodeURIComponent ).join('&').replace( /%3D/g, '=' ).replace( /%2B/g, '+' );
+ }
+
+ var pre = 'http://a:b@example.com:1234/foo.html',
+ post = '#get-on-the-floor',
+ current_url = pre + post;
+
+ run_many_tests(
+
+ // execute this for each array item
+ function(){
+ current_url = $.param.querystring.apply( this, [ current_url ].concat( aps.call( arguments ) ) );
+ },
+
+ // tests:
+
+ [ { a:'2' } ],
+
+ function(result){
+ equal( current_url, pre + '?a=2' + post, '$.param.querystring( url, Object )' );
+ },
+
+ [ { b:'2' } ],
+
+ function(result){
+ equal( current_url, pre + '?a=2&b=2' + post, '$.param.querystring( url, Object )' );
+ },
+
+ [ { c:true, d:false, e:'undefined', f:'' } ],
+
+ function(result){
+ equal( current_url, pre + '?a=2&b=2&c=true&d=false&e=undefined&f=' + post, '$.param.querystring( url, Object )' );
+ },
+
+ [ { a:[4,5,6]}],//, b:{x:[7], y:8, z:[9,0,'true','false','undefined','']} }, 2 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=';
+
+ equal( current_url, pre + fake_encode( params ) + post, '$.param.querystring( url, Object, 2 )' );
+ },
+
+ [ { a:'1', c:'2' }, 1 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&c=2'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=2';
+
+ equal( current_url, pre + fake_encode( params ) + post, '$.param.querystring( url, Object, 1 )' );
+ },
+
+ [ 'foo=1' ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&c=2&foo=1'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=2&foo=1';
+
+ equal( current_url, pre + fake_encode( params ) + post, '$.param.querystring( url, String )' );
+ },
+
+ [ 'foo=2&bar=3', 1 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&bar=3&c=2&foo=1'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&bar=3&c=2&foo=1';
+
+ equal( current_url, pre + fake_encode( params ) + post, '$.param.querystring( url, String, 1 )' );
+ },
+
+ [ 'http://example.com/test.html?/path/to/file.php#the-cow-goes-moo', 2 ],
+
+ function(result){
+ equal( current_url, pre + '?/path/to/file.php' + post, '$.param.querystring( url, String, 2 )' );
+ },
+
+ [ '?another-example', 2 ],
+
+ function(result){
+ equal( current_url, pre + '?another-example' + post, '$.param.querystring( url, String, 2 )' );
+ },
+
+ [ 'i_am_out_of_witty_strings', 2 ],
+
+ function(result){
+ equal( current_url, pre + '?i_am_out_of_witty_strings' + post, '$.param.querystring( url, String, 2 )' );
+ }
+
+ );
+
+});
+
+test( 'jQuery.param.fragment', function() {
+ expect( 29 );
+
+ equal( $.param.fragment( 'http://example.com/' ), '', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo' ),'', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo#bar' ),'bar', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo#bar?baz' ),'bar?baz', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/#foo' ),'foo', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/#foo?bar' ),'foo?bar', 'properly identifying params' );
+
+ equal( $.param.fragment( 'http://example.com/' ), '', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo' ),'', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo#!bar' ),'!bar', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo#!bar?baz' ),'!bar?baz', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/#!foo' ),'!foo', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/#!foo?bar' ),'!foo?bar', 'properly identifying params' );
+
+ equal( $.param.fragment(), params_str, 'params string from window.location' );
+ equal( $.param.fragment( '#' + params_str ), params_str, 'params string from url' );
+ equal( $.param.fragment( 'foo.html#' + params_str ), params_str, 'params string from url' );
+ equal( $.param.fragment( 'http://a:b@example.com:1234/foo.html#' + params_str ), params_str, 'params string from url' );
+ equal( $.param.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#' + params_str ), params_str, 'params string from url' );
+
+ $.param.fragment.ajaxCrawlable( true );
+
+ equal( $.param.fragment( 'http://example.com/' ), '', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo' ),'', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo#bar' ),'bar', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo#bar?baz' ),'bar?baz', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/#foo' ),'foo', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/#foo?bar' ),'foo?bar', 'properly identifying params' );
+
+ equal( $.param.fragment( 'http://example.com/' ), '', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo' ),'', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo#!bar' ),'bar', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo#!bar?baz' ),'bar?baz', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/#!foo' ),'foo', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/#!foo?bar' ),'foo?bar', 'properly identifying params' );
+
+ $.param.fragment.ajaxCrawlable( false );
+
+});
+
+test( 'jQuery.param.fragment - build URL', function() {
+ expect( 40 );
+
+ function fake_encode( params_str ) {
+ return '#' + $.map( params_str.split('&'), encodeURIComponent ).join('&').replace( /%3D/g, '=' ).replace( /%2B/g, '+' );
+ }
+
+ var pre = 'http://a:b@example.com:1234/foo.html?and-dance-with-me',
+ current_url = pre;
+
+ run_many_tests(
+
+ // execute this for each array item
+ function(){
+ current_url = $.param.fragment.apply( this, [ current_url ].concat( aps.call( arguments ) ) );
+ },
+
+ // tests:
+
+ [ { a:'2' } ],
+
+ function(result){
+ equal( current_url, pre + '#a=2', '$.param.fragment( url, Object )' );
+ },
+
+ [ { b:'2' } ],
+
+ function(result){
+ equal( current_url, pre + '#a=2&b=2', '$.param.fragment( url, Object )' );
+ },
+
+ [ { c:true, d:false, e:'undefined', f:'' } ],
+
+ function(result){
+ equal( current_url, pre + '#a=2&b=2&c=true&d=false&e=undefined&f=', '$.param.fragment( url, Object )' );
+ },
+
+ [ { a:[4,5,6]}],//, b:{x:[7], y:8, z:[9,0,'true','false','undefined','']} }, 2 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=';
+
+ equal( current_url, pre + fake_encode( params ), '$.param.fragment( url, Object, 2 )' );
+ },
+
+ [ { a:'1', c:'2' }, 1 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&c=2'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=2';
+
+ equal( current_url, pre + fake_encode( params ), '$.param.fragment( url, Object, 1 )' );
+ },
+
+ [ 'foo=1' ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&c=2&foo=1'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=2&foo=1';
+
+ equal( current_url, pre + fake_encode( params ), '$.param.fragment( url, String )' );
+ },
+
+ [ 'foo=2&bar=3', 1 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&bar=3&c=2&foo=1'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&bar=3&c=2&foo=1';
+
+ equal( current_url, pre + fake_encode( params ), '$.param.fragment( url, String, 1 )' );
+ },
+
+ [ 'http://example.com/test.html?the-cow-goes-moo#/path/to/file.php', 2 ],
+
+ function(result){
+ equal( current_url, pre + '#/path/to/file.php', '$.param.fragment( url, String, 2 )' );
+ },
+
+ [ '#another-example', 2 ],
+
+ function(result){
+ equal( current_url, pre + '#another-example', '$.param.fragment( url, String, 2 )' );
+ },
+
+ [ 'i_am_out_of_witty_strings', 2 ],
+
+ function(result){
+ equal( current_url, pre + '#i_am_out_of_witty_strings', '$.param.fragment( url, String, 2 )' );
+ }
+
+ );
+
+ $.param.fragment.ajaxCrawlable( true );
+
+ equal( $.param.fragment( 'foo', {} ) , 'foo#!', '$.param.fragment( url, Object )' );
+ equal( $.param.fragment( 'foo', { b:2, a:1 } ) , 'foo#!a=1&b=2', '$.param.fragment( url, Object )' );
+ equal( $.param.fragment( 'foo#', { b:2, a:1 } ) , 'foo#!a=1&b=2', '$.param.fragment( url, Object )' );
+ equal( $.param.fragment( 'foo#!', { b:2, a:1 } ) , 'foo#!a=1&b=2', '$.param.fragment( url, Object )' );
+ equal( $.param.fragment( 'foo#c=3&a=4', { b:2, a:1 } ) , 'foo#!a=1&b=2&c=3', '$.param.fragment( url, Object )' );
+ equal( $.param.fragment( 'foo#!c=3&a=4', { b:2, a:1 } ) , 'foo#!a=1&b=2&c=3', '$.param.fragment( url, Object )' );
+
+ equal( $.param.fragment( 'foo', '' ) , 'foo#!', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo', 'b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#', 'b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#!', 'b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#c=3&a=4', 'b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#!c=3&a=4', 'b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.param.fragment( url, String )' );
+
+ equal( $.param.fragment( 'foo', '#' ) , 'foo#!', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo', '#b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#', '#b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#!', '#b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#c=3&a=4', '#b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#!c=3&a=4', '#b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.param.fragment( url, String )' );
+
+ equal( $.param.fragment( 'foo', '#!' ) , 'foo#!', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo', '#!b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#', '#!b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#!', '#!b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#c=3&a=4', '#!b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#!c=3&a=4', '#!b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.param.fragment( url, String )' );
+
+ $.param.fragment.ajaxCrawlable( false );
+
+ // If a params fragment starts with ! and BBQ is not in ajaxCrawlable mode,
+ // things can get very ugly, very quickly.
+ equal( $.param.fragment( 'foo', '#!' ) , 'foo#!=', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo', '#!b=2&a=1' ) , 'foo#!b=2&a=1', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#', '#!b=2&a=1' ) , 'foo#!b=2&a=1', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#!', '#!b=2&a=1' ) , 'foo#!=&!b=2&a=1', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#c=3&a=4', '#!b=2&a=1' ) , 'foo#!b=2&a=1&c=3', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#!c=3&a=4', '#!b=2&a=1' ) , 'foo#!b=2&!c=3&a=1', '$.param.fragment( url, String )' );
+
+});
+
+test( 'jQuery.param.fragment.ajaxCrawlable', function() {
+ expect( 5 );
+
+ equal( ajaxcrawlable_init, false, 'ajaxCrawlable is disabled by default' );
+ equal( $.param.fragment.ajaxCrawlable( true ), true, 'enabling ajaxCrawlable should return true' );
+ equal( $.param.fragment.ajaxCrawlable(), true, 'ajaxCrawlable is now enabled' );
+ equal( $.param.fragment.ajaxCrawlable( false ), false, 'disabling ajaxCrawlable should return false' );
+ equal( $.param.fragment.ajaxCrawlable(), false, 'ajaxCrawlable is now disabled' );
+});
+
+test( 'jQuery.param.fragment.noEscape', function() {
+ expect( 2 );
+
+ equal( $.param.fragment( '#', { foo: '/a,b@c$d+e&f=g h!' } ), '#foo=/a,b%40c%24d%2Be%26f%3Dg+h!', '/, should be unescaped, everything else but space (+) should be urlencoded' );
+
+ $.param.fragment.ajaxCrawlable( true );
+
+ equal( $.param.fragment( '#', { foo: '/a,b@c$d+e&f=g h!' } ), '#!foo=/a,b%40c%24d%2Be%26f%3Dg+h!', '/, should be unescaped, everything else but ! and space (+) should be urlencoded' );
+
+ $.param.fragment.ajaxCrawlable( false );
+});
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+QUnit.module( 'jQuery.deparam' );
+
+test( 'jQuery.deparam - 1.4-style params', function() {
+ expect( 2 );
+ deepEqual( $.deparam( params_str ), params_obj, '$.deparam( String )' );
+ deepEqual( $.deparam( params_str, true ), params_obj_coerce, '$.deparam( String, true )' );
+});
+
+test( 'jQuery.deparam - pre-1.4-style params', function() {
+ var params_str = 'a=1&a=2&a=3&b=4&c=5&c=6&c=true&c=false&c=undefined&c=&d=7',
+ params_obj = { a:['1','2','3'], b:'4', c:['5','6','true','false','undefined',''], d:'7' },
+ params_obj_coerce = { a:[1,2,3], b:4, c:[5,6,true,false,undefined,''], d:7 };
+
+ expect( 2 );
+ deepEqual( $.deparam( params_str ), params_obj, '$.deparam( String )' );
+ deepEqual( $.deparam( params_str, true ), params_obj_coerce, '$.deparam( String, true )' );
+});
+
+test( 'jQuery.deparam.querystring', function() {
+ expect( 12 );
+
+ deepEqual( $.deparam.querystring(), params_obj, 'params obj from window.location' );
+ deepEqual( $.deparam.querystring( /*true*/ ), params_obj_coerce, 'params obj from window.location, coerced' );
+ deepEqual( $.deparam.querystring( params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.querystring( params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.querystring( '?' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.querystring( '?' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.querystring( 'foo.html?' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.querystring( 'foo.html?' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.querystring( 'http://a:b@example.com:1234/foo.html?' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.querystring( 'http://a:b@example.com:1234/foo.html?' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.querystring( 'http://a:b@example.com:1234/foo.html?' + params_str + '#bippity-boppity-boo' ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.querystring( 'http://a:b@example.com:1234/foo.html?' + params_str + '#bippity-boppity-boo', true ), params_obj_coerce, 'params obj from string, coerced' );
+});
+
+test( 'jQuery.deparam.fragment', function() {
+ expect( 36 );
+
+ deepEqual( $.deparam.fragment(), params_obj, 'params obj from window.location' );
+ deepEqual( $.deparam.fragment( /*true*/ ), params_obj_coerce, 'params obj from window.location, coerced' );
+ deepEqual( $.deparam.fragment( params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+
+ deepEqual( $.deparam.fragment( '#' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( '#' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'foo.html#' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'foo.html#' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html#' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html#' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+
+ // If a params fragment starts with ! and BBQ is not in ajaxCrawlable mode,
+ // things can get very ugly, very quickly.
+ deepEqual( $.deparam.fragment( '#!' + params_str ), params_obj_bang, 'params obj from string' );
+ deepEqual( $.deparam.fragment( '#!' + params_str, true ), params_obj_bang_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'foo.html#!' + params_str ), params_obj_bang, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'foo.html#!' + params_str, true ), params_obj_bang_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html#!' + params_str ), params_obj_bang, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html#!' + params_str, true ), params_obj_bang_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#!' + params_str ), params_obj_bang, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#!' + params_str, true ), params_obj_bang_coerce, 'params obj from string, coerced' );
+
+ $.param.fragment.ajaxCrawlable( true );
+
+ deepEqual( $.deparam.fragment( '#' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( '#' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'foo.html#' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'foo.html#' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html#' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html#' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+
+ deepEqual( $.deparam.fragment( '#!' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( '#!' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'foo.html#!' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'foo.html#!' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html#!' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html#!' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#!' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#!' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+
+ $.param.fragment.ajaxCrawlable( false );
+});
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+QUnit.module( 'jQuery.fn' );
+
+$.elemUrlAttr({ span: 'arbitrary_attr' });
+var test_elems = 'a form link span'.split(' ');
+
+function init_url_attr( container, url ) {
+ var container = $('').hide().appendTo('body');
+ $.each( test_elems, function(i,v){
+ $('<' + v + '/>')
+ .attr( $.elemUrlAttr()[ v ], url )
+ .appendTo( container );
+ });
+ return container;
+};
+
+function test_url_attr( container ) {
+ var url;
+
+ $.each( test_elems, function(i,v){
+ var val = container.children( v ).attr( $.elemUrlAttr()[ v ] );
+ if ( !url ) {
+ url = val;
+ } else if ( val !== url ) {
+ url = -1;
+ }
+ });
+
+ return url;
+};
+
+test( 'jQuery.fn.querystring', function() {
+ expect( 60 );
+
+ function fake_encode( params_str ) {
+ return '?' + $.map( params_str.split('&'), encodeURIComponent ).join('&').replace( /%3D/g, '=' ).replace( /%2B/g, '+' );
+ }
+
+ var pre = 'http://a:b@example.com:1234/foo.html',
+ post = '#get-on-the-floor',
+ current_url = pre + post;
+
+ run_many_tests(
+
+ // execute this for each array item
+ function(){
+ var container,
+ elems;
+
+ container = init_url_attr( container, current_url );
+ elems = container.children('span');
+ equal( elems.length, 1, 'select the correct elements' );
+ equal( elems.querystring.apply( elems, [ 'arbitrary_attr' ].concat( aps.call( arguments ) ) ), elems, 'pass query string' );
+
+ container = init_url_attr( container, current_url );
+ elems = container.children('a, link');
+ equal( elems.length, 2, 'select the correct elements' );
+ equal( elems.querystring.apply( elems, [ 'href' ].concat( aps.call( arguments ) ) ), elems, 'pass query string' );
+
+ container = init_url_attr( container, current_url );
+ elems = container.children();
+ equal( elems.querystring.apply( elems, aps.call( arguments ) ), elems, 'pass query string' );
+
+ current_url = test_url_attr( container );
+ },
+
+ // tests:
+
+ [ { a:'2' } ],
+
+ function(result){
+ equal( current_url, pre + '?a=2' + post, '$.fn.querystring( url, Object )' );
+ },
+
+ [ { b:'2' } ],
+
+ function(result){
+ equal( current_url, pre + '?a=2&b=2' + post, '$.fn.querystring( url, Object )' );
+ },
+
+ [ { c:true, d:false, e:'undefined', f:'' } ],
+
+ function(result){
+ equal( current_url, pre + '?a=2&b=2&c=true&d=false&e=undefined&f=' + post, '$.fn.querystring( url, Object )' );
+ },
+
+ [ { a:[4,5,6]}],//, b:{x:[7], y:8, z:[9,0,'true','false','undefined','']} }, 2 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=';
+
+ equal( current_url, pre + fake_encode( params ) + post, '$.fn.querystring( url, Object, 2 )' );
+ },
+
+ [ { a:'1', c:'2' }, 1 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&c=2'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=2';
+
+ equal( current_url, pre + fake_encode( params ) + post, '$.fn.querystring( url, Object, 1 )' );
+ },
+
+ [ 'foo=1' ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&c=2&foo=1'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=2&foo=1';
+
+ equal( current_url, pre + fake_encode( params ) + post, '$.fn.querystring( url, String )' );
+ },
+
+ [ 'foo=2&bar=3', 1 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&bar=3&c=2&foo=1'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&bar=3&c=2&foo=1';
+
+ equal( current_url, pre + fake_encode( params ) + post, '$.fn.querystring( url, String, 1 )' );
+ },
+
+ [ 'http://example.com/test.html?/path/to/file.php#the-cow-goes-moo', 2 ],
+
+ function(result){
+ equal( current_url, pre + '?/path/to/file.php' + post, '$.fn.querystring( url, String, 2 )' );
+ },
+
+ [ '?another-example', 2 ],
+
+ function(result){
+ equal( current_url, pre + '?another-example' + post, '$.fn.querystring( url, String, 2 )' );
+ },
+
+ [ 'i_am_out_of_witty_strings', 2 ],
+
+ function(result){
+ equal( current_url, pre + '?i_am_out_of_witty_strings' + post, '$.fn.querystring( url, String, 2 )' );
+ }
+
+ );
+
+});
+
+test( 'jQuery.fn.fragment', function() {
+ expect( 240 );
+
+ function fake_encode( params_str ) {
+ return '#' + $.map( params_str.split('&'), encodeURIComponent ).join('&').replace( /%3D/g, '=' ).replace( /%2B/g, '+' );
+ }
+
+ var pre = 'http://a:b@example.com:1234/foo.html?and-dance-with-me',
+ current_url = pre;
+
+ run_many_tests(
+
+ // execute this for each array item
+ function( params, merge_mode ){
+ current_url = test_fn_fragment( current_url, params, merge_mode );
+ },
+
+ // tests:
+
+ [ { a:'2' } ],
+
+ function(result){
+ equal( current_url, pre + '#a=2', '$.fn.fragment( url, Object )' );
+ },
+
+ [ { b:'2' } ],
+
+ function(result){
+ equal( current_url, pre + '#a=2&b=2', '$.fn.fragment( url, Object )' );
+ },
+
+ [ { c:true, d:false, e:'undefined', f:'' } ],
+
+ function(result){
+ equal( current_url, pre + '#a=2&b=2&c=true&d=false&e=undefined&f=', '$.fn.fragment( url, Object )' );
+ },
+
+ [ { a:[4,5,6]}],//, b:{x:[7], y:8, z:[9,0,'true','false','undefined','']} }, 2 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=';
+
+ equal( current_url, pre + fake_encode( params ), '$.fn.fragment( url, Object, 2 )' );
+ },
+
+ [ { a:'1', c:'2' }, 1 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&c=2'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=2';
+
+ equal( current_url, pre + fake_encode( params ), '$.fn.fragment( url, Object, 1 )' );
+ },
+
+ [ 'foo=1' ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&c=2&foo=1'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=2&foo=1';
+
+ equal( current_url, pre + fake_encode( params ), '$.fn.fragment( url, String )' );
+ },
+
+ [ 'foo=2&bar=3', 1 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&bar=3&c=2&foo=1'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&bar=3&c=2&foo=1';
+
+ equal( current_url, pre + fake_encode( params ), '$.fn.fragment( url, String, 1 )' );
+ },
+
+ [ 'http://example.com/test.html?the-cow-goes-moo#/path/to/file.php', 2 ],
+
+ function(result){
+ equal( current_url, pre + '#/path/to/file.php', '$.fn.fragment( url, String, 2 )' );
+ },
+
+ [ '#another-example', 2 ],
+
+ function(result){
+ equal( current_url, pre + '#another-example', '$.fn.fragment( url, String, 2 )' );
+ },
+
+ [ 'i_am_out_of_witty_strings', 2 ],
+
+ function(result){
+ equal( current_url, pre + '#i_am_out_of_witty_strings', '$.fn.fragment( url, String, 2 )' );
+ }
+
+ );
+
+ $.param.fragment.ajaxCrawlable( true );
+
+ function test_fn_fragment( url, params, merge_mode? ) {
+ var container,
+ elems;
+
+ container = init_url_attr( container, url );
+ elems = container.children('span');
+ equal( elems.length, 1, 'select the correct elements' );
+ equal( elems.fragment( 'arbitrary_attr', params, merge_mode ), elems, 'pass fragment' );
+
+ container = init_url_attr( container, url );
+ elems = container.children('a, link');
+ equal( elems.length, 2, 'select the correct elements' );
+ equal( elems.fragment( params, merge_mode ), elems, 'pass fragment' );
+
+ container = init_url_attr( container, url );
+ elems = container.children();
+ equal( elems.fragment( params, merge_mode ), elems, 'pass fragment' );
+
+ return test_url_attr( container );
+ };
+
+ equal( test_fn_fragment( 'foo', {} ) , 'foo#!', '$.fn.fragment( url, Object )' );
+ equal( test_fn_fragment( 'foo', { b:2, a:1 } ) , 'foo#!a=1&b=2', '$.fn.fragment( url, Object )' );
+ equal( test_fn_fragment( 'foo#', { b:2, a:1 } ) , 'foo#!a=1&b=2', '$.fn.fragment( url, Object )' );
+ equal( test_fn_fragment( 'foo#!', { b:2, a:1 } ) , 'foo#!a=1&b=2', '$.fn.fragment( url, Object )' );
+ equal( test_fn_fragment( 'foo#c=3&a=4', { b:2, a:1 } ) , 'foo#!a=1&b=2&c=3', '$.fn.fragment( url, Object )' );
+ equal( test_fn_fragment( 'foo#!c=3&a=4', { b:2, a:1 } ) , 'foo#!a=1&b=2&c=3', '$.fn.fragment( url, Object )' );
+
+ equal( test_fn_fragment( 'foo', '' ) , 'foo#!', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo', 'b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#', 'b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#!', 'b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#c=3&a=4', 'b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#!c=3&a=4', 'b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.fn.fragment( url, String )' );
+
+ equal( test_fn_fragment( 'foo', '#' ) , 'foo#!', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo', '#b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#', '#b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#!', '#b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#c=3&a=4', '#b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#!c=3&a=4', '#b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.fn.fragment( url, String )' );
+
+ equal( test_fn_fragment( 'foo', '#!' ) , 'foo#!', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo', '#!b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#', '#!b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#!', '#!b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#c=3&a=4', '#!b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#!c=3&a=4', '#!b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.fn.fragment( url, String )' );
+
+ $.param.fragment.ajaxCrawlable( false );
+
+ // If a params fragment starts with ! and BBQ is not in ajaxCrawlable mode,
+ // things can get very ugly, very quickly.
+ equal( test_fn_fragment( 'foo', '#!' ) , 'foo#!=', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo', '#!b=2&a=1' ) , 'foo#!b=2&a=1', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#', '#!b=2&a=1' ) , 'foo#!b=2&a=1', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#!', '#!b=2&a=1' ) , 'foo#!=&!b=2&a=1', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#c=3&a=4', '#!b=2&a=1' ) , 'foo#!b=2&a=1&c=3', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#!c=3&a=4', '#!b=2&a=1' ) , 'foo#!b=2&!c=3&a=1', '$.fn.fragment( url, String )' );
+
+});
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+QUnit.module( 'jQuery.bbq' );
+
+test( 'jQuery.bbq.pushState(), jQuery.bbq.getState(), jQuery.bbq.removeState(), window.onhashchange', function() {
+ expect( old_jquery ? 95 : 167 );
+
+ var a, b, c, d, e, f, x, y, hash, hash_actual, obj, event, msg = 'Testing window.onhashchange and history';
+
+ $.bbq.pushState();
+ equal( window.location.hash.replace( /^#/, ''), '', 'window.location hash should be empty' );
+
+ $.bbq.pushState({ a:'1', b:'1' });
+ deepEqual( $.deparam.fragment(), { a:'1', b:'1' }, 'hash should be set properly' );
+
+ $(window).bind( 'hashchange', function(evt) {
+ var hash_str = $.param.fragment(),
+ param_obj = $.bbq.getState(),
+ param_val = $.bbq.getState( 'param_name' );
+
+ event = evt;
+ hash = $.param.fragment();
+ hash_actual = location.hash;
+ obj = { str: $.bbq.getState(), coerce: $.bbq.getState( true ) };
+ a = { str: $.bbq.getState( 'a' ), coerce: $.bbq.getState( 'a', true ) };
+ b = { str: $.bbq.getState( 'b' ), coerce: $.bbq.getState( 'b', true ) };
+ c = { str: $.bbq.getState( 'c' ), coerce: $.bbq.getState( 'c', true ) };
+ d = { str: $.bbq.getState( 'd' ), coerce: $.bbq.getState( 'd', true ) };
+ e = { str: $.bbq.getState( 'e' ), coerce: $.bbq.getState( 'e', true ) };
+ f = { str: $.bbq.getState( 'f' ), coerce: $.bbq.getState( 'f', true ) };
+
+ }).trigger( 'hashchange' );
+
+ deepEqual( obj.str, { a:'1', b:'1' }, 'hashchange triggered manually: $.bbq.getState()' );
+ deepEqual( obj.coerce, { a:1, b:1 }, 'hashchange triggered manually: $.bbq.getState( true )' );
+ equal( a.str, '1', 'hashchange triggered manually: $.bbq.getState( "a" )' );
+ equal( a.coerce, 1, 'hashchange triggered manually: $.bbq.getState( "a", true )' );
+
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), { a:'1', b:'1' }, 'hashchange triggered manually: event.getState()' );
+ deepEqual( event.getState(true), { a:1, b:1 }, 'hashchange triggered manually: event.getState( true )' );
+ equal( event.getState('a'), '1', 'hashchange triggered manually: event.getState( "a" )' );
+ equal( event.getState('a',true), 1, 'hashchange triggered manually: event.getState( "a", true )' );
+ }
+
+ run_many_tests(
+ // run asynchronously
+ 250,
+
+ // execute this for each array item
+ function(){
+ notice( msg += '.' );
+ $.bbq.pushState.apply( this, aps.call( arguments ) );
+ },
+
+ // execute this at the end
+ function(){
+ notice();
+ },
+
+ // tests:
+
+ [ { a:'2' } ],
+
+ function(result){
+ equal( hash_actual, '#' + hash, 'hash should begin with #!' );
+ deepEqual( obj.str, { a:'2', b:'1' }, '$.bbq.getState()' );
+ deepEqual( obj.coerce, { a:2, b:1 }, '$.bbq.getState( true )' );
+ equal( a.str, '2', '$.bbq.getState( "a" )' );
+ equal( a.coerce, 2, '$.bbq.getState( "a", true )' );
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), { a:'2', b:'1' }, 'event.getState()' );
+ deepEqual( event.getState(true), { a:2, b:1 }, 'event.getState( true )' );
+ equal( event.getState('a'), '2', 'event.getState( "a" )' );
+ equal( event.getState('a',true), 2, 'event.getState( "a", true )' );
+ }
+ },
+
+ [ { b:'2' } ],
+
+ function(result){
+ equal( hash_actual, '#' + hash, 'hash should begin with #!' );
+ deepEqual( obj.str, { a:'2', b:'2' }, '$.bbq.getState()' );
+ deepEqual( obj.coerce, { a:2, b:2 }, '$.bbq.getState( true )' );
+ equal( b.str, '2', '$.bbq.getState( "b" )' );
+ equal( b.coerce, 2, '$.bbq.getState( "b", true )' );
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), { a:'2', b:'2' }, 'event.getState()' );
+ deepEqual( event.getState(true), { a:2, b:2 }, 'event.getState( true )' );
+ equal( event.getState('b'), '2', 'event.getState( "b" )' );
+ equal( event.getState('b',true), 2, 'event.getState( "b", true )' );
+ }
+ },
+
+ [ { c:true, d:false, e:'undefined', f:'' } ],
+
+ function(result){
+ equal( hash_actual, '#' + hash, 'hash should begin with #!' );
+ deepEqual( obj.str, { a:'2', b:'2', c:'true', d:'false', e:'undefined', f:'' }, '$.bbq.getState()' );
+ deepEqual( obj.coerce, { a:2, b:2, c:true, d:false, e:undefined, f:'' }, '$.bbq.getState( true )' );
+ equal( c.str, 'true', '$.bbq.getState( "c" )' );
+ equal( c.coerce, true, '$.bbq.getState( "c", true )' );
+ equal( d.str, 'false', '$.bbq.getState( "d" )' );
+ equal( d.coerce, false, '$.bbq.getState( "d", true )' );
+ equal( e.str, 'undefined', '$.bbq.getState( "e" )' );
+ equal( e.coerce, undefined, '$.bbq.getState( "e", true )' );
+ equal( f.str, '', '$.bbq.getState( "f" )' );
+ equal( f.coerce, '', '$.bbq.getState( "f", true )' );
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), { a:'2', b:'2', c:'true', d:'false', e:'undefined', f:'' }, 'event.getState()' );
+ deepEqual( event.getState(true), { a:2, b:2, c:true, d:false, e:undefined, f:'' }, 'event.getState( true )' );
+ equal( event.getState('c'), 'true', 'event.getState( "c" )' );
+ equal( event.getState('c',true), true, 'event.getState( "c", true )' );
+ equal( event.getState('d'), 'false', 'event.getState( "d" )' );
+ equal( event.getState('d',true), false, 'event.getState( "d", true )' );
+ equal( event.getState('e'), 'undefined', 'event.getState( "e" )' );
+ equal( event.getState('e',true), undefined, 'event.getState( "e", true )' );
+ equal( event.getState('f'), '', 'event.getState( "f" )' );
+ equal( event.getState('f',true), '', 'event.getState( "f", true )' );
+ }
+ },
+
+ function(result){
+ $.param.fragment.ajaxCrawlable( true );
+ },
+
+ function(result){
+ $.bbq.removeState( 'c' );
+ },
+
+ function(result){
+ equal( hash_actual, '#!' + hash, 'hash should begin with #!' );
+ deepEqual( obj.str, { a:'2', b:'2', d:'false', e:'undefined', f:'' }, '$.bbq.getState()' );
+ deepEqual( obj.coerce, { a:2, b:2, d:false, e:undefined, f:'' }, '$.bbq.getState( true )' );
+ equal( a.str, '2', '$.bbq.getState( "a" )' );
+ equal( a.coerce, 2, '$.bbq.getState( "a", true )' );
+ equal( b.str, '2', '$.bbq.getState( "b" )' );
+ equal( b.coerce, 2, '$.bbq.getState( "b", true )' );
+ equal( c.str, undefined, '$.bbq.getState( "c" )' );
+ equal( c.coerce, undefined, '$.bbq.getState( "c", true )' );
+ equal( d.str, 'false', '$.bbq.getState( "d" )' );
+ equal( d.coerce, false, '$.bbq.getState( "d", true )' );
+ equal( e.str, 'undefined', '$.bbq.getState( "e" )' );
+ equal( e.coerce, undefined, '$.bbq.getState( "e", true )' );
+ equal( f.str, '', '$.bbq.getState( "f" )' );
+ equal( f.coerce, '', '$.bbq.getState( "f", true )' );
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), { a:'2', b:'2', d:'false', e:'undefined', f:'' }, 'event.getState()' );
+ deepEqual( event.getState(true), { a:2, b:2, d:false, e:undefined, f:'' }, 'event.getState( true )' );
+ equal( event.getState('a'), '2', 'event.getState( "a" )' );
+ equal( event.getState('a',true), 2, 'event.getState( "a", true )' );
+ equal( event.getState('b'), '2', 'event.getState( "b" )' );
+ equal( event.getState('b',true), 2, 'event.getState( "b", true )' );
+ equal( event.getState('c'), undefined, 'event.getState( "c" )' );
+ equal( event.getState('c',true), undefined, 'event.getState( "c", true )' );
+ equal( event.getState('d'), 'false', 'event.getState( "d" )' );
+ equal( event.getState('d',true), false, 'event.getState( "d", true )' );
+ equal( event.getState('e'), 'undefined', 'event.getState( "e" )' );
+ equal( event.getState('e',true), undefined, 'event.getState( "e", true )' );
+ equal( event.getState('f'), '', 'event.getState( "f" )' );
+ equal( event.getState('f',true), '', 'event.getState( "f", true )' );
+ }
+ },
+
+ function(result){
+ $.bbq.removeState( [ 'd', 'e', 'f', 'nonexistent' ] );
+ },
+
+ function(result){
+ equal( hash_actual, '#!' + hash, 'hash should begin with #!' );
+ deepEqual( obj.str, { a:'2', b:'2' }, '$.bbq.getState()' );
+ deepEqual( obj.coerce, { a:2, b:2 }, '$.bbq.getState( true )' );
+ equal( a.str, '2', '$.bbq.getState( "a" )' );
+ equal( a.coerce, 2, '$.bbq.getState( "a", true )' );
+ equal( b.str, '2', '$.bbq.getState( "b" )' );
+ equal( b.coerce, 2, '$.bbq.getState( "b", true )' );
+ equal( c.str, undefined, '$.bbq.getState( "c" )' );
+ equal( c.coerce, undefined, '$.bbq.getState( "c", true )' );
+ equal( d.str, undefined, '$.bbq.getState( "d" )' );
+ equal( d.coerce, undefined, '$.bbq.getState( "d", true )' );
+ equal( e.str, undefined, '$.bbq.getState( "e" )' );
+ equal( e.coerce, undefined, '$.bbq.getState( "e", true )' );
+ equal( f.str, undefined, '$.bbq.getState( "f" )' );
+ equal( f.coerce, undefined, '$.bbq.getState( "f", true )' );
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), { a:'2', b:'2' }, 'event.getState()' );
+ deepEqual( event.getState(true), { a:2, b:2 }, 'event.getState( true )' );
+ equal( event.getState('a'), '2', 'event.getState( "a" )' );
+ equal( event.getState('a',true), 2, 'event.getState( "a", true )' );
+ equal( event.getState('b'), '2', 'event.getState( "b" )' );
+ equal( event.getState('b',true), 2, 'event.getState( "b", true )' );
+ equal( event.getState('c'), undefined, 'event.getState( "c" )' );
+ equal( event.getState('c',true), undefined, 'event.getState( "c", true )' );
+ equal( event.getState('d'), undefined, 'event.getState( "d" )' );
+ equal( event.getState('d',true), undefined, 'event.getState( "d", true )' );
+ equal( event.getState('e'), undefined, 'event.getState( "e" )' );
+ equal( event.getState('e',true), undefined, 'event.getState( "e", true )' );
+ equal( event.getState('f'), undefined, 'event.getState( "f" )' );
+ equal( event.getState('f',true), undefined, 'event.getState( "f", true )' );
+ }
+ },
+
+ function(result){
+ $.bbq.removeState();
+ },
+
+ function(result){
+ equal( hash_actual, '#!', 'hash should just be #!' );
+ deepEqual( obj.str, {}, '$.bbq.getState()' );
+ deepEqual( obj.coerce, {}, '$.bbq.getState( true )' );
+ equal( a.str, undefined, '$.bbq.getState( "a" )' );
+ equal( a.coerce, undefined, '$.bbq.getState( "a", true )' );
+ equal( b.str, undefined, '$.bbq.getState( "b" )' );
+ equal( b.coerce, undefined, '$.bbq.getState( "b", true )' );
+ equal( c.str, undefined, '$.bbq.getState( "c" )' );
+ equal( c.coerce, undefined, '$.bbq.getState( "c", true )' );
+ equal( d.str, undefined, '$.bbq.getState( "d" )' );
+ equal( d.coerce, undefined, '$.bbq.getState( "d", true )' );
+ equal( e.str, undefined, '$.bbq.getState( "e" )' );
+ equal( e.coerce, undefined, '$.bbq.getState( "e", true )' );
+ equal( f.str, undefined, '$.bbq.getState( "f" )' );
+ equal( f.coerce, undefined, '$.bbq.getState( "f", true )' );
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), {}, 'event.getState()' );
+ deepEqual( event.getState(true), {}, 'event.getState( true )' );
+ equal( event.getState('a'), undefined, 'event.getState( "a" )' );
+ equal( event.getState('a',true), undefined, 'event.getState( "a", true )' );
+ equal( event.getState('b'), undefined, 'event.getState( "b" )' );
+ equal( event.getState('b',true), undefined, 'event.getState( "b", true )' );
+ equal( event.getState('c'), undefined, 'event.getState( "c" )' );
+ equal( event.getState('c',true), undefined, 'event.getState( "c", true )' );
+ equal( event.getState('d'), undefined, 'event.getState( "d" )' );
+ equal( event.getState('d',true), undefined, 'event.getState( "d", true )' );
+ equal( event.getState('e'), undefined, 'event.getState( "e" )' );
+ equal( event.getState('e',true), undefined, 'event.getState( "e", true )' );
+ equal( event.getState('f'), undefined, 'event.getState( "f" )' );
+ equal( event.getState('f',true), undefined, 'event.getState( "f", true )' );
+ }
+ },
+
+ [ { a:'2', b:'2', c:true, d:false, e:'undefined', f:'' } ],
+
+ [ { a:[4,5,6]}],//, b:{x:[7], y:8, z:[9,0,'true','false','undefined','']} }, 2 ],
+
+ function(result){
+ var b_str = old_jquery
+ ? '[object Object]'
+ : {x:['7'], y:'8', z:['9','0','true','false','undefined','']},
+ b_coerce = old_jquery
+ ? '[object Object]'
+ : {x:[7], y:8};//z:[9,0,true,false,undefined,'']};
+
+ equal( hash_actual, '#!' + hash, 'hash should begin with #!' );
+ deepEqual( obj.str, { a:['4','5','6'], b:b_str }, '$.bbq.getState()' );
+ deepEqual( obj.coerce, { a:[4,5,6], b:b_coerce }, '$.bbq.getState( true )' );
+ deepEqual( a.str, ['4','5','6'], '$.bbq.getState( "a" )' );
+ deepEqual( a.coerce, [4,5,6], '$.bbq.getState( "a", true )' );
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), { a:['4','5','6'], b:b_str }, 'event.getState()' );
+ deepEqual( event.getState(true), { a:[4,5,6], b:b_coerce }, 'event.getState( true )' );
+ deepEqual( event.getState('a'), ['4','5','6'], 'event.getState( "a" )' );
+ deepEqual( event.getState('a',true), [4,5,6], 'event.getState( "a", true )' );
+ }
+ },
+
+ [ { a:'1', c:'2' }, 1 ],
+
+ function(result){
+ var b_str = old_jquery
+ ? '[object Object]'
+ : {x:['7'], y:'8', z:['9','0','true','false','undefined','']},
+ b_coerce = old_jquery
+ ? '[object Object]'
+ : {x:[7], y:8};//, z:[9,0,true,false,undefined,'']};
+
+ equal( hash_actual, '#!' + hash, 'hash should begin with #!' );
+ deepEqual( obj.str, { a:['4','5','6'], b:b_str, c:'2' }, '$.bbq.getState()' );
+ deepEqual( obj.coerce, { a:[4,5,6], b:b_coerce, c:2 }, '$.bbq.getState( true )' );
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), { a:['4','5','6'], b:b_str, c:'2' }, 'event.getState()' );
+ deepEqual( event.getState(true), { a:[4,5,6], b:b_coerce, c:2 }, 'event.getState( true )' );
+ }
+ },
+
+ [ '#/path/to/file.php', 2 ],
+
+ function(result){
+ equal( hash_actual, '#!' + hash, 'hash should begin with #!' );
+ equal( hash, '/path/to/file.php', '$.param.fragment()' );
+ if ( !old_jquery ) {
+ equal( event.fragment, '/path/to/file.php', 'event.fragment' );
+ }
+ },
+
+ [],
+
+ function(result){
+ equal( hash_actual, '#!', 'hash should just be #!' );
+ equal( hash, '', '$.param.fragment()' );
+ if ( !old_jquery ) {
+ equal( event.fragment, '', 'event.fragment' );
+ }
+ },
+
+ function(result){
+ $(window).bind( 'hashchange', function(evt){
+ x = $.param.fragment();
+ });
+ },
+
+ [ '#omg_ponies', 2 ],
+
+ function(result){
+ equal( hash, 'omg_ponies', 'event handler 1: $.param.fragment()' );
+ equal( x, 'omg_ponies', 'event handler 2: $.param.fragment()' );
+
+ hash = x = '';
+ equal( hash + x, '', 'vars reset' );
+
+ $(window).triggerHandler( 'hashchange' );
+ equal( hash, 'omg_ponies', 'event handler 1: $.param.fragment()' );
+ equal( x, 'omg_ponies', 'event handler 2: $.param.fragment()' );
+
+ hash = x = '';
+ equal( hash + x, '', 'vars reset' );
+
+ $(window).unbind( 'hashchange' );
+ },
+
+ [ '#almost_done?not_search', 2 ],
+
+ function(result){
+ equal( hash, '', 'event handler 1: $.param.fragment()' );
+ equal( x, '', 'event handler 2: $.param.fragment()' );
+
+ var events:any;// = $.data( window, 'events' );
+ ok( !events || !events.hashchange, 'hashchange event unbound' );
+ },
+
+ [ '#' ],
+
+ function(result){
+ x = [];
+ $(window).bind( 'hashchange', function(evt){
+ x.push( $.param.fragment() );
+ });
+ },
+
+ function(result){
+ !is_chrome && window.history.go( -1 );
+ },
+
+ function(result){
+ !is_chrome && window.history.go( -1 );
+ },
+
+ function(result){
+ !is_chrome && window.history.go( -1 );
+ },
+
+ function(result){
+ !is_chrome && window.history.go( -1 );
+ },
+
+ function(result){
+ if ( is_chrome ) {
+ // Read about this issue here: http://benalman.com/news/2009/09/chrome-browser-history-buggine/
+ ok( true, 'history is sporadically broken in chrome, this is a known bug, so this test is skipped in chrome' );
+ } else {
+ deepEqual( x, ['almost_done?not_search', 'omg_ponies', '', '/path/to/file.php'], 'back button and window.bbq.go(-1) should work' );
+ }
+
+ $(window).unbind( 'hashchange' );
+ var events: any;// = $.data( window, 'events' );
+ ok( !events || !events.hashchange, 'hashchange event unbound' );
+ },
+
+ function(result){
+ $.param.fragment.ajaxCrawlable( false );
+ },
+
+ [ '#all_done' ]
+
+ );
+
+});
+
+
+}); // END CLOSURE
\ No newline at end of file
diff --git a/jquery.bbq/jquery.bbq.d.ts b/jquery.bbq/jquery.bbq.d.ts
index b34ea0eb36..5e94efea99 100644
--- a/jquery.bbq/jquery.bbq.d.ts
+++ b/jquery.bbq/jquery.bbq.d.ts
@@ -1,42 +1,160 @@
// Type definitions for jquery.bbq 1.2
// Project: http://benalman.com/projects/jquery-bbq-plugin/
-// Definitions by: https://github.com/sunetos
+// Definitions by: Adam R. Smith
// Definitions: https://github.com/borisyankov/DefinitelyTyped
-interface JQueryBBQ {
- pushState(params?: any, merge_mode?: number): void;
- getState(key?: string, coerce?: bool): any;
- removeState(...key: any[]): void;
+///
+
+module JQueryBbq {
+
+ interface JQuery {
+ /**
+ * Adds a 'state' into the browser history at the current position, setting
+ * location.hash and triggering any bound callbacks
+ * (provided the new state is different than the previous state).
+ *
+ * @name params A serialized params string or a hash string beginning with # to merge into location.hash.
+ * @name merge_mode Merge behavior defaults to 0 if merge_mode is not specified (unless a hash string beginning with # is specified, in which case merge behavior defaults to 2)
+ */
+ pushState(params?: string, merge_mode?: number): void;
+
+ pushState(params?: any, merge_mode?: number): void;
+
+ /**
+ * Retrieves the current 'state' from the browser history, parsing
+ * location.hash for a specific key or returning an object containing the
+ * entire state, optionally coercing numbers, booleans, null and undefined
+ * values.
+ *
+ * @name key An optional state key for which to return a value.
+ * @name coerce If true, coerces any numbers or true, false, null, and undefined to their actual value. Defaults to false
+ */
+ getState(key?: string, coerce?: bool): any;
+
+ getState(coerce?: bool): any;
+
+ /**
+ * Remove one or more keys from the current browser history 'state', creating
+ * a new state, setting location.hash and triggering any bound
+ * callbacks (provided the new state is different than
+ * the previous state).
+ *
+ * @name key One or more key values to remove from the current state.
+ */
+ removeState(...key: any[]): void;
+ }
+
+ interface ParamFragment {
+ (url?: string): string;
+
+ (url: string, params: any, merge_mode?: number): string;
+
+ /**
+ * Specify characters that will be left unescaped when fragments are created
+ * or merged using , or when the fragment is modified
+ * using . This option only applies to serialized data
+ * object fragments, and not set-as-string fragments. Does not affect the
+ * query string. Defaults to ",/" (comma, forward slash).
+ *
+ * @name chars The characters to not escape in the fragment. If unspecified, defaults to empty string (escape all characters).
+ */
+ noEscape: (chars?: string) => void;
+
+ /**
+ * TODO: DESCRIBE
+ *
+ * @name state TODO: DESCRIBE
+ */
+ ajaxCrawlable(state?: bool): bool;
+ }
+
+ interface JQueryDeparam {
+ /**
+ * Deserialize a params string into an object, optionally coercing numbers,
+ * booleans, null and undefined values; this method is the counterpart to the
+ * internal jQuery.param method.
+ *
+ * @name params A params string to be parsed.
+ * @name coerce If true, coerces any numbers or true, false, null, and undefined to their actual value. Defaults to false if omitted.
+ */
+ (params: string, coerce?: bool): any;
+
+
+ /**
+ * Parse the query string from a URL or the current window.location.href,
+ * deserializing it into an object, optionally coercing numbers, booleans,
+ * null and undefined values.
+ *
+ * @name url An optional params string or URL containing query string params to be parsed. If url is omitted, the current window.location.href is used.
+ * @name coerce If true, coerces any numbers or true, false, null, and undefined to their actual value. Defaults to false if omitted.
+ */
+ querystring(url?: string, coerce?: bool): any;
+
+ /**
+ * Parse the fragment (hash) from a URL or the current window.location.href,
+ * deserializing it into an object, optionally coercing numbers, booleans,
+ * null and undefined values.
+ *
+ * @name url An optional params string or URL containing fragment (hash) params to be parsed. If url is omitted, the current window.location.href is used.
+ * @name coerce If true, coerces any numbers or true, false, null, and undefined to their actual value. Defaults to false if omitted.
+ */
+ fragment(url?: string, coerce?: bool): any;
+ }
+
+ interface EventObject extends JQueryEventObject {
+ fragment: string;
+
+ getState( key?: string, coerce? :bool );
+ }
}
interface JQueryParam {
- (obj: any): string;
- (obj: any, traditional: bool): string;
+ /**
+ * Parse the query string from a URL or the current window.location.href,
+ * deserializing it into an object, optionally coercing numbers, booleans,
+ * null and undefined values.
+ *
+ * @name url An optional params string or URL containing query string params to be parsed. If url is omitted, the current window.location.href is used.
+ * @name coerce (Boolean) If true, coerces any numbers or true, false, null, and undefined to their actual value. Defaults to false if omitted.
+ * @name merge_mode An object representing the deserialized params string.
+ */
+ querystring(url?: string, coerce?: bool, merge_mode?: number): string;
- querystring(url?: string): string;
- querystring(url: string, params: any, merge_mode?: number): string;
- fragment: {
- noEscape: (chars?: string) => void;
- (url?: string): string;
- (url: string, params: any, merge_mode?: number): string;
- };
-}
+ querystring(url?: string, coerce?: any, merge_mode?: number): string;
-interface JQueryDeparam {
- (params: string, coerce?: bool): any;
- querystring(url?: string, coerce?: bool): any;
- fragment(url?: string, coerce?: bool): any;
+ fragment: JQueryBbq.ParamFragment;
+
+ /**
+ * Returns a params string equivalent to that returned by the internal
+ * jQuery.param method, but sorted, which makes it suitable for use as a
+ * cache key.
+ *
+ * @name obj An object to be serialized.
+ * @name traditional Params deep/shallow serialization mode. See the documentation at http://api.jquery.com/jQuery.param/ for more detail.
+ */
+ sorted(obj: any, traditional?: bool): string;
}
interface JQueryStatic {
- bbq: JQueryBBQ;
- param: JQueryParam;
- deparam: JQueryDeparam;
+ bbq: JQueryBbq.JQuery;
- elemUrlAttr(tag_attr: any): any;
+ deparam: JQueryBbq.JQueryDeparam;
+
+ /**
+ * Get the internal "Default URL attribute per tag" list, or augment the list
+ * with additional tag-attribute pairs, in case the defaults are insufficient.
+ *
+ * @name tag_attr An object containing a list of tag names and their associated default attribute names in the format { tag: 'attr', ... } to be merged into the internal tag-attribute list.
+ */
+ elemUrlAttr(tag_attr?: any): any;
}
interface JQuery {
- querystring(attr?: any, params?: any, merge_mode?: number): JQuery;
- fragment(attr?: any, params?: any, merge_mode?: number): JQuery;
+ querystring(attr?: any, params?: any, merge_mode?: number): JQuery;
+
+ fragment(attr?: any, params?: any, merge_mode?: number): JQuery;
+
+ hashchange(eventData?: any, handler?: (eventObject: JQueryBbq.EventObject) => any): JQuery;
+
+ hashchange(handler: (eventObject: JQueryBbq.EventObject) => any): JQuery;
}
diff --git a/jquery.clientSideLogging/jquery.clientSideLogging-tests.ts b/jquery.clientSideLogging/jquery.clientSideLogging-tests.ts
new file mode 100644
index 0000000000..35974af26a
--- /dev/null
+++ b/jquery.clientSideLogging/jquery.clientSideLogging-tests.ts
@@ -0,0 +1,17 @@
+///
+
+$.clientSideLogging({
+ log_level: 3,
+ client_info: {
+ location:true,
+ screen_size:true,
+ user_agent:true,
+ window_size:false
+ }
+});
+
+$.info({msg:$(this).parents('li').find('input:text').val()});
+$.error({msg:$(this).parents('li').find('input:text').val()});
+$.log($(this).parents('li').find('input:text').val());
+
+$.post('/log?type=error&msg=YOUR_ERROR_MESSAGE');
\ No newline at end of file
diff --git a/jquery.clientSideLogging/jquery.clientSideLogging.d.ts b/jquery.clientSideLogging/jquery.clientSideLogging.d.ts
new file mode 100644
index 0000000000..d2031029e4
--- /dev/null
+++ b/jquery.clientSideLogging/jquery.clientSideLogging.d.ts
@@ -0,0 +1,31 @@
+// Type definitions for jquery.clientSideLogging.
+// Project: https://github.com/remybach/jQuery.clientSideLogging
+// Definitions by: Diullei Gomes
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+///
+
+interface ClientSideLoggingClientInfoObject {
+ location?: bool; // The url to the page on which the error occurred.
+ screen_size?: bool; // The size of the user's screen (different to the window size because the window might not be maximized)
+ user_agent?: bool; // The user agent string.
+ window_size?: bool; // The window size.
+}
+
+interface ClientSideLoggingObject {
+ error_url?: string; // The url to which errors logs are sent
+ info_url?: string; // The url to which info logs are sent
+ log_url?: string; // The url to which standard logs are sent
+ log_level?: number; // The level at which to log. This allows you to keep the calls to the logging in your code and just change this variable to log varying degrees. 1 = only error, 2 = error & log, 3 = error, log & info
+ native_error?: bool; // Whether or not to send native js errors as well (using window.onerror).
+ hijack_console?: bool; // Hijacks the default console functionality (ie: all your console.error/info/log are belong to us).
+ query_var?: string; // The variable to send the log message through as.
+ client_info?: ClientSideLoggingClientInfoObject; // Configuration for what info about the client's browser is logged.
+}
+
+interface JQueryStatic {
+ info: (what?: any) => any;
+ error: (what?: any) => any;
+ log: (what?: any) => any;
+ clientSideLogging: (options: ClientSideLoggingObject) => any;
+}
diff --git a/jquery.cycle/jquery.cycle-tests.ts b/jquery.cycle/jquery.cycle-tests.ts
new file mode 100644
index 0000000000..2b5bd668e5
--- /dev/null
+++ b/jquery.cycle/jquery.cycle-tests.ts
@@ -0,0 +1,324 @@
+///
+///
+
+// As basic as it can be
+$('#element').cycle();
+
+/* Beginner Demos */
+
+$('#s1').cycle('fade');
+
+$('#s2').cycle({
+ fx: 'scrollDown'
+});
+
+$('#s3').cycle({
+ fx: 'fade',
+ speed: 2500
+});
+
+$('#s4').cycle({
+ fx: 'scrollDown',
+ speed: 300,
+ timeout: 2000
+});
+
+$('#s5').cycle({
+ fx: 'fade',
+ pause: true
+});
+
+$('#s6').cycle({
+ fx: 'scrollDown',
+ random: true
+});
+
+/* Intermediate Demos (Part 1) */
+$('#s1').cycle({
+ fx: 'zoom',
+ easing: 'easeInBounce',
+ delay: -4000
+});
+
+$('#s2').cycle({
+ fx: 'scrollDown',
+ easing: 'easeOutBounce',
+ delay: -2000
+});
+
+$('#s3').cycle({
+ fx: 'zoom',
+ sync: false,
+ delay: -4000
+});
+
+$('#s4').cycle({
+ fx: 'scrollDown',
+ sync: false,
+ delay: -2000
+});
+
+$('#s5').cycle({
+ fx: 'shuffle',
+ delay: -4000
+});
+
+$('#s6').cycle({
+ fx: 'shuffle',
+ shuffle: {
+ top: -230,
+ left: 230
+ },
+ easing: 'easeInOutBack',
+ delay: -2000
+});
+
+/* Intermediate Demos (Part 2) */
+
+$('#s1').cycle({
+ fx: 'slideY',
+ speed: 300,
+ next: '#s1',
+ timeout: 0
+});
+
+$('#s2').cycle({
+ fx: 'fade',
+ speed: 'fast',
+ timeout: 0,
+ next: '#next2',
+ prev: '#prev2'
+});
+
+$('#s3').cycle({
+ fx: 'fade',
+ speed: 300,
+ timeout: 3000,
+ next: '#s3',
+ pause: true
+});
+
+$('#s4')
+.before('
inner via inline binding: 2inner via external binding: 1
");
+
+ ko.bindingProvider.instance = originalBindingProvider;
+ });
+
+ it('Data binding syntax should support \'foreach\' option, whereby it renders for each item in an array but doesn\'t rerender everything if you push or splice', function () {
+ var myArray = new ko.observableArray([{ personName: "Bob" }, { personName: "Frank"}]);
+ ko.setTemplateEngine(new dummyTemplateEngine({ itemTemplate: "
");
+ var originalBobNode = testNode.childNodes[0].childNodes[0];
+ var originalFrankNode = testNode.childNodes[0].childNodes[1];
+
+ myArray.push({ personName: "Steve" });
+ expect(testNode.childNodes[0]).toContainHtml("
the item is bob
the item is frank
the item is steve
");
+ expect(testNode.childNodes[0].childNodes[0]).toEqual(originalBobNode);
+ expect(testNode.childNodes[0].childNodes[1]).toEqual(originalFrankNode);
+ });
+
+ it('Data binding \'foreach\' option should apply bindings within the context of each item in the array', function () {
+ var myArray = new ko.observableArray([{ personName: "Bob" }, { personName: "Frank"}]);
+ ko.setTemplateEngine(new dummyTemplateEngine({ itemTemplate: "The item is " }));
+ testNode.innerHTML = "";
+
+ ko.applyBindings({ myCollection: myArray }, testNode);
+ expect(testNode.childNodes[0]).toContainHtml("the item is bobthe item is frank");
+ });
+
+ it('Data binding \'foreach\' options should only bind each group of output nodes once', function() {
+ var initCalls = 0;
+ (ko.bindingHandlers).countInits = { init: function() { initCalls++ } };
+ ko.setTemplateEngine(new dummyTemplateEngine({ itemTemplate: "" }));
+ testNode.innerHTML = "";
+
+ ko.applyBindings({ myCollection: [1,2,3] }, testNode);
+ expect(initCalls).toEqual(3); // 3 because there were 3 items in myCollection
+ });
+
+ it('Data binding \'foreach\' should handle templates in which the very first node has a binding', function() {
+ // Represents https://github.com/SteveSanderson/knockout/pull/440
+ // Previously, the rewriting (which introduces a comment node before the bound node) was interfering
+ // with the array-to-DOM-node mapping state tracking
+ ko.setTemplateEngine(new dummyTemplateEngine({ mytemplate: "" }));
+ testNode.innerHTML = "";
+
+ // Bind against initial array containing one entry. UI just shows "original"
+ var myArray = ko.observableArray(["original"]);
+ ko.applyBindings({ items: myArray }, testNode);
+ expect(testNode.childNodes[0]).toContainHtml("
original
");
+
+ // Now replace the entire array contents with one different entry.
+ // UI just shows "new" (previously with bug, showed "original" AND "new")
+ myArray(["new"]);
+ expect(testNode.childNodes[0]).toContainHtml("
new
");
+ });
+
+ it('Data binding \'foreach\' should handle chained templates in which the very first node has a binding', function() {
+ // See https://github.com/SteveSanderson/knockout/pull/440 and https://github.com/SteveSanderson/knockout/pull/144
+ ko.setTemplateEngine(new dummyTemplateEngine({
+ outerTemplate: "[renderTemplate:innerTemplate]x", // [renderTemplate:...] is special syntax supported by dummy template engine
+ innerTemplate: "inner "
+ }));
+ testNode.innerHTML = "";
+
+ // Bind against initial array containing one entry.
+ var myArray = ko.observableArray(["original"]);
+ ko.applyBindings({ items: myArray }, testNode);
+ expect(testNode.childNodes[0]).toContainHtml("
original
inner 123x");
+
+ // Now replace the entire array contents with one different entry.
+ myArray(["new"]);
+ expect(testNode.childNodes[0]).toContainHtml("
new
inner 123x");
+ });
+
+ it('Data binding \'foreach\' should handle templates in which the very first node has a binding but it does not reference any observables', function() {
+ // Represents https://github.com/SteveSanderson/knockout/issues/739
+ // Previously, the rewriting (which introduces a comment node before the bound node) was interfering
+ // with the array-to-DOM-node mapping state tracking
+ ko.setTemplateEngine(new dummyTemplateEngine({ mytemplate: "
");
+
+ // Modify the observable property and check that UI is updated
+ // Previously with the bug, it wasn't updated because the removal of the memo comment caused the array-to-DOM-node computed to be disposed
+ myItem.name("b");
+ expect(testNode.childNodes[0]).toContainHtml("
b
");
+ });
+
+ it('Data binding \'foreach\' option should apply bindings with an $index in the context', function () {
+ var myArray = new ko.observableArray([{ personName: "Bob" }, { personName: "Frank"}]);
+ ko.setTemplateEngine(new dummyTemplateEngine({ itemTemplate: "The item # is " }));
+ testNode.innerHTML = "";
+
+ ko.applyBindings({ myCollection: myArray }, testNode);
+ expect(testNode.childNodes[0]).toContainHtml("the item # is 0the item # is 1");
+ });
+
+ it('Data binding \'foreach\' option should update bindings that reference an $index if the list changes', function () {
+ var myArray = new ko.observableArray([{ personName: "Bob" }, { personName: "Frank"}]);
+ ko.setTemplateEngine(new dummyTemplateEngine({ itemTemplate: "The item is " }));
+ testNode.innerHTML = "";
+
+ ko.applyBindings({ myCollection: myArray }, testNode);
+ expect(testNode.childNodes[0]).toContainHtml("the item bobis 0the item frankis 1");
+
+ var frank = myArray.pop(); // remove frank
+ expect(testNode.childNodes[0]).toContainHtml("the item bobis 0");
+
+ myArray.unshift(frank); // put frank in the front
+ expect(testNode.childNodes[0]).toContainHtml("the item frankis 0the item bobis 1");
+
+ });
+
+ it('Data binding \'foreach\' option should accept array with "undefined" and "null" items', function () {
+ var myArray = new ko.observableArray([undefined, null]);
+ ko.setTemplateEngine(new dummyTemplateEngine({ itemTemplate: "The item is " }));
+ testNode.innerHTML = "";
+
+ ko.applyBindings({ myCollection: myArray }, testNode);
+ expect(testNode.childNodes[0]).toContainHtml("the item is undefinedthe item is null");
+ });
+
+ it('Data binding \'foreach\' option should update DOM nodes when a dependency of their mapping function changes', function() {
+ var myObservable = new ko.observable("Steve");
+ var myArray = new ko.observableArray([{ personName: "Bob" }, { personName: myObservable }, { personName: "Another" }]);
+ ko.setTemplateEngine(new dummyTemplateEngine({ itemTemplate: "
The item is [js: ko.utils.unwrapObservable(personName)]
");
+ expect(testNode.childNodes[0].childNodes[0]).toEqual(originalBobNode);
+
+ // Ensure we can still remove the corresponding nodes (even though they've changed), and that doing so causes the subscription to be disposed
+ expect(myObservable.getSubscriptionsCount()).toEqual(1);
+ myArray.splice(1, 1);
+ expect(testNode.childNodes[0]).toContainHtml("
the item is bob
the item is another
");
+ myObservable("Something else"); // Re-evaluating the observable causes the orphaned subscriptions to be disposed
+ expect(myObservable.getSubscriptionsCount()).toEqual(0);
+ });
+
+ it('Data binding \'foreach\' option should treat a null parameter as meaning \'no items\'', function() {
+ var myArray = new ko.observableArray(["A", "B"]);
+ ko.setTemplateEngine(new dummyTemplateEngine({ itemTemplate: "hello" }));
+ testNode.innerHTML = "";
+
+ ko.applyBindings({ myCollection: myArray }, testNode);
+ expect(testNode.childNodes[0].childNodes.length).toEqual(2);
+
+ // Now set the observable to null and check it's treated like an empty array
+ // (because how else should null be interpreted?)
+ myArray(null);
+ expect(testNode.childNodes[0].childNodes.length).toEqual(0);
+ });
+
+ it('Data binding \'foreach\' option should accept an \"as\" option to define an alias for the iteration variable', function() {
+ // Note: There are more detailed specs (e.g., covering nesting) associated with the "foreach" binding which
+ // uses this templating functionality internally.
+ var myArray = new ko.observableArray(["A", "B"]);
+ ko.setTemplateEngine(new dummyTemplateEngine({ itemTemplate: "[js:myAliasedItem]" }));
+ testNode.innerHTML = "";
+
+ ko.applyBindings({ myCollection: myArray }, testNode);
+ expect(testNode.childNodes[0]).toContainText("AB");
+ });
+
+ it('Data binding \'foreach\' option should stop tracking inner observables when the container node is removed', function() {
+ var innerObservable = ko.observable("some value");
+ var myArray = new ko.observableArray([{obsVal:innerObservable}, {obsVal:innerObservable}]);
+ ko.setTemplateEngine(new dummyTemplateEngine({ itemTemplate: "The item is [js: ko.utils.unwrapObservable(obsVal)]" }));
+ testNode.innerHTML = "";
+
+ ko.applyBindings({ myCollection: myArray }, testNode);
+ expect(innerObservable.getSubscriptionsCount()).toEqual(2);
+
+ ko.removeNode(testNode.childNodes[0]);
+ expect(innerObservable.getSubscriptionsCount()).toEqual(0);
+ });
+
+ it('Data binding \'foreach\' option should stop tracking inner observables related to each array item when that array item is removed', function() {
+ var innerObservable = ko.observable("some value");
+ var myArray = new ko.observableArray([{obsVal:innerObservable}, {obsVal:innerObservable}]);
+ ko.setTemplateEngine(new dummyTemplateEngine({ itemTemplate: "The item is [js: ko.utils.unwrapObservable(obsVal)]" }));
+ testNode.innerHTML = "";
+
+ ko.applyBindings({ myCollection: myArray }, testNode);
+ expect(innerObservable.getSubscriptionsCount()).toEqual(2);
+
+ myArray.splice(1, 1);
+ expect(innerObservable.getSubscriptionsCount()).toEqual(1);
+ myArray([]);
+ expect(innerObservable.getSubscriptionsCount()).toEqual(0);
+ });
+
+ it('Data binding syntax should omit any items whose \'_destroy\' flag is set (unwrapping the flag if it is observable)', function() {
+ var myArray = new ko.observableArray([{ someProp: 1 }, { someProp: 2, _destroy: 'evals to true' }, { someProp : 3 }, { someProp: 4, _destroy: ko.observable(false) }]);
+ ko.setTemplateEngine(new dummyTemplateEngine({ itemTemplate: "
");
+ });
+
+ it('Data binding syntax should include any items whose \'_destroy\' flag is set if you use includeDestroyed', function() {
+ var myArray = new ko.observableArray([{ someProp: 1 }, { someProp: 2, _destroy: 'evals to true' }, { someProp : 3 }]);
+ ko.setTemplateEngine(new dummyTemplateEngine({ itemTemplate: "
person alpha has additional property someadditionalvalue
person beta has additional property someadditionalvalue
");
+ });
+
+ it('If the template binding is updated, should dispose any template subscriptions previously associated with the element', function() {
+ var myObservable = ko.observable("some value"),
+ myModel = {
+ subModel: ko.observable({ myObservable: myObservable })
+ };
+ ko.setTemplateEngine(new dummyTemplateEngine({myTemplate: "The value is [js:myObservable()]"}));
+ testNode.innerHTML = "";
+ ko.applyBindings(myModel, testNode);
+
+ // Right now the template references myObservable, so there should be exactly one subscription on it
+ expect(testNode.childNodes[0]).toContainText("The value is some value");
+ expect(myObservable.getSubscriptionsCount()).toEqual(1);
+ var renderedNode1 = testNode.childNodes[0].childNodes[0];
+
+ // By changing the object for subModel, we force the data-bind value to be re-evaluated and the template to be re-rendered,
+ // setting up a new template subscription, so there have now existed two subscriptions on myObservable...
+ myModel.subModel({ myObservable: myObservable });
+ expect(testNode.childNodes[0].childNodes[0]).not.toEqual(renderedNode1);
+
+ // ...but, because the old subscription should have been disposed automatically, there should only be one left
+ expect(myObservable.getSubscriptionsCount()).toEqual(1);
+ });
+
+ it('Should be able to specify a template engine instance using data-bind syntax', function() {
+ ko.setTemplateEngine(new dummyTemplateEngine({ theTemplate: "Default output" })); // Not going to use this one
+ var alternativeTemplateEngine = new dummyTemplateEngine({ theTemplate: "Alternative output" });
+
+ testNode.innerHTML = "";
+ ko.applyBindings({ chosenEngine: alternativeTemplateEngine }, testNode);
+
+ expect(testNode.childNodes[0]).toContainText("Alternative output");
+ });
+
+ it('Should be able to bind $data to an alias using \'as\'', function() {
+ ko.setTemplateEngine(new dummyTemplateEngine({
+ myTemplate: "ValueLiteral: [js:item.prop], ValueBound: "
+ }));
+ testNode.innerHTML = "";
+ ko.applyBindings({ someItem: { prop: 'Hello' } }, testNode);
+ expect(testNode.childNodes[0]).toContainText("ValueLiteral: Hello, ValueBound: Hello");
+ });
+
+ it('Data-bind syntax should expose parent binding context as $parent if binding with an explicit \"data\" value', function() {
+ ko.setTemplateEngine(new dummyTemplateEngine({
+ myTemplate: "ValueLiteral: [js:$parent.parentProp], ValueBound: "
+ }));
+ testNode.innerHTML = "";
+ ko.applyBindings({ someItem: {}, parentProp: 'Hello' }, testNode);
+ expect(testNode.childNodes[0]).toContainText("ValueLiteral: Hello, ValueBound: Hello");
+ });
+
+ it('Data-bind syntax should expose all ancestor binding contexts as $parents', function() {
+ ko.setTemplateEngine(new dummyTemplateEngine({
+ outerTemplate: "",
+ middleTemplate: "",
+ innerTemplate: "(Data:[js:$data.val], Parent:[[js:$parents[0].val]], Grandparent:[[js:$parents[1].val]], Root:[js:$root.val], Depth:[js:$parents.length])"
+ }));
+ testNode.innerHTML = "";
+
+ ko.applyBindings({
+ val: "ROOT",
+ outerItem: {
+ val: "OUTER",
+ middleItem: {
+ val: "MIDDLE",
+ innerItem: { val: "INNER" }
+ }
+ }
+ }, testNode);
+ expect(testNode.childNodes[0].childNodes[0]).toContainText("(Data:INNER, Parent:MIDDLE, Grandparent:OUTER, Root:ROOT, Depth:3)");
+ });
+
+ it('Should not be allowed to rewrite templates that embed anonymous templates', function() {
+ // The reason is that your template engine's native control flow and variable evaluation logic is going to run first, independently
+ // of any KO-native control flow, so variables would get evaluated in the wrong context. Example:
+ //
+ //
+ // ${ somePropertyOfEachArrayItem } <-- This gets evaluated *before* the foreach binds, so it can't reference array entries
+ //
+ //
+ // It should be perfectly OK to fix this just by preventing anonymous templates within rewritten templates, because
+ // (1) The developer can always use their template engine's native control flow syntax instead of the KO-native ones - that will work
+ // (2) The developer can use KO's native templating instead, if they are keen on KO-native control flow or anonymous templates
+
+ ko.setTemplateEngine(new dummyTemplateEngine({
+ myTemplate: "
Childprop: [js: childProp]
"
+ }));
+ testNode.innerHTML = "";
+
+ var didThrow = false;
+ try {
+ ko.applyBindings({ someData: { childProp: 'abc' } }, testNode);
+ } catch(ex) {
+ didThrow = true;
+ expect(ex.message).toEqual("This template engine does not support anonymous templates nested within its templates");
+ }
+ expect(didThrow).toEqual(true);
+ });
+
+ it('Should not be allowed to rewrite templates that embed control flow bindings', function() {
+ // Same reason as above
+ ko.utils.arrayForEach(['if', 'ifnot', 'with', 'foreach'], function(bindingName) {
+ ko.setTemplateEngine(new dummyTemplateEngine({ myTemplate: "
Hello
" }));
+ testNode.innerHTML = "";
+
+ var didThrow = false;
+ ko.utils.domData.clear(testNode);
+ try { ko.applyBindings({ someData: { childProp: 'abc' } }, testNode) }
+ catch (ex) {
+ didThrow = true;
+ expect(ex.message).toEqual("This template engine does not support the '" + bindingName + "' binding within its templates");
+ }
+ if (!didThrow)
+ throw new Error("Did not prevent use of " + bindingName);
+ });
+ });
+
+ it('Data binding syntax should permit nested templates using virtual containers (with arbitrary internal whitespace and newlines)', function() {
+ ko.setTemplateEngine(new dummyTemplateEngine({
+ outerTemplate: "Outer ",
+ innerTemplate: "Inner via inline binding: "
+ }));
+ var model = { };
+ testNode.innerHTML = "";
+ ko.applyBindings(model, testNode);
+ expect(testNode.childNodes[0]).toContainHtml("outer inner via inline binding: sometext");
+ });
+
+ it('Should be able to render anonymous templates using virtual containers', function() {
+ ko.setTemplateEngine(new dummyTemplateEngine());
+ testNode.innerHTML = "Start Childprop: [js: childProp] End";
+ ko.applyBindings({ someData: { childProp: 'abc' } }, testNode);
+ expect(testNode).toContainHtml("start childprop: abcend");
+ });
+
+ it('Should be able to use anonymous templates that contain first-child comment nodes', function() {
+ // This represents issue https://github.com/SteveSanderson/knockout/issues/188
+ // (IE < 9 strips out leading comment nodes when you use .innerHTML)
+ ko.setTemplateEngine(new dummyTemplateEngine({}));
+ testNode.innerHTML = "start
');
+ });
+
+ it('Should allow anonymous templates output to include top-level virtual elements, and will bind their virtual children only once', function() {
+ delete (ko.bindingHandlers).nonexistentHandler;
+ var initCalls = 0;
+ (ko.bindingHandlers).countInits = { init: function () { initCalls++ } };
+ testNode.innerHTML = "
";
+ ko.applyBindings(null, testNode);
+ expect(initCalls).toEqual(1);
+ });
+
+ it('Should not throw errors if trying to apply text to a non-rendered node', function() {
+ // Represents https://github.com/SteveSanderson/knockout/issues/660
+ // A can't go directly into a
, so modern browsers will silently strip it. We need to verify this doesn't
+ // throw errors during unmemoization (when unmemoizing, it will try to apply the text to the following text node
+ // instead of the node you intended to bind to).
+ // Note that IE < 9 won't strip the
; instead it has much stranger behaviors regarding unexpected DOM structures.
+ // It just happens not to give an error in this particular case, though it would throw errors in many other cases
+ // of malformed template DOM.
+ ko.setTemplateEngine(new dummyTemplateEngine({
+ myTemplate: "
'.stripTags('p'); // - > 'just some text'
+
+'man from the boondocks'.titleize(); // - > 'Man from the Boondocks'
+'x-men: the last stand'.titleize(); // - > 'X Men: The Last Stand'
+'TheManWithoutAPast'.titleize(); // - > 'The Man Without a Past'
+'raiders_of_the_lost_ark'.titleize(); // - > 'Raiders of the Lost Ark'
+
+'lucky charms'.to(); // - > 'lucky charms'
+'lucky charms'.to(7); // - > 'lucky ch'
+
+'153'.toNumber(); // - > 153
+'12,000'.toNumber(); // - > 12000
+'10px'.toNumber(); // - > 10
+'ff'.toNumber(16); // - > 255
+
+' wasabi '.trim(); // - > 'wasabi'
+' wasabi '.trimLeft(); // - > 'wasabi '
+' wasabi '.trimRight(); // - > ' wasabi'
+
+'just sittin on the dock of the bay'.truncate(20); // - > 'just sittin on the do...'
+'just sittin on the dock of the bay'.truncate(20, false); // - > 'just sittin on the...'
+'just sittin on the dock of the bay'.truncate(20, true, 'middle'); // - > 'just sitt...of the bay'
+'just sittin on the dock of the bay'.truncate(20, true, 'left'); // - > '...the dock of the bay'
+
+'a-farewell-to-arms'.underscore(); // - > 'a_farewell_to_arms'
+'capsLock'.underscore(); // - > 'caps_lock'
+
+'<p>some text</p>'.unescapeHTML(); // - > '
some text
'
+'one & two'.unescapeHTML(); // - > 'one & two'
+
+'http%3A%2F%2Ffoo.com%2Fthe%20bar'.unescapeURL(); // - > 'http://foo.com/the bar'
+'http%3A%2F%2Ffoo.com%2Fthe%20bar'.unescapeURL(true); // - > 'http%3A%2F%2Ffoo.com%2Fthe bar'
+
+'broken wear'.words(); // - > ['broken', 'wear']
+'broken wear'.words(function (w) {
+ // Called twice: "broken", "wear"
+});
+
+'??? YAMADA??!'.zenkaku(); // - > '??? YAMADA??!'
+'??? YAMADA??!'.zenkaku('a'); // - > '??? YAMADA??!'
+'??? YAMADA??!'.zenkaku('alphabet'); // - > '??? YAMADA??!'
+'?????! 25???!'.zenkaku('katakana', 'numbers'); // - > '?????! 25???!'
+'?????! 25???!'.zenkaku('k', 'n'); // - > '?????! 25???!'
+'?????! 25???!'.zenkaku('kn'); // - > '?????! 25???!'
+'?????! 25???!'.zenkaku('sp'); // - > '?????! 25???!'
+
+// static
+//Number.random(50, 100); // - > ex.85
+//Number.random(50); // - > ex.27
+//Number.random(); // - > ex.0
+
+(1000).abbr(); // - > "1k"
+(1000000).abbr(); // - > "1m"
+(1280).abbr(1); // - > "1.3k"
+
+(1000).bytes(); // - > "1kB"
+(1000).bytes(2); // - > "0.98kB"
+((10).pow(20)).bytes(); // - > "90,949,470TB"
+((10).pow(20)).bytes(0, false); // - > "87EB"
+
+(1000).bytes(); // - > "1kB"
+(1000).bytes(2); // - > "0.98kB"
+((10).pow(20)).bytes(); // - > "90,949,470TB"
+((10).pow(20)).bytes(0, false); // - > "87EB"
+
+(3.241).ceil(); // - > 4
+(-3.241).ceil(); // - > -3
+(3.241).ceil(2); // - > 3.25
+(3748).ceil(-2); // - > 3800
+
+(65).chr(); // - > "A"
+(75).chr(); // - > "K"
+
+(8).downto(3); // - > [8, 7, 6, 5, 4, 3]
+(8).downto(3, function (n) {
+ // This function is called 6 times receiving n as the value.
+});
+(8).downto(2, null, 2); // - > [8, 6, 4, 2]
+
+(500).duration(); // - > '500 milliseconds'
+(1200).duration(); // - > '1 second'
+(75).minutes().duration(); // - > '1 hour'
+(75).minutes().duration('es'); // - > '1 hora'
+
+(3.241).floor(); // - > 3
+(-3.841).floor(); // - > -4
+(3.241).floor(2); // - > 3.24
+(3748).floor(-2); // - > 3700
+
+(56782).format(); //- > '56,782'
+(56782).format(2); // - > '56,782.00'
+(4388.43).format(2, ' '); // - > '4 388.43'
+(4388.43).format(2, '.', ','); // - > '4.388,43'
+
+(255).hex(); // - > 'ff';
+(255).hex(4); // - > '00ff';
+(23654).hex(); // - > '5c66';
+
+(6).isEven(); // - > true
+(17).isEven(); // - > false
+
+(420).isInteger(); // - > true
+(4.5).isInteger(); // - > false
+
+(6).isMultipleOf(2); // - > true
+(17).isMultipleOf(2); // - > false
+(32).isMultipleOf(4); // - > true
+(34).isMultipleOf(4); // - > false
+
+(3).isOdd(); // - > true
+(18).isOdd(); // - > false
+
+(64).log(2); // - > 6
+(9).log(3); // - > 2
+(5).log(); // - > 1.6094379124341003
+
+(3).pow(3); // - > 27
+(-3).abs(); // - > 3
+(1024).sqrt(); // - > 32
+
+(1000).metric(); // - > "1k"
+(1000000).metric(); // - > "1,000k"
+(1000000).metric(0, false); // - > "1M"
+(1249).metric(2) + 'g'; // - > "1.25kg"
+(0.025).metric() + 'm'; // - > "25mm"
+
+(1).ordinalize(); // - > '1st'
+(2).ordinalize(); // - > '2nd'
+(8).ordinalize(); // - > '8th'
+
+(5).pad(2); // - > '05'
+(-5).pad(4); // - > '-0005'
+(82).pad(3, true); // - > '+082'
+
+(3.241).round(); // - > 3
+(-3.841).round(); // - > -4
+(3.241).round(2); // - > 3.24
+(3748).round(-2); // - > 3800
+
+(8).times(function (i) {
+ // This function is called 8 times.
+});
+
+(420).toNumber(); // - > 420
+
+(5).milliseconds(); // - > 5
+(10).hours(); // - > 36000000
+(1).day(); // - > 86400000
+
+(5).daysAfter('tuesday'); // - > 5 days after tuesday of this week
+(1).yearAfter('January 23, 1997'); // - > January 23, 1998
+
+(5).weeksAgo(); // - > 5 weeks ago
+(1).yearAgo(); // - > January 23, 1996
+
+(5).daysBefore('tuesday'); // - > 5 days before tuesday of this week
+(1).yearBefore('January 23, 1997'); // - > January 23, 1996
+
+(5).weeksFromNow(); // - > 5 weeks ago
+(1).yearFromNow(); // - > January 23, 1998
+
+(2).upto(6); // - > [2, 3, 4, 5, 6]
+(2).upto(6, function (n) {
+ // This function is called 5 times receiving n as the value.
+});
+(2).upto(8, null, 2); // - > [2, 4, 6, 8]
diff --git a/sugar/sugar.d.ts b/sugar/sugar.d.ts
index a2291551dc..936c3121d6 100644
--- a/sugar/sugar.d.ts
+++ b/sugar/sugar.d.ts
@@ -1,4042 +1,4515 @@
-// sugar-1.3.6.d.ts
-// (c) 2012 Josh Baldwin
-// sugar.d.ts may be freely distributed under the MIT license.
-// For all details and documentation:
-// https://github.com/jbaldwin/sugar.d.ts
-
-interface String {
-
- /***
- * @short Adds at [index]. Negative values are also allowed.
- * @param str String to add.
- * @param index Index where str is added. Default = str.length
- * @returns String
- * @extra %insert% is provided as an alias, and is generally more readable when using an index.
- * @example
- *
- * 'schfifty'.add(' five') -> schfifty five
- * 'dopamine'.insert('e', 3) -> dopeamine
- * 'spelling eror'.insert('r', -3) -> spelling error
- *
- ***/
- add(str: string, index?: number): string;
- insert(str: string, index?: number): string;
-
- /***
- * @short Assigns variables to tokens in a string.
- * @method assign(, , ...)
- * @returns String
- * @extra If an object is passed, it's properties can be assigned using
- * the object's keys. If a non-object (string, number, etc.)
- * is passed it can be accessed by the argument number beginning
- * with 1 (as with regex tokens). Multiple objects can be passed
- * and will be merged together (original objects are unaffected).
- * @example
- *
- * 'Welcome, Mr. {name}.'.assign({ name: 'Franklin' }) -> 'Welcome, Mr. Franklin.'
- * 'You are {1} years old today.'.assign(14) -> 'You are 14 years old today.'
- * '{n} and {r}'.assign({ n: 'Cheech' }, { r: 'Chong' }) -> 'Cheech and Chong'
- *
- ***/
- assign(str: string): string;
- assign(strs: string[]): string;
- assign(num: number): string;
- assign(nums: number[]): string;
- assign(obj: { }): string;
- assign(...objs: { }[]): string;
-
- /***
- * @short Gets the character(s) at a given index.
- * @method at(, [loop] = true)
- * @param index Index of the character.
- * @param loop Default = true
- * @returns String or String[]
- * @extra When [loop] is true, overshooting the end of the string
- * (or the beginning) will begin counting from the other end.
- * As an alternate syntax, passing multiple indexes will get
- * the characters at those indexes.
- * @example
- *
- * 'jumpy'.at(0) -> 'j'
- * 'jumpy'.at(2) -> 'm'
- * 'jumpy'.at(5) -> 'j'
- * 'jumpy'.at(5, false) -> ''
- * 'jumpy'.at(-1) -> 'y'
- * 'lucky charms'.at(2,4,6,8) -> ['u','k','y',c']
- *
- ***/
- at(index: number, loop?: bool): string;
- at(indexes: number[], loop?: bool): string[];
-
- /***
- * @short Converts underscores and hyphens to camel case.
- * If [first] is true the first letter will also be capitalized.
- * @method camelize([first] = true)
- * @param first Default = true
- * @returns String
- * @extra If the Inflections package is included acryonyms can also
- * be defined that will be used when camelizing.
- * @example
- *
- * 'caps_lock'.camelize() -> 'CapsLock'
- * 'moz-border-radius'.camelize() -> 'MozBorderRadius'
- * 'moz-border-radius'.camelize(false) -> 'mozBorderRadius'
- *
- ***/
- camelize(first?: bool): string;
-
- /***
- * @short Capitalizes the first character in the string.
- * @method capitalize([all] = false)
- * @param all Default = false
- * @returns String
- * @extra If [all] is true, all words in the string will be capitalized.
- * @example
- *
- * 'hello'.capitalize() -> 'Hello'
- * 'hello kitty'.capitalize() -> 'Hello kitty'
- * 'hello kitty'.capitalize(true) -> 'Hello Kitty'
- *
- ***/
- capitalize(all: bool): string;
-
- /***
- * @short Runs callback [fn] against each character in the string.
- * Returns an array of characters.
- * @method chars([fn])
- * @param fn Callback function.
- * @returns String[]
- * @example
- *
- * 'jumpy'.chars() -> ['j','u','m','p','y']
- * 'jumpy'.chars(function(c) {
- * // Called 5 times: "j","u","m","p","y"
- * });
- *
- ***/
- chars(fn?: Function): string[];
-
- /***
- * @short Runs callback [fn] against each character code in the string.
- Returns an array of character codes.
- * @method codes([fn])
- * @param fn Callback function.
- * @returns number[]
- * @example
- *
- * 'jumpy'.codes() -> [106,117,109,112,121]
- * 'jumpy'.codes(function(c) {
- * // Called 5 times: 106, 117, 109, 112, 121
- * });
- *
- ***/
- codes(fn?: Function): number[];
-
- /***
- * @short Compacts all white space in the string to
- * a single space and trims the ends.
- * @method compact()
- * @returns String
- * @example
- *
- * 'too \n much \n space'.compact() -> 'too much space'
- * 'enough \n '.compact() -> 'enought'
- *
- ***/
- compact(): string;
-
- /***
- * @short Converts underscores and camel casing to hypens.
- * @method dasherize()
- * @returns String
- * @example
- *
- * 'a_farewell_to_arms'.dasherize() -> 'a-farewell-to-arms'
- * 'capsLock'.dasherize() -> 'caps-lock'
- *
- ***/
- dasherize(): string;
-
- /***
- * @short Decodes the string from base64 encoding.
- * @method decodeBase64()
- * @returns String
- * @extra This method wraps the browser native %atob% when available,
- and uses a custom implementation when not available.
- * @example
- *
- * 'aHR0cDovL3R3aXR0ZXIuY29tLw=='.decodeBase64() -> 'http://twitter.com/'
- * 'anVzdCBnb3QgZGVjb2RlZA=='.decodeBase64() -> 'just got decoded!'
- *
- ***/
- decodeBase64(): string;
-
- /***
- * @short Runs callback [fn] against each occurence of [search].
- * @method each([search] = single character, [fn])
- * @returns Array
- * @extra Returns an array of matches. [search] may be either
- * a string or regex, and defaults to every character in the string.
- * @example
- *
- * 'jumpy'.each() -> ['j','u','m','p','y']
- * 'jumpy'.each(/[r-z]/) -> ['u','y']
- * 'jumpy'.each(/[r-z]/, function(m) {
- * // Called twice: "u", "y"
- * });
- *
- ***/
- each(): string[];
- each(search: string, fn?: Function): string[];
- each(search: RegExp, fn?: Function): string[];
- each(search: Function): string[];
-
- /***
- * @short Encodes the string into base64 encoding.
- * @method encodeBase64()
- * @returns String
- * @extra This method wraps the browser native %btoa% when available,
- * and uses a custom implementation when not available.
- * @example
- *
- * 'gonna get encoded!'.encodeBase64() -> 'Z29ubmEgZ2V0IGVuY29kZWQh'
- * 'http://twitter.com/'.encodeBase64() -> 'aHR0cDovL3R3aXR0ZXIuY29tLw=='
- *
- ***/
- encodeBase64(): string;
-
- /***
- * @short Returns true if the string ends with .
- * @method endsWith(, [case] = true)
- * @returns Boolean
- * @extra may be either a string or regex. Case
- * sensitive if [case] is true.
- * @example
- *
- * 'jumpy'.endsWith('py') -> true
- * 'jumpy'.endsWith(/[q-z]/) -> true
- * 'jumpy'.endsWith('MPY') -> false
- * 'jumpy'.endsWith('MPY', false) -> true
- *
- ***/
- endsWith(find: string, case_?: bool): bool;
- endsWith(find: RegExp, case_?: bool): bool;
-
- /***
- * @short Converts HTML characters to their entity equivalents.
- * @method escapeHTML()
- * @returns String
- * @example
- *
- * '
some text
'.escapeHTML() -> '<p>some text</p>'
- * 'one & two'.escapeHTML() -> 'one & two'
- *
- ***/
- escapeHTML(): string;
-
- /***
- * @short Escapes all RegExp tokens in the string.
- * @method escapeRegExp()
- * @returns String
- * @example
- *
- * 'really?'.escapeRegExp() -> 'really\?'
- * 'yes.'.escapeRegExp() -> 'yes\.'
- * '(not really)'.escapeRegExp() -> '\(not really\)'
- *
- ***/
- escapeRegExp(): string;
-
- /***
- * @short Escapes characters in a string to make a valid URL.
- * @method escapeURL([param] = false)
- * @returns String
- * @extra If [param] is true, it will also escape valid URL
- * characters for use as a URL parameter.
- * @example
- *
- * 'http://foo.com/"bar"'.escapeURL() -> 'http://foo.com/%22bar%22'
- * 'http://foo.com/"bar"'.escapeURL(true) -> 'http%3A%2F%2Ffoo.com%2F%22bar%22'
- *
- ***/
- escapeURL(param?: bool): string;
-
- /***
- * @short Returns the first [n] characters of the string.
- * @method first([n] = 1)
- * @returns String
- * @example
- *
- * 'lucky charms'.first() -> 'l'
- * 'lucky charms'.first(3) -> 'luc'
- *
- ***/
- first(n?: number): string;
-
- /***
- * @short Returns a section of the string starting from [index].
- * @method from([index] = 0)
- * @returns String
- * @example
- *
- * 'lucky charms'.from() -> 'lucky charms'
- * 'lucky charms'.from(7) -> 'harms'
- *
- ***/
- from(index?: number): string;
-
- /***
- * @short Converts full-width characters (zenkaku) to half-width (hankaku).
- * @method hankaku([mode] = 'all')
- * @returns String
- * @extra [mode] accepts any combination of
- * "a" (alphabet),
- * "n" (numbers),
- * "k" (katakana),
- * "s" (spaces),
- * "p" (punctuation),
- * or "all".
- * @example
- *
- * 'タロウ YAMADAです!'.hankaku() -> 'タロウ YAMADAです!'
- * 'タロウ YAMADAです!'.hankaku('a') -> 'タロウ YAMADAです!'
- * 'タロウ YAMADAです!'.hankaku('alphabet') -> 'タロウ YAMADAです!'
- * 'タロウです! 25歳です!'.hankaku('katakana', 'numbers') -> 'タロウです! 25歳です!'
- * 'タロウです! 25歳です!'.hankaku('k', 'n') -> 'タロウです! 25歳です!'
- * 'タロウです! 25歳です!'.hankaku('kn') -> 'タロウです! 25歳です!'
- * 'タロウです! 25歳です!'.hankaku('sp') -> 'タロウです! 25歳です!'
- *
- ***/
- hankaku(mode?: string): string;
-
- /***
- * @short Returns true if the string matches .
- * @method has()
- * @returns Boolean
- * @extra may be a string or regex.
- * @example
- *
- * 'jumpy'.has('py') -> true
- * 'broken'.has(/[a-n]/) -> true
- * 'broken'.has(/[s-z]/) -> false
- *
- ***/
- has(find: string): bool;
- has(find: RegExp): bool;
-
- /***
- * @short Returns true if the string contains any characters in that script.
- * @method has[Script]()
- * @returns Boolean
- *
- * @set
- * hasArabic
- * hasCyrillic
- * hasGreek
- * hasHangul
- * hasHan
- * hasKanji
- * hasHebrew
- * hasHiragana
- * hasKana
- * hasKatakana
- * hasLatin
- * hasThai
- * hasDevanagari
- *
- * @example
- *
- * 'أتكلم'.hasArabic() -> true
- * 'визит'.hasCyrillic() -> true
- * '잘 먹겠습니다!'.hasHangul() -> true
- * 'ミックスです'.hasKatakana() -> true
- * "l'année".hasLatin() -> true
- *
- ***/
- hasArabic(): bool;
- hasCyrillic(): bool;
- hasGreek(): bool;
- hasHangul(): bool;
- hasHan(): bool;
- hasKanji(): bool;
- hasHebrew(): bool;
- hasHiragana(): bool;
- hasKana(): bool;
- hasKatakana(): bool;
- hasLatin(): bool;
- hasThai(): bool;
- hasDevanagari(): bool;
-
- /***
- * @method hiragana([all] = true)
- * @returns String
- * @short Converts katakana into hiragana.
- * @extra If [all] is false, only full-width katakana will be converted.
- * @example
- *
- * 'カタカナ'.hiragana() -> 'かたかな'
- * 'コンニチハ'.hiragana() -> 'こんにちは'
- * 'カタカナ'.hiragana() -> 'かたかな'
- * 'カタカナ'.hiragana(false) -> 'カタカナ'
- *
- ***/
- hiragana(all?: bool): string;
-
- /***
- * @method humanize()
- * @returns String
- * @short Creates a human readable string.
- * @extra Capitalizes the first word and turns underscores into spaces and strips a trailing '_id', if any. Like String#titleize, this is meant for creating pretty output.
- * @example
- *
- * 'employee_salary'.humanize() -> 'Employee salary'
- * 'author_id'.humanize() -> 'Author'
- *
- ***/
- humanize(): string;
-
- /***
- * @short Returns true if the string has a length of 0 or contains only whitespace.
- * @method isBlank()
- * @returns Boolean
- * @example
- *
- * ''.isBlank() -> true
- * ' '.isBlank() -> true
- * 'noway'.isBlank() -> false
- *
- ***/
- isBlank(): bool;
-
- /***
- * @short Returns true if the string contains only characters in that script. Whitespace is ignored.
- * @method is[Script]()
- * @returns Boolean
- *
- * @set
- * isArabic
- * isCyrillic
- * isGreek
- * isHangul
- * isHan
- * isKanji
- * isHebrew
- * isHiragana
- * isKana
- * isKatakana
- * isKatakana
- * isThai
- * isDevanagari
- *
- * @example
- *
- * 'أتكلم'.isArabic() -> true
- * 'визит'.isCyrillic() -> true
- * '잘 먹겠습니다!'.isHangul() -> true
- * 'ミックスです'.isKatakana() -> false
- * "l'année".isLatin() -> true
- *
- ***/
- isArabic(): bool;
- isCyrillic(): bool;
- isGreek(): bool;
- isHangul(): bool;
- isHan(): bool;
- isKanji(): bool;
- isHebrew(): bool;
- isHiragana(): bool;
- isKana(): bool;
- isKatakana(): bool;
- isLatin(): bool;
- isThai(): bool;
- isDevanagari(): bool;
-
- /***
- * @short Converts hiragana into katakana.
- * @method katakana()
- * @returns String
- * @example
- *
- * 'かたかな'.katakana() -> 'カタカナ'
- * 'こんにちは'.katakana() -> 'コンニチハ'
- *
- ***/
- katakana(): string;
-
- /***
- * @short Returns the last [n] characters of the string.
- * @method last([n] = 1)
- * @returns String
- * @example
- *
- * 'lucky charms'.last() -> 's'
- * 'lucky charms'.last(3) -> 'rms'
- *
- ***/
- last(n?: number): string;
-
- /***
- * @short Runs callback [fn] against each line in the string.
- * Returns an array of lines.
- * @method lines([fn])
- * @returns Array
- * @example
- *
- * 'broken wear\nand\njumpy jump'.lines() -> ['broken wear','and','jumpy jump']
- * 'broken wear\nand\njumpy jump'.lines(function(l) {
- * // Called three times: "broken wear", "and", "jumpy jump"
- * });
- *
- ***/
- lines(fn?: Function): string[];
-
- /***
- * @short Finds the namespace or property indicated by the string.
- * @method namespace([init] = global)
- * @returns Mixed
- * @extra [init] can be passed to provide a starting context,
- * otherwise the global context will be used. If any
- * level returns a falsy value, that will be the final result.
- * @example
- *
- * 'Path.To.Namespace'.namespace() -> Path.To.Namespace
- * '$.fn'.namespace() -> $.fn
- *
- ***/
- namespace(init?: any): any;
-
- /***
- * @short Returns the string with accented and non-standard Latin-based
- * characters converted into ASCII approximate equivalents.
- * @method normalize()
- * @returns String
- * @example
- *
- * 'á'.normalize() -> 'a'
- * 'Ménage à trois'.normalize() -> 'Menage a trois'
- * 'Volkswagen'.normalize() -> 'Volkswagen'
- * 'FULLWIDTH'.normalize() -> 'FULLWIDTH'
- *
- ***/
- normalize(): string;
-
- /***
- * @short Pads either/both sides of the string.
- * @method pad[Side]( = '', [num] = 1)
- * @returns String
- * @extra [num] is the number of characters on each side,
- * and [padding] is the character to pad with.
- *
- * @set
- * pad
- * padLeft
- * padRight
- *
- * @example
- *
- * 'wasabi'.pad('-') -> '-wasabi-'
- * 'wasabi'.pad('-', 2) -> '--wasabi--'
- * 'wasabi'.padLeft('-', 2) -> '--wasabi'
- * 'wasabi'.padRight('-', 2) -> 'wasabi--'
- *
- ***/
- pad(padding: string, num?: number): string;
- padLeft(padding: string, num?: number): string;
- padRight(padding: string, num?: number): string;
-
- /***
- * @short Runs callback [fn] against each paragraph in the string.
- * Returns an array of paragraphs.
- * @method paragraphs([fn])
- * @returns Array
- * @extra A paragraph here is defined as a block of text bounded
- * by two or more line breaks.
- * @example
- *
- * 'Once upon a time.\n\nIn the land of oz...'.paragraphs() -> ['Once upon a time.','In the land of oz...']
- * 'Once upon a time.\n\nIn the land of oz...'.paragraphs(function(p) {
- * // Called twice: "Once upon a time.", "In teh land of oz..."
- * });
- *
- ***/
- paragraphs(fn?: Function): string[];
-
- /***
- * @short Replaces special characters in a string so that it may
- * be used as part of a pretty URL.
- * @method parameterize()
- * @returns String
- * @example
- *
- * 'hell, no!'.parameterize() -> 'hell-no'
- *
- ***/
- parameterize(): string;
-
- /***
- * @short Returns the plural form of the word in the string.
- * @method pluralize()
- * @returns String
- * @example
- *
- * 'post'.pluralize() -> 'posts'
- * 'octopus'.pluralize() -> 'octopi'
- * 'sheep'.pluralize() -> 'sheep'
- * 'words'.pluralize() -> 'words'
- * 'CamelOctopus'.pluralize() -> 'CamelOctopi'
- *
- ***/
- pluralize(): string;
-
- /***
- * @short Removes any part of the string that matches .
- * @method remove()
- * @returns String
- * @extra can be a string or a regex.
- * @example
- *
- * 'schfifty five'.remove('f') -> 'schity ive'
- * 'schfifty five'.remove(/[a-f]/g) -> 'shity iv'
- *
- ***/
- remove(find: string): string;
- remove(find: RegExp): string;
-
- /***
- * @short Removes all HTML tags and their contents from the string.
- * @method removeTags([tag1], [tag2], ...)
- * @returns String
- * @extra Tags to remove may be enumerated in the parameters,
- * otherwise will remove all.
- * @example
- *
- * '
just some text
'.removeTags() -> ''
- * '
just some text
'.removeTags('b') -> '
just text
'
- *
- ***/
- removeTags(): string;
- removeTags(tag: string): string;
- removeTags(...tags: string[]): string;
-
- /***
- * @short Returns the string repeated [num] times.
- * @method repeat([num] = 0)
- * @returns String
- * @example
- *
- * 'jumpy'.repeat(2) -> 'jumpyjumpy'
- * 'a'.repeat(5) -> 'aaaaa'
- * 'a'.repeat(0) -> ''
- *
- ***/
- repeat(num?: number): string;
-
- /***
- * @short Reverses the string.
- * @method reverse()
- * @returns String
- * @example
- *
- * 'jumpy'.reverse() -> 'ypmuj'
- * 'lucky charms'.reverse() -> 'smrahc ykcul'
- *
- ***/
- reverse(): string;
-
- /***
- * @short Shifts each character in the string places in the character map.
- * @method shift()
- * @returns Array
- * @example
- *
- * 'a'.shift(1) -> 'b'
- * 'ク'.shift(1) -> 'グ'
- *
- ***/
- shift(num: number): string[];
-
- /***
- * @short The reverse of String#pluralize.
- * Returns the singular form of a word in a string.
- * @method singularize()
- * @returns String
- * @example
- *
- * 'posts'.singularize() -> 'post'
- * 'octopi'.singularize() -> 'octopus'
- * 'sheep'.singularize() -> 'sheep'
- * 'word'.singularize() -> 'word'
- * 'CamelOctopi'.singularize() -> 'CamelOctopus'
- *
- ***/
- singularize(): string;
-
- /***
- * @short Converts camel case, underscores, and hyphens to a properly spaced string.
- * @method spacify()
- * @returns String
- * @example
- *
- * 'camelCase'.spacify() -> 'camel case'
- * 'an-ugly-string'.spacify() -> 'an ugly string'
- * 'oh-no_youDid-not'.spacify().capitalize(true) -> 'something else'
- *
- ***/
- spacify(): string;
-
- /***
- * @short Returns true if the string starts with .
- * @method startsWith(, [case] = true)
- * @returns Boolean
- * @extra may be either a string or regex.
- * Case sensitive if [case] is true.
- * @example
- *
- * 'hello'.startsWith('hell') -> true
- * 'hello'.startsWith(/[a-h]/) -> true
- * 'hello'.startsWith('HELL') -> false
- * 'hello'.startsWith('HELL', false) -> true
- *
- ***/
- startsWith(find: string, case_?: bool): bool;
- startsWith(find: RegExp, case_?: bool): bool;
-
- /***
- * @short Strips all HTML tags from the string.
- * @method stripTags([tag1], [tag2], ...)
- * @returns String
- * @extra Tags to strip may be enumerated in the parameters,
- * otherwise will strip all.
- * @example
- *
- * '
just some text
'.stripTags() -> 'just some text'
- * '
just some text
'.stripTags('p') -> 'just some text'
- *
- ***/
- stripTags(): string;
- stripTags(tag: string): string;
- stripTags(...tags: string[]): string;
-
- /***
- * @short Creates a title version of the string.
- * @method titleize()
- * @returns String
- * @extra Capitalizes all the words and replaces some characters
- * in the string to create a nicer looking title.
- * String#titleize is meant for creating pretty output.
- * @example
- *
- * 'man from the boondocks'.titleize() -> 'Man from the Boondocks'
- * 'x-men: the last stand'.titleize() -> 'X Men: The Last Stand'
- * 'TheManWithoutAPast'.titleize() -> 'The Man Without a Past'
- * 'raiders_of_the_lost_ark'.titleize() -> 'Raiders of the Lost Ark'
- *
- ***/
- titleize(): string;
-
- /***
- * @short Returns a section of the string ending at [index].
- * @method to([index] = end)
- * @returns String
- * @example
- *
- * 'lucky charms'.to() -> 'lucky charms'
- * 'lucky charms'.to(7) -> 'lucky ch'
- *
- ***/
- to(index?: number): string;
-
- /***
- * @short Converts the string into a number.
- * @method toNumber([base] = 10)
- * @returns Number
- * @extra Any value with a "." fill be converted to a floating point value,
- * otherwise an integer.
- * @example
- *
- * '153'.toNumber() -> 153
- * '12,000'.toNumber() -> 12000
- * '10px'.toNumber() -> 10
- * 'ff'.toNumber(16) -> 255
- *
- ***/
- toNumber(base?: number): number;
-
- /***
- * @short Removes leading and/or trailing whitespace from the string.
- * @method trim[Side]()
- * @returns String
- * @extra Whitespace is defined as line breaks, tabs, and any character
- * in the "Space, Separator" Unicode category, conforming to the
- * the ES5 spec. The standard %trim% method is only added when
- * not fully supported natively.
- *
- * @set
- * trim
- * trimLeft
- * trimRight
- *
- * @example
- *
- * ' wasabi '.trim() -> 'wasabi'
- * ' wasabi '.trimLeft() -> 'wasabi '
- * ' wasabi '.trimRight() -> ' wasabi'
- *
- ***/
- // Duplicate from lib.d.ts
- // trim(): string;
- trimLeft(): string;
- trimRight(): string;
-
- /***
- * @short Truncates a string.
- * @method truncate(, [split] = true, [from] = 'right', [ellipsis] = '...')
- * @returns Object
- * @extra If [split] is %false%, will not split words up, and instead
- * discard the word where the truncation occurred. [from] can
- * also be %"middle"% or %"left"%.
- * @example
- *
- * 'just sittin on the dock of the bay'.truncate(20) -> 'just sittin on the do...'
- * 'just sittin on the dock of the bay'.truncate(20, false) -> 'just sittin on the...'
- * 'just sittin on the dock of the bay'.truncate(20, true, 'middle') -> 'just sitt...of the bay'
- * 'just sittin on the dock of the bay'.truncate(20, true, 'left') -> '...the dock of the bay'
- *
- ***/
- truncate(length: number, split?: bool, from?: string, ellipsis?: string): string;
-
- /***
- * @short Converts hyphens and camel casing to underscores.
- * @method underscore()
- * @returns String
- * @example
- *
- * 'a-farewell-to-arms'.underscore() -> 'a_farewell_to_arms'
- * 'capsLock'.underscore() -> 'caps_lock'
- *
- ***/
- underscore(): string;
-
- /***
- * @short Restores escaped HTML characters.
- * @method unescapeHTML([partial] = false)
- * @returns String
- * @example
- *
- * '<p>some text</p>'.unescapeHTML() -> '
some text
'
- * 'one & two'.unescapeHTML() -> 'one & two'
- *
- ***/
- unescapeHTML(partial?: bool): string;
-
- /***
- * @short Restores escaped characters in a URL escaped string.
- * @method unescapeURL([partial] = false)
- * @returns String
- * @extra If [partial] is true, it will only unescape non-valid URL characters. [partial] is included here for completeness, but should very rarely be needed.
- * @example
- *
- * 'http%3A%2F%2Ffoo.com%2Fthe%20bar'.unescapeURL() -> 'http://foo.com/the bar'
- * 'http%3A%2F%2Ffoo.com%2Fthe%20bar'.unescapeURL(true) -> 'http%3A%2F%2Ffoo.com%2Fthe bar'
- *
- ***/
- unescapeURL(partial?: bool): string;
-
- /***
- * @short Runs callback [fn] against each word in the string.
- * Returns an array of words.
- * @method words([fn])
- * @returns String[]
- * @extra A "word" here is defined as any sequence of non-whitespace characters.
- * @example
- *
- * 'broken wear'.words() -> ['broken','wear']
- * 'broken wear'.words(function(w) {
- * // Called twice: "broken", "wear"
- * });
- *
- ***/
- words(fn?: Function): string[];
-
- /***
- * @short Converts half-width characters (hankaku) to full-width (zenkaku).
- * @method zenkaku([mode] = 'all')
- * @returns String
- * @extra [mode] accepts any combination of
- * "a" (alphabet),
- * "n" (numbers),
- * "k" (katakana),
- * "s" (spaces),
- * "p" (punctuation),
- * or "all".
- * @example
- *
- * 'タロウ YAMADAです!'.zenkaku() -> 'タロウ YAMADAです!'
- * 'タロウ YAMADAです!'.zenkaku('a') -> 'タロウ YAMADAです!'
- * 'タロウ YAMADAです!'.zenkaku('alphabet') -> 'タロウ YAMADAです!'
- * 'タロウです! 25歳です!'.zenkaku('katakana', 'numbers') -> 'タロウです! 25歳です!'
- * 'タロウです! 25歳です!'.zenkaku('k', 'n') -> 'タロウです! 25歳です!'
- * 'タロウです! 25歳です!'.zenkaku('kn') -> 'タロウです! 25歳です!'
- * 'タロウです! 25歳です!'.zenkaku('sp') -> 'タロウです! 25歳です!'
- *
- ***/
- zenkaku(mode?: string): string;
-}
-
-interface Number {
-
- /***
- * @short Returns a random integer between [n1] and [n2].
- * @method Number.random([n1], [n2])
- * @returns Number
- * @extra If only 1 number is passed, the other will be 0. If none are passed, the number will be either 0 or 1.
- * @example
- *
- * Number.random(50, 100) -> ex. 85
- * Number.random(50) -> ex. 27
- * Number.random() -> ex. 0
- *
- ***/
- random(n1?: number, n2?: number): number;
-
- /***
- * @short Returns an abbreviated form of the number.
- * @method abbr([precision] = 0)
- * @returns String
- * @extra [precision] will round to the given precision.
- * @example
- *
- * (1000).abbr() -> "1k"
- * (1000000).abbr() -> "1m"
- * (1280).abbr(1) -> "1.3k"
- *
- ***/
- abbr(precision?: number): string;
-
- /***
- * @short Returns an abbreviated form of the number, considered to be "Bytes".
- * @method bytes([precision] = 0, [limit] = 4)
- * @returns String
- * @extra [precision] will round to the given precision.
- * [limit] is the upper limit for the units.
- * The default is %4%, which is "terabytes" (TB).
- * If [limit] is %false%, the upper limit will be "exa".
- * @example
- *
- * (1000).bytes() -> "1kB"
- * (1000).bytes(2) -> "0.98kB"
- * ((10).pow(20)).bytes() -> "90,949,470TB"
- * ((10).pow(20)).bytes(0, false) -> "87EB"
- *
- ***/
- bytes(precision?: number, limit?: number): string;
- bytes(precision?: number, limit?: bool): string;
-
- /***
- * @short Shortcut for %Math.ceil% that also allows a .
- * @method ceil( = 0)
- * @returns Number
- *
- * @example
- *
- * (3.241).ceil() -> 4
- * (-3.241).ceil() -> -3
- * (3.241).ceil(2) -> 3.25
- * (3748).ceil(-2) -> 3800
- *
- ***/
- ceil(precision?: number): number;
-
- /***
- * @short Returns a string at the code point of the number.
- * @method chr()
- * @returns String
- * @example
- *
- * (65).chr() -> "A"
- * (75).chr() -> "K"
- *
- ***/
- chr(): string;
-
- /***
- * @short Returns an array containing numbers from the number down to .
- * @method downto(, [fn], [step] = 1)
- * @returns Array
- * @extra Optionally calls [fn] callback for each number in that array.
- * [step] allows multiples greater than 1.
- * @example
- *
- * (8).downto(3) -> [8, 7, 6, 5, 4, 3]
- * (8).downto(3, function(n) {
- * // This function is called 6 times receiving n as the value.
- * });
- * (8).downto(2, null, 2) -> [8, 6, 4, 2]
- *
- ***/
- downto(num: number, fn?: Function, step?: number): number[];
-
- /***
- * @short Takes the number as milliseconds and returns a unit-
- * adjusted localized string.
- * @method duration([locale] = currentLocale)
- * @returns String
- * @extra This method is the same as %Date#relative% without
- * the localized equivalent of "from now" or "ago".
- * [locale] can be passed as the first (and only) parameter.
- * Note that this method is only available when the dates
- * package is included.
- * @example
- *
- * (500).duration() -> '500 milliseconds'
- * (1200).duration() -> '1 second'
- * (75).minutes().duration() -> '1 hour'
- * (75).minutes().duration('es') -> '1 hora'
- *
- ***/
- duration(locale?: string): string;
-
- /***
- * @short Shortcut for %Math.floor% that also allows a .
- * @method floor( = 0)
- * @returns Number
- * @example
- *
- * (3.241).floor() -> 3
- * (-3.841).floor() -> -4
- * (3.241).floor(2) -> 3.24
- * (3748).floor(-2) -> 3700
- *
- ***/
- floor(precision?: number): number;
-
- /***
- * @short Formats the number to a readable string.
- * @method format([place] = 0, [thousands] = ',', [decimal] = '.')
- * @returns String
- * @extra If [place] is %undefined%, will automatically determine the place.
- * [thousands] is the character used for the thousands separator.
- * [decimal] is the character used for the decimal point.
- * @example
- *
- * (56782).format() -> '56,782'
- * (56782).format(2) -> '56,782.00'
- * (4388.43).format(2, ' ') -> '4 388.43'
- * (4388.43).format(2, '.', ',') -> '4.388,43'
- *
- ***/
- format(place?: number, thousands?: string, decimal?: string): string;
-
- /***
- * @short Converts the number to hexidecimal.
- * @method hex([pad] = 1)
- * @returns String
- * @extra [pad] will pad the resulting string to that many places.
- * @example
- *
- * (255).hex() -> 'ff';
- * (255).hex(4) -> '00ff';
- * (23654).hex() -> '5c66';
- *
- ***/
- hex(pad?: number): string;
-
- /***
- * @short Returns true if the number is even.
- * @method isEven()
- * @returns Boolean
- * @example
- *
- * (6).isEven() -> true
- * (17).isEven() -> false
- *
- ***/
- isEven(): bool;
-
- /***
- * @short Returns true if the number has no trailing decimal.
- * @method isInteger()
- * @returns Boolean
- * @example
- *
- * (420).isInteger() -> true
- * (4.5).isInteger() -> false
- *
- ***/
- isInteger(): bool;
-
- /***
- * @short Returns true if the number is a multiple of .
- * @method isMultipleOf()
- * @returns Boolean
- * @example
- *
- * (6).isMultipleOf(2) -> true
- * (17).isMultipleOf(2) -> false
- * (32).isMultipleOf(4) -> true
- * (34).isMultipleOf(4) -> false
- *
- ***/
- isMultipleOf(num: number): bool;
-
- /***
- * @short Returns true if the number is odd.
- * @method isOdd()
- * @returns Boolean
- * @example
- *
- * (3).isOdd() -> true
- * (18).isOdd() -> false
- *
- ***/
- isOdd(): bool;
-
- /***
- * @short Returns the logarithm of the number with base ,
- * or natural logarithm of the number if is undefined.
- * @method log( = Math.E)
- * @returns Number
- * @example
- *
- * (64).log(2) -> 6
- * (9).log(3) -> 2
- * (5).log() -> 1.6094379124341003
- *
- ***/
- log(base?: number): number;
-
- /***
- * @short Math related functions are mapped as shortcuts to numbers and are identical. Note that %Number#log% provides some special defaults.
- * @method [math]()
- * @returns Number
- *
- * @set
- * abs
- * sin
- * asin
- * cos
- * acos
- * tan
- * atan
- * sqrt
- * exp
- * pow
- *
- * @example
- *
- * (3).pow(3) -> 27
- * (-3).abs() -> 3
- * (1024).sqrt() -> 32
- *
- ***/
- abs(): number;
- sin(): number;
- asin(): number;
- cos(): number;
- acos(): number;
- tan(): number;
- atan(): number;
- sqrt(): number;
- exp(): number;
- pow(num: number): number;
-
- /***
- * @short Returns the number as a string in metric notation.
- * @method metric([precision] = 0, [limit] = 1)
- * @returns String
- * @extra [precision] will round to the given precision.
- * Both very large numbers and very small numbers are supported.
- * [limit] is the upper limit for the units.
- * The default is %1%, which is "kilo".
- * If [limit] is %false%, the upper limit will be "exa".
- * The lower limit is "nano", and cannot be changed.
- * @example
- *
- * (1000).metric() -> "1k"
- * (1000000).metric() -> "1,000k"
- * (1000000).metric(0, false) -> "1M"
- * (1249).metric(2) + 'g' -> "1.25kg"
- * (0.025).metric() + 'm' -> "25mm"
- *
- ***/
- metric(precision?: number, limit?: number): string;
- metric(precision?: number, limit?: bool): string;
-
- /***
- * @short Returns an ordinalized (English) string, i.e. "1st", "2nd", etc.
- * @method ordinalize()
- * @returns String
- * @example
- *
- * (1).ordinalize() -> '1st';
- * (2).ordinalize() -> '2nd';
- * (8).ordinalize() -> '8th';
- *
- ***/
- ordinalize(): string;
-
- /***
- * @short Pads a number with "0" to .
- * @method pad( = 0, [sign] = false, [base] = 10)
- * @returns String
- * @extra [sign] allows you to force the sign as well (+05, etc). [base] can change the base for numeral conversion.
- * @example
- *
- * (5).pad(2) -> '05'
- * (-5).pad(4) -> '-0005'
- * (82).pad(3, true) -> '+082'
- *
- ***/
- pad(place?: number, sign?: bool, base?: number): string;
-
- /***
- * @short Shortcut for %Math.round% that also allows a .
- * @method round( = 0)
- * @returns Number
- *
- * @example
- *
- * (3.241).round() -> 3
- * (-3.841).round() -> -4
- * (3.241).round(2) -> 3.24
- * (3748).round(-2) -> 3800
- *
- ***/
- round(precision?: number): number;
-
- /***
- * @short Calls a number of times equivalent to the number.
- * @method times()
- * @returns Number
- * @example
- *
- * (8).times(function(i) {
- * // This function is called 8 times.
- * });
- *
- ***/
- times(fn: Function): number;
-
- /***
- * @short Returns a number. This is mostly for compatibility reasons.
- * @method toNumber()
- * @returns Number
- * @example
- *
- * (420).toNumber() -> 420
- *
- ***/
- toNumber(): number;
-
- /***
- * @short Takes the number as a corresponding unit of time and
- * converts to milliseconds.
- * @method [unit]()
- * @returns Number
- * @extra Method names can be both singular and plural.
- * Note that as "a month" is ambiguous as a unit of time,
- * %months% will be equivalent to 30.4375 days, the average
- * number in a month. Be careful using %months% if you need
- * exact precision.
- *
- * @set
- * millisecond
- * milliseconds
- * second
- * seconds
- * minute
- * minutes
- * hour
- * hours
- * day
- * days
- * week
- * weeks
- * month
- * months
- * year
- * years
- *
- * @example
- *
- * (5).milliseconds() -> 5
- * (10).hours() -> 36000000
- * (1).day() -> 86400000
- *
- ***/
- millisecond(): number;
- milliseconds(): number;
- second(): number;
- seconds(): number;
- minute(): number;
- minutes(): number;
- hour(): number;
- hours(): number;
- day(): number;
- days(): number;
- week(): number;
- weeks(): number;
- month(): number;
- months(): number;
- year(): number;
- years(): number;
-
- /***
- * @short Returns a date units after [d], where is the number.
- * @method [unit]After([d], [locale] = currentLocale)
- * @returns Date
- * @extra [d] will accept a date object, timestamp, or text format.
- * Note that "months" is ambiguous as a unit of time. If the
- * target date falls on a day that does not exist
- * (ie. August 31 -> February 31), the date will be shifted
- * to the last day of the month. Be careful using %monthsAfter%
- * if you need exact precision. See @date_format for more.
- *
- * @set
- * millisecondAfter
- * millisecondsAfter
- * secondAfter
- * secondsAfter
- * minuteAfter
- * minutesAfter
- * hourAfter
- * hoursAfter
- * dayAfter
- * daysAfter
- * weekAfter
- * weeksAfter
- * monthAfter
- * monthsAfter
- * yearAfter
- * yearsAfter
- *
- * @example
- *
- * (5).daysAfter('tuesday') -> 5 days after tuesday of this week
- * (1).yearAfter('January 23, 1997') -> January 23, 1998
- *
- ***/
- millisecondAfter(d: string, locale?: string): Date;
- millisecondAfter(d: Date, locale?: string): Date;
- millisecondsAfter(d: string, locale?: string): Date;
- millisecondsAfter(d: Date, locale?: string): Date;
- secondAfter(d: string, locale?: string): Date;
- secondAfter(d: Date, locale?: string): Date;
- secondsAfter(d: string, locale?: string): Date;
- secondsAfter(d: Date, locale?: string): Date;
- minuteAfter(d: string, locale?: string): Date;
- minuteAfter(d: Date, locale?: string): Date;
- minutesAfter(d: string, locale?: string): Date;
- minutesAfter(d: Date, locale?: string): Date;
- hourAfter(d: string, locale?: string): Date;
- hourAfter(d: Date, locale?: string): Date;
- hoursAfter(d: string, locale?: string): Date;
- hoursAfter(d: Date, locale?: string): Date;
- dayAfter(d: string, locale?: string): Date;
- dayAfter(d: Date, locale?: string): Date;
- daysAfter(d: string, locale?: string): Date;
- daysAfter(d: Date, locale?: string): Date;
- weekAfter(d: string, locale?: string): Date;
- weekAfter(d: Date, locale?: string): Date;
- weeksAfter(d: string, locale?: string): Date;
- weeksAfter(d: Date, locale?: string): Date;
- monthAfter(d: string, locale?: string): Date;
- monthAfter(d: Date, locale?: string): Date;
- monthsAfter(d: string, locale?: string): Date;
- yearAfter(d: string, locale?: string): Date;
- yearAfter(d: Date, locale?: string): Date;
- yearsAfter(d: string, locale?: string): Date;
- yearsAfter(d: Date, locale?: string): Date;
-
- /***
- * @short Returns a date that is units ago.
- * @method [unit]Ago()
- * @returns Date
- * @extra Note that "months" is ambiguous as a unit of time.
- * If the target date falls on a day that does not exist
- * (ie. August 31 -> February 31), the date will be shifted
- * to the last day of the month. Be careful using %monthsAgo%
- * if you need exact precision.
- *
- * @set
- * millisecondAgo
- * millisecondsAgo
- * secondAgo
- * secondsAgo
- * minuteAgo
- * minutesAgo
- * hourAgo
- * hoursAgo
- * dayAgo
- * daysAgo
- * weekAgo
- * weeksAgo
- * monthAgo
- * monthsAgo
- * yearAgo
- * yearsAgo
- *
- * @example
- *
- * (5).weeksAgo() -> 5 weeks ago
- * (1).yearAgo() -> January 23, 1996
- *
- ***/
- millisecondAgo(): Date;
- millisecondsAgo(): Date;
- secondAgo(): Date;
- secondsAgo(): Date;
- minuteAgo(): Date;
- minutesAgo(): Date;
- hourAgo(): Date;
- hoursAgo(): Date;
- dayAgo(): Date;
- daysAgo(): Date;
- weekAgo(): Date;
- weeksAgo(): Date;
- monthAgo(): Date;
- monthsAgo(): Date;
- yearAgo(): Date;
- yearsAgo(): Date;
-
- /***
- * @short Returns a date that is units before [d], where is the number.
- * @method [unit]Before([d], [locale] = currentLocale)
- * @returns Date
- * @extra [d] will accept a date object, timestamp, or text format.
- * Note that "months" is ambiguous as a unit of time. If the
- * target date falls on a day that does not exist
- * (ie. August 31 -> February 31), the date will be shifted to
- * the last day of the month. Be careful using %monthsBefore%
- * if you need exact precision. See @date_format for more.
- *
- * @set
- * millisecondBefore
- * millisecondsBefore
- * secondBefore
- * secondsBefore
- * minuteBefore
- * minutesBefore
- * hourBefore
- * hoursBefore
- * dayBefore
- * daysBefore
- * weekBefore
- * weeksBefore
- * monthBefore
- * monthsBefore
- * yearBefore
- * yearsBefore
- *
- * @example
- *
- * (5).daysBefore('tuesday') -> 5 days before tuesday of this week
- * (1).yearBefore('January 23, 1997') -> January 23, 1996
- *
- ***/
- millisecondBefore(d: string, locale?: string): Date;
- millisecondBefore(d: Date, locale?: string): Date;
- millisecondsBefore(d: string, locale?: string): Date;
- millisecondsBefore(d: Date, locale?: string): Date;
- secondBefore(d: string, locale?: string): Date;
- secondBefore(d: Date, locale?: string): Date;
- secondsBefore(d: string, locale?: string): Date;
- secondsBefore(d: Date, locale?: string): Date;
- minuteBefore(d: string, locale?: string): Date;
- minuteBefore(d: Date, locale?: string): Date;
- minutesBefore(d: string, locale?: string): Date;
- minutesBefore(d: Date, locale?: string): Date;
- hourBefore(d: string, locale?: string): Date;
- hourBefore(d: Date, locale?: string): Date;
- hoursBefore(d: string, locale?: string): Date;
- hoursBefore(d: Date, locale?: string): Date;
- dayBefore(d: string, locale?: string): Date;
- dayBefore(d: Date, locale?: string): Date;
- daysBefore(d: string, locale?: string): Date;
- daysBefore(d: Date, locale?: string): Date;
- weekBefore(d: string, locale?: string): Date;
- weekBefore(d: Date, locale?: string): Date;
- weeksBefore(d: string, locale?: string): Date;
- weeksBefore(d: Date, locale?: string): Date;
- monthBefore(d: string, locale?: string): Date;
- monthBefore(d: Date, locale?: string): Date;
- monthsBefore(d: string, locale?: string): Date;
- monthsBefore(d: Date, locale?: string): Date;
- yearBefore(d: string, locale?: string): Date;
- yearBefore(d: Date, locale?: string): Date;
- yearsBefore(d: string, locale?: string): Date;
- yearsBefore(d: Date, locale?: string): Date;
-
- /***
- * @short Returns a date units from now.
- * @method [unit]FromNow()
- * @returns Date
- * @extra Note that "months" is ambiguous as a unit of time.
- * If the target date falls on a day that does not exist
- * (ie. August 31 -> February 31), the date will be shifted
- * to the last day of the month. Be careful using %monthsFromNow%
- * if you need exact precision.
- *
- * @set
- * millisecondFromNow
- * millisecondsFromNow
- * secondFromNow
- * secondsFromNow
- * minuteFromNow
- * minutesFromNow
- * hourFromNow
- * hoursFromNow
- * dayFromNow
- * daysFromNow
- * weekFromNow
- * weeksFromNow
- * monthFromNow
- * monthsFromNow
- * yearFromNow
- * yearsFromNow
- *
- * @example
- *
- * (5).weeksFromNow() -> 5 weeks ago
- * (1).yearFromNow() -> January 23, 1998
- *
- ***/
- millisecondFromNow(): Date;
- millisecondsFromNow(): Date;
- secondFromNow(): Date;
- secondsFromNow(): Date;
- minuteFromNow(): Date;
- minutesFromNow(): Date;
- hourFromNow(): Date;
- hoursFromNow(): Date;
- dayFromNow(): Date;
- daysFromNow(): Date;
- weekFromNow(): Date;
- weeksFromNow(): Date;
- monthFromNow(): Date;
- monthsFromNow(): Date;
- yearFromNow(): Date;
- yearsFromNow(): Date;
-
- /***
- * @short Returns an array containing numbers from the number up to .
- * @method upto(