jquery.finger
Version:
jQuery Finger unifies click and touch events by removing the 300ms delay on touch devices. It also provide a common set of events to handle basic gestures such as drag and pinch. Small (< 1kb gzipped), it is focused on performance, is well tested and ...
1,667 lines (1,370 loc) • 154 kB
JavaScript
;(function(){
// CommonJS require()
function require(p){
var path = require.resolve(p)
, mod = require.modules[path];
if (!mod) throw new Error('failed to require "' + p + '"');
if (!mod.exports) {
mod.exports = {};
mod.call(mod.exports, mod, mod.exports, require.relative(path));
}
return mod.exports;
}
require.modules = {};
require.resolve = function (path){
var orig = path
, reg = path + '.js'
, index = path + '/index.js';
return require.modules[reg] && reg
|| require.modules[index] && index
|| orig;
};
require.register = function (path, fn){
require.modules[path] = fn;
};
require.relative = function (parent) {
return function(p){
if ('.' != p.charAt(0)) return require(p);
var path = parent.split('/')
, segs = p.split('/');
path.pop();
for (var i = 0; i < segs.length; i++) {
var seg = segs[i];
if ('..' == seg) path.pop();
else if ('.' != seg) path.push(seg);
}
return require(path.join('/'));
};
};
require.register("browser/debug.js", function(module, exports, require){
module.exports = function(type){
return function(){
}
};
}); // module: browser/debug.js
require.register("browser/diff.js", function(module, exports, require){
/* See license.txt for terms of usage */
/*
* Text diff implementation.
*
* This library supports the following APIS:
* JsDiff.diffChars: Character by character diff
* JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace
* JsDiff.diffLines: Line based diff
*
* JsDiff.diffCss: Diff targeted at CSS content
*
* These methods are based on the implementation proposed in
* "An O(ND) Difference Algorithm and its Variations" (Myers, 1986).
* http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927
*/
var JsDiff = (function() {
function clonePath(path) {
return { newPos: path.newPos, components: path.components.slice(0) };
}
function removeEmpty(array) {
var ret = [];
for (var i = 0; i < array.length; i++) {
if (array[i]) {
ret.push(array[i]);
}
}
return ret;
}
function escapeHTML(s) {
var n = s;
n = n.replace(/&/g, "&");
n = n.replace(/</g, "<");
n = n.replace(/>/g, ">");
n = n.replace(/"/g, """);
return n;
}
var fbDiff = function(ignoreWhitespace) {
this.ignoreWhitespace = ignoreWhitespace;
};
fbDiff.prototype = {
diff: function(oldString, newString) {
// Handle the identity case (this is due to unrolling editLength == 0
if (newString == oldString) {
return [{ value: newString }];
}
if (!newString) {
return [{ value: oldString, removed: true }];
}
if (!oldString) {
return [{ value: newString, added: true }];
}
newString = this.tokenize(newString);
oldString = this.tokenize(oldString);
var newLen = newString.length, oldLen = oldString.length;
var maxEditLength = newLen + oldLen;
var bestPath = [{ newPos: -1, components: [] }];
// Seed editLength = 0
var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0);
if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) {
return bestPath[0].components;
}
for (var editLength = 1; editLength <= maxEditLength; editLength++) {
for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) {
var basePath;
var addPath = bestPath[diagonalPath-1],
removePath = bestPath[diagonalPath+1];
oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;
if (addPath) {
// No one else is going to attempt to use this value, clear it
bestPath[diagonalPath-1] = undefined;
}
var canAdd = addPath && addPath.newPos+1 < newLen;
var canRemove = removePath && 0 <= oldPos && oldPos < oldLen;
if (!canAdd && !canRemove) {
bestPath[diagonalPath] = undefined;
continue;
}
// Select the diagonal that we want to branch from. We select the prior
// path whose position in the new string is the farthest from the origin
// and does not pass the bounds of the diff graph
if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) {
basePath = clonePath(removePath);
this.pushComponent(basePath.components, oldString[oldPos], undefined, true);
} else {
basePath = clonePath(addPath);
basePath.newPos++;
this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined);
}
var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath);
if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) {
return basePath.components;
} else {
bestPath[diagonalPath] = basePath;
}
}
}
},
pushComponent: function(components, value, added, removed) {
var last = components[components.length-1];
if (last && last.added === added && last.removed === removed) {
// We need to clone here as the component clone operation is just
// as shallow array clone
components[components.length-1] =
{value: this.join(last.value, value), added: added, removed: removed };
} else {
components.push({value: value, added: added, removed: removed });
}
},
extractCommon: function(basePath, newString, oldString, diagonalPath) {
var newLen = newString.length,
oldLen = oldString.length,
newPos = basePath.newPos,
oldPos = newPos - diagonalPath;
while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) {
newPos++;
oldPos++;
this.pushComponent(basePath.components, newString[newPos], undefined, undefined);
}
basePath.newPos = newPos;
return oldPos;
},
equals: function(left, right) {
var reWhitespace = /\S/;
if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) {
return true;
} else {
return left == right;
}
},
join: function(left, right) {
return left + right;
},
tokenize: function(value) {
return value;
}
};
var CharDiff = new fbDiff();
var WordDiff = new fbDiff(true);
WordDiff.tokenize = function(value) {
return removeEmpty(value.split(/(\s+|\b)/));
};
var CssDiff = new fbDiff(true);
CssDiff.tokenize = function(value) {
return removeEmpty(value.split(/([{}:;,]|\s+)/));
};
var LineDiff = new fbDiff();
LineDiff.tokenize = function(value) {
return value.split(/^/m);
};
return {
diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); },
diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); },
diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); },
diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); },
createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) {
var ret = [];
ret.push("Index: " + fileName);
ret.push("===================================================================");
ret.push("--- " + fileName + (typeof oldHeader === "undefined" ? "" : "\t" + oldHeader));
ret.push("+++ " + fileName + (typeof newHeader === "undefined" ? "" : "\t" + newHeader));
var diff = LineDiff.diff(oldStr, newStr);
if (!diff[diff.length-1].value) {
diff.pop(); // Remove trailing newline add
}
diff.push({value: "", lines: []}); // Append an empty value to make cleanup easier
function contextLines(lines) {
return lines.map(function(entry) { return ' ' + entry; });
}
function eofNL(curRange, i, current) {
var last = diff[diff.length-2],
isLast = i === diff.length-2,
isLastOfType = i === diff.length-3 && (current.added === !last.added || current.removed === !last.removed);
// Figure out if this is the last line for the given file and missing NL
if (!/\n$/.test(current.value) && (isLast || isLastOfType)) {
curRange.push('\\ No newline at end of file');
}
}
var oldRangeStart = 0, newRangeStart = 0, curRange = [],
oldLine = 1, newLine = 1;
for (var i = 0; i < diff.length; i++) {
var current = diff[i],
lines = current.lines || current.value.replace(/\n$/, "").split("\n");
current.lines = lines;
if (current.added || current.removed) {
if (!oldRangeStart) {
var prev = diff[i-1];
oldRangeStart = oldLine;
newRangeStart = newLine;
if (prev) {
curRange = contextLines(prev.lines.slice(-4));
oldRangeStart -= curRange.length;
newRangeStart -= curRange.length;
}
}
curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?"+":"-") + entry; }));
eofNL(curRange, i, current);
if (current.added) {
newLine += lines.length;
} else {
oldLine += lines.length;
}
} else {
if (oldRangeStart) {
// Close out any changes that have been output (or join overlapping)
if (lines.length <= 8 && i < diff.length-2) {
// Overlapping
curRange.push.apply(curRange, contextLines(lines));
} else {
// end the range and output
var contextSize = Math.min(lines.length, 4);
ret.push(
"@@ -" + oldRangeStart + "," + (oldLine-oldRangeStart+contextSize)
+ " +" + newRangeStart + "," + (newLine-newRangeStart+contextSize)
+ " @@");
ret.push.apply(ret, curRange);
ret.push.apply(ret, contextLines(lines.slice(0, contextSize)));
if (lines.length <= 4) {
eofNL(ret, i, current);
}
oldRangeStart = 0; newRangeStart = 0; curRange = [];
}
}
oldLine += lines.length;
newLine += lines.length;
}
}
return ret.join('\n') + '\n';
},
convertChangesToXML: function(changes){
var ret = [];
for ( var i = 0; i < changes.length; i++) {
var change = changes[i];
if (change.added) {
ret.push("<ins>");
} else if (change.removed) {
ret.push("<del>");
}
ret.push(escapeHTML(change.value));
if (change.added) {
ret.push("</ins>");
} else if (change.removed) {
ret.push("</del>");
}
}
return ret.join("");
}
};
})();
if (typeof module !== "undefined") {
module.exports = JsDiff;
}
}); // module: browser/diff.js
require.register("browser/events.js", function(module, exports, require){
/**
* Module exports.
*/
exports.EventEmitter = EventEmitter;
/**
* Check if `obj` is an array.
*/
function isArray(obj) {
return '[object Array]' == {}.toString.call(obj);
}
/**
* Event emitter constructor.
*
* @api public
*/
function EventEmitter(){};
/**
* Adds a listener.
*
* @api public
*/
EventEmitter.prototype.on = function (name, fn) {
if (!this.$events) {
this.$events = {};
}
if (!this.$events[name]) {
this.$events[name] = fn;
} else if (isArray(this.$events[name])) {
this.$events[name].push(fn);
} else {
this.$events[name] = [this.$events[name], fn];
}
return this;
};
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
/**
* Adds a volatile listener.
*
* @api public
*/
EventEmitter.prototype.once = function (name, fn) {
var self = this;
function on () {
self.removeListener(name, on);
fn.apply(this, arguments);
};
on.listener = fn;
this.on(name, on);
return this;
};
/**
* Removes a listener.
*
* @api public
*/
EventEmitter.prototype.removeListener = function (name, fn) {
if (this.$events && this.$events[name]) {
var list = this.$events[name];
if (isArray(list)) {
var pos = -1;
for (var i = 0, l = list.length; i < l; i++) {
if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
pos = i;
break;
}
}
if (pos < 0) {
return this;
}
list.splice(pos, 1);
if (!list.length) {
delete this.$events[name];
}
} else if (list === fn || (list.listener && list.listener === fn)) {
delete this.$events[name];
}
}
return this;
};
/**
* Removes all listeners for an event.
*
* @api public
*/
EventEmitter.prototype.removeAllListeners = function (name) {
if (name === undefined) {
this.$events = {};
return this;
}
if (this.$events && this.$events[name]) {
this.$events[name] = null;
}
return this;
};
/**
* Gets all listeners for a certain event.
*
* @api public
*/
EventEmitter.prototype.listeners = function (name) {
if (!this.$events) {
this.$events = {};
}
if (!this.$events[name]) {
this.$events[name] = [];
}
if (!isArray(this.$events[name])) {
this.$events[name] = [this.$events[name]];
}
return this.$events[name];
};
/**
* Emits an event.
*
* @api public
*/
EventEmitter.prototype.emit = function (name) {
if (!this.$events) {
return false;
}
var handler = this.$events[name];
if (!handler) {
return false;
}
var args = [].slice.call(arguments, 1);
if ('function' == typeof handler) {
handler.apply(this, args);
} else if (isArray(handler)) {
var listeners = handler.slice();
for (var i = 0, l = listeners.length; i < l; i++) {
listeners[i].apply(this, args);
}
} else {
return false;
}
return true;
};
}); // module: browser/events.js
require.register("browser/fs.js", function(module, exports, require){
}); // module: browser/fs.js
require.register("browser/path.js", function(module, exports, require){
}); // module: browser/path.js
require.register("browser/progress.js", function(module, exports, require){
/**
* Expose `Progress`.
*/
module.exports = Progress;
/**
* Initialize a new `Progress` indicator.
*/
function Progress() {
this.percent = 0;
this.size(0);
this.fontSize(11);
this.font('helvetica, arial, sans-serif');
}
/**
* Set progress size to `n`.
*
* @param {Number} n
* @return {Progress} for chaining
* @api public
*/
Progress.prototype.size = function(n){
this._size = n;
return this;
};
/**
* Set text to `str`.
*
* @param {String} str
* @return {Progress} for chaining
* @api public
*/
Progress.prototype.text = function(str){
this._text = str;
return this;
};
/**
* Set font size to `n`.
*
* @param {Number} n
* @return {Progress} for chaining
* @api public
*/
Progress.prototype.fontSize = function(n){
this._fontSize = n;
return this;
};
/**
* Set font `family`.
*
* @param {String} family
* @return {Progress} for chaining
*/
Progress.prototype.font = function(family){
this._font = family;
return this;
};
/**
* Update percentage to `n`.
*
* @param {Number} n
* @return {Progress} for chaining
*/
Progress.prototype.update = function(n){
this.percent = n;
return this;
};
/**
* Draw on `ctx`.
*
* @param {CanvasRenderingContext2d} ctx
* @return {Progress} for chaining
*/
Progress.prototype.draw = function(ctx){
var percent = Math.min(this.percent, 100)
, size = this._size
, half = size / 2
, x = half
, y = half
, rad = half - 1
, fontSize = this._fontSize;
ctx.font = fontSize + 'px ' + this._font;
var angle = Math.PI * 2 * (percent / 100);
ctx.clearRect(0, 0, size, size);
// outer circle
ctx.strokeStyle = '#9f9f9f';
ctx.beginPath();
ctx.arc(x, y, rad, 0, angle, false);
ctx.stroke();
// inner circle
ctx.strokeStyle = '#eee';
ctx.beginPath();
ctx.arc(x, y, rad - 1, 0, angle, true);
ctx.stroke();
// text
var text = this._text || (percent | 0) + '%'
, w = ctx.measureText(text).width;
ctx.fillText(
text
, x - w / 2 + 1
, y + fontSize / 2 - 1);
return this;
};
}); // module: browser/progress.js
require.register("browser/tty.js", function(module, exports, require){
exports.isatty = function(){
return true;
};
exports.getWindowSize = function(){
return [window.innerHeight, window.innerWidth];
};
}); // module: browser/tty.js
require.register("context.js", function(module, exports, require){
/**
* Expose `Context`.
*/
module.exports = Context;
/**
* Initialize a new `Context`.
*
* @api private
*/
function Context(){}
/**
* Set or get the context `Runnable` to `runnable`.
*
* @param {Runnable} runnable
* @return {Context}
* @api private
*/
Context.prototype.runnable = function(runnable){
if (0 == arguments.length) return this._runnable;
this.test = this._runnable = runnable;
return this;
};
/**
* Set test timeout `ms`.
*
* @param {Number} ms
* @return {Context} self
* @api private
*/
Context.prototype.timeout = function(ms){
this.runnable().timeout(ms);
return this;
};
/**
* Set test slowness threshold `ms`.
*
* @param {Number} ms
* @return {Context} self
* @api private
*/
Context.prototype.slow = function(ms){
this.runnable().slow(ms);
return this;
};
/**
* Inspect the context void of `._runnable`.
*
* @return {String}
* @api private
*/
Context.prototype.inspect = function(){
return JSON.stringify(this, function(key, val){
if ('_runnable' == key) return;
if ('test' == key) return;
return val;
}, 2);
};
}); // module: context.js
require.register("hook.js", function(module, exports, require){
/**
* Module dependencies.
*/
var Runnable = require('./runnable');
/**
* Expose `Hook`.
*/
module.exports = Hook;
/**
* Initialize a new `Hook` with the given `title` and callback `fn`.
*
* @param {String} title
* @param {Function} fn
* @api private
*/
function Hook(title, fn) {
Runnable.call(this, title, fn);
this.type = 'hook';
}
/**
* Inherit from `Runnable.prototype`.
*/
function F(){};
F.prototype = Runnable.prototype;
Hook.prototype = new F;
Hook.prototype.constructor = Hook;
/**
* Get or set the test `err`.
*
* @param {Error} err
* @return {Error}
* @api public
*/
Hook.prototype.error = function(err){
if (0 == arguments.length) {
var err = this._error;
this._error = null;
return err;
}
this._error = err;
};
}); // module: hook.js
require.register("interfaces/bdd.js", function(module, exports, require){
/**
* Module dependencies.
*/
var Suite = require('../suite')
, Test = require('../test');
/**
* BDD-style interface:
*
* describe('Array', function(){
* describe('#indexOf()', function(){
* it('should return -1 when not present', function(){
*
* });
*
* it('should return the index when present', function(){
*
* });
* });
* });
*
*/
module.exports = function(suite){
var suites = [suite];
suite.on('pre-require', function(context, file, mocha){
/**
* Execute before running tests.
*/
context.before = function(fn){
suites[0].beforeAll(fn);
};
/**
* Execute after running tests.
*/
context.after = function(fn){
suites[0].afterAll(fn);
};
/**
* Execute before each test case.
*/
context.beforeEach = function(fn){
suites[0].beforeEach(fn);
};
/**
* Execute after each test case.
*/
context.afterEach = function(fn){
suites[0].afterEach(fn);
};
/**
* Describe a "suite" with the given `title`
* and callback `fn` containing nested suites
* and/or tests.
*/
context.describe = context.context = function(title, fn){
var suite = Suite.create(suites[0], title);
suites.unshift(suite);
fn.call(suite);
suites.shift();
return suite;
};
/**
* Pending describe.
*/
context.xdescribe =
context.xcontext =
context.describe.skip = function(title, fn){
var suite = Suite.create(suites[0], title);
suite.pending = true;
suites.unshift(suite);
fn.call(suite);
suites.shift();
};
/**
* Exclusive suite.
*/
context.describe.only = function(title, fn){
var suite = context.describe(title, fn);
mocha.grep(suite.fullTitle());
};
/**
* Describe a specification or test-case
* with the given `title` and callback `fn`
* acting as a thunk.
*/
context.it = context.specify = function(title, fn){
var suite = suites[0];
if (suite.pending) var fn = null;
var test = new Test(title, fn);
suite.addTest(test);
return test;
};
/**
* Exclusive test-case.
*/
context.it.only = function(title, fn){
var test = context.it(title, fn);
mocha.grep(test.fullTitle());
};
/**
* Pending test case.
*/
context.xit =
context.xspecify =
context.it.skip = function(title){
context.it(title);
};
});
};
}); // module: interfaces/bdd.js
require.register("interfaces/exports.js", function(module, exports, require){
/**
* Module dependencies.
*/
var Suite = require('../suite')
, Test = require('../test');
/**
* TDD-style interface:
*
* exports.Array = {
* '#indexOf()': {
* 'should return -1 when the value is not present': function(){
*
* },
*
* 'should return the correct index when the value is present': function(){
*
* }
* }
* };
*
*/
module.exports = function(suite){
var suites = [suite];
suite.on('require', visit);
function visit(obj) {
var suite;
for (var key in obj) {
if ('function' == typeof obj[key]) {
var fn = obj[key];
switch (key) {
case 'before':
suites[0].beforeAll(fn);
break;
case 'after':
suites[0].afterAll(fn);
break;
case 'beforeEach':
suites[0].beforeEach(fn);
break;
case 'afterEach':
suites[0].afterEach(fn);
break;
default:
suites[0].addTest(new Test(key, fn));
}
} else {
var suite = Suite.create(suites[0], key);
suites.unshift(suite);
visit(obj[key]);
suites.shift();
}
}
}
};
}); // module: interfaces/exports.js
require.register("interfaces/index.js", function(module, exports, require){
exports.bdd = require('./bdd');
exports.tdd = require('./tdd');
exports.qunit = require('./qunit');
exports.exports = require('./exports');
}); // module: interfaces/index.js
require.register("interfaces/qunit.js", function(module, exports, require){
/**
* Module dependencies.
*/
var Suite = require('../suite')
, Test = require('../test');
/**
* QUnit-style interface:
*
* suite('Array');
*
* test('#length', function(){
* var arr = [1,2,3];
* ok(arr.length == 3);
* });
*
* test('#indexOf()', function(){
* var arr = [1,2,3];
* ok(arr.indexOf(1) == 0);
* ok(arr.indexOf(2) == 1);
* ok(arr.indexOf(3) == 2);
* });
*
* suite('String');
*
* test('#length', function(){
* ok('foo'.length == 3);
* });
*
*/
module.exports = function(suite){
var suites = [suite];
suite.on('pre-require', function(context){
/**
* Execute before running tests.
*/
context.before = function(fn){
suites[0].beforeAll(fn);
};
/**
* Execute after running tests.
*/
context.after = function(fn){
suites[0].afterAll(fn);
};
/**
* Execute before each test case.
*/
context.beforeEach = function(fn){
suites[0].beforeEach(fn);
};
/**
* Execute after each test case.
*/
context.afterEach = function(fn){
suites[0].afterEach(fn);
};
/**
* Describe a "suite" with the given `title`.
*/
context.suite = function(title){
if (suites.length > 1) suites.shift();
var suite = Suite.create(suites[0], title);
suites.unshift(suite);
};
/**
* Describe a specification or test-case
* with the given `title` and callback `fn`
* acting as a thunk.
*/
context.test = function(title, fn){
suites[0].addTest(new Test(title, fn));
};
});
};
}); // module: interfaces/qunit.js
require.register("interfaces/tdd.js", function(module, exports, require){
/**
* Module dependencies.
*/
var Suite = require('../suite')
, Test = require('../test');
/**
* TDD-style interface:
*
* suite('Array', function(){
* suite('#indexOf()', function(){
* suiteSetup(function(){
*
* });
*
* test('should return -1 when not present', function(){
*
* });
*
* test('should return the index when present', function(){
*
* });
*
* suiteTeardown(function(){
*
* });
* });
* });
*
*/
module.exports = function(suite){
var suites = [suite];
suite.on('pre-require', function(context, file, mocha){
/**
* Execute before each test case.
*/
context.setup = function(fn){
suites[0].beforeEach(fn);
};
/**
* Execute after each test case.
*/
context.teardown = function(fn){
suites[0].afterEach(fn);
};
/**
* Execute before the suite.
*/
context.suiteSetup = function(fn){
suites[0].beforeAll(fn);
};
/**
* Execute after the suite.
*/
context.suiteTeardown = function(fn){
suites[0].afterAll(fn);
};
/**
* Describe a "suite" with the given `title`
* and callback `fn` containing nested suites
* and/or tests.
*/
context.suite = function(title, fn){
var suite = Suite.create(suites[0], title);
suites.unshift(suite);
fn.call(suite);
suites.shift();
return suite;
};
/**
* Exclusive test-case.
*/
context.suite.only = function(title, fn){
var suite = context.suite(title, fn);
mocha.grep(suite.fullTitle());
};
/**
* Describe a specification or test-case
* with the given `title` and callback `fn`
* acting as a thunk.
*/
context.test = function(title, fn){
var test = new Test(title, fn);
suites[0].addTest(test);
return test;
};
/**
* Exclusive test-case.
*/
context.test.only = function(title, fn){
var test = context.test(title, fn);
mocha.grep(test.fullTitle());
};
/**
* Pending test case.
*/
context.test.skip = function(title){
context.test(title);
};
});
};
}); // module: interfaces/tdd.js
require.register("mocha.js", function(module, exports, require){
/*!
* mocha
* Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var path = require('browser/path')
, utils = require('./utils');
/**
* Expose `Mocha`.
*/
exports = module.exports = Mocha;
/**
* Expose internals.
*/
exports.utils = utils;
exports.interfaces = require('./interfaces');
exports.reporters = require('./reporters');
exports.Runnable = require('./runnable');
exports.Context = require('./context');
exports.Runner = require('./runner');
exports.Suite = require('./suite');
exports.Hook = require('./hook');
exports.Test = require('./test');
/**
* Return image `name` path.
*
* @param {String} name
* @return {String}
* @api private
*/
function image(name) {
return __dirname + '/../images/' + name + '.png';
}
/**
* Setup mocha with `options`.
*
* Options:
*
* - `ui` name "bdd", "tdd", "exports" etc
* - `reporter` reporter instance, defaults to `mocha.reporters.Dot`
* - `globals` array of accepted globals
* - `timeout` timeout in milliseconds
* - `bail` bail on the first test failure
* - `slow` milliseconds to wait before considering a test slow
* - `ignoreLeaks` ignore global leaks
* - `grep` string or regexp to filter tests with
*
* @param {Object} options
* @api public
*/
function Mocha(options) {
options = options || {};
this.files = [];
this.options = options;
this.grep(options.grep);
this.suite = new exports.Suite('', new exports.Context);
this.ui(options.ui);
this.bail(options.bail);
this.reporter(options.reporter);
if (options.timeout) this.timeout(options.timeout);
if (options.slow) this.slow(options.slow);
}
/**
* Enable or disable bailing on the first failure.
*
* @param {Boolean} [bail]
* @api public
*/
Mocha.prototype.bail = function(bail){
if (0 == arguments.length) bail = true;
this.suite.bail(bail);
return this;
};
/**
* Add test `file`.
*
* @param {String} file
* @api public
*/
Mocha.prototype.addFile = function(file){
this.files.push(file);
return this;
};
/**
* Set reporter to `reporter`, defaults to "dot".
*
* @param {String|Function} reporter name or constructor
* @api public
*/
Mocha.prototype.reporter = function(reporter){
if ('function' == typeof reporter) {
this._reporter = reporter;
} else {
reporter = reporter || 'dot';
try {
this._reporter = require('./reporters/' + reporter);
} catch (err) {
this._reporter = require(reporter);
}
if (!this._reporter) throw new Error('invalid reporter "' + reporter + '"');
}
return this;
};
/**
* Set test UI `name`, defaults to "bdd".
*
* @param {String} bdd
* @api public
*/
Mocha.prototype.ui = function(name){
name = name || 'bdd';
this._ui = exports.interfaces[name];
if (!this._ui) throw new Error('invalid interface "' + name + '"');
this._ui = this._ui(this.suite);
return this;
};
/**
* Load registered files.
*
* @api private
*/
Mocha.prototype.loadFiles = function(fn){
var self = this;
var suite = this.suite;
var pending = this.files.length;
this.files.forEach(function(file){
file = path.resolve(file);
suite.emit('pre-require', global, file, self);
suite.emit('require', require(file), file, self);
suite.emit('post-require', global, file, self);
--pending || (fn && fn());
});
};
/**
* Enable growl support.
*
* @api private
*/
Mocha.prototype._growl = function(runner, reporter) {
var notify = require('growl');
runner.on('end', function(){
var stats = reporter.stats;
if (stats.failures) {
var msg = stats.failures + ' of ' + runner.total + ' tests failed';
notify(msg, { name: 'mocha', title: 'Failed', image: image('error') });
} else {
notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', {
name: 'mocha'
, title: 'Passed'
, image: image('ok')
});
}
});
};
/**
* Add regexp to grep, if `re` is a string it is escaped.
*
* @param {RegExp|String} re
* @return {Mocha}
* @api public
*/
Mocha.prototype.grep = function(re){
this.options.grep = 'string' == typeof re
? new RegExp(utils.escapeRegexp(re))
: re;
return this;
};
/**
* Invert `.grep()` matches.
*
* @return {Mocha}
* @api public
*/
Mocha.prototype.invert = function(){
this.options.invert = true;
return this;
};
/**
* Ignore global leaks.
*
* @return {Mocha}
* @api public
*/
Mocha.prototype.ignoreLeaks = function(){
this.options.ignoreLeaks = true;
return this;
};
/**
* Enable global leak checking.
*
* @return {Mocha}
* @api public
*/
Mocha.prototype.checkLeaks = function(){
this.options.ignoreLeaks = false;
return this;
};
/**
* Enable growl support.
*
* @return {Mocha}
* @api public
*/
Mocha.prototype.growl = function(){
this.options.growl = true;
return this;
};
/**
* Ignore `globals` array or string.
*
* @param {Array|String} globals
* @return {Mocha}
* @api public
*/
Mocha.prototype.globals = function(globals){
this.options.globals = (this.options.globals || []).concat(globals);
return this;
};
/**
* Set the timeout in milliseconds.
*
* @param {Number} timeout
* @return {Mocha}
* @api public
*/
Mocha.prototype.timeout = function(timeout){
this.suite.timeout(timeout);
return this;
};
/**
* Set slowness threshold in milliseconds.
*
* @param {Number} slow
* @return {Mocha}
* @api public
*/
Mocha.prototype.slow = function(slow){
this.suite.slow(slow);
return this;
};
/**
* Makes all tests async (accepting a callback)
*
* @return {Mocha}
* @api public
*/
Mocha.prototype.asyncOnly = function(){
this.options.asyncOnly = true;
return this;
};
/**
* Run tests and invoke `fn()` when complete.
*
* @param {Function} fn
* @return {Runner}
* @api public
*/
Mocha.prototype.run = function(fn){
if (this.files.length) this.loadFiles();
var suite = this.suite;
var options = this.options;
var runner = new exports.Runner(suite);
var reporter = new this._reporter(runner);
runner.ignoreLeaks = options.ignoreLeaks;
runner.asyncOnly = options.asyncOnly;
if (options.grep) runner.grep(options.grep, options.invert);
if (options.globals) runner.globals(options.globals);
if (options.growl) this._growl(runner, reporter);
return runner.run(fn);
};
}); // module: mocha.js
require.register("ms.js", function(module, exports, require){
/**
* Helpers.
*/
var s = 1000;
var m = s * 60;
var h = m * 60;
var d = h * 24;
/**
* Parse or format the given `val`.
*
* @param {String|Number} val
* @return {String|Number}
* @api public
*/
module.exports = function(val){
if ('string' == typeof val) return parse(val);
return format(val);
}
/**
* Parse the given `str` and return milliseconds.
*
* @param {String} str
* @return {Number}
* @api private
*/
function parse(str) {
var m = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str);
if (!m) return;
var n = parseFloat(m[1]);
var type = (m[2] || 'ms').toLowerCase();
switch (type) {
case 'years':
case 'year':
case 'y':
return n * 31557600000;
case 'days':
case 'day':
case 'd':
return n * 86400000;
case 'hours':
case 'hour':
case 'h':
return n * 3600000;
case 'minutes':
case 'minute':
case 'm':
return n * 60000;
case 'seconds':
case 'second':
case 's':
return n * 1000;
case 'ms':
return n;
}
}
/**
* Format the given `ms`.
*
* @param {Number} ms
* @return {String}
* @api public
*/
function format(ms) {
if (ms == d) return Math.round(ms / d) + ' day';
if (ms > d) return Math.round(ms / d) + ' days';
if (ms == h) return Math.round(ms / h) + ' hour';
if (ms > h) return Math.round(ms / h) + ' hours';
if (ms == m) return Math.round(ms / m) + ' minute';
if (ms > m) return Math.round(ms / m) + ' minutes';
if (ms == s) return Math.round(ms / s) + ' second';
if (ms > s) return Math.round(ms / s) + ' seconds';
return ms + ' ms';
}
}); // module: ms.js
require.register("reporters/base.js", function(module, exports, require){
/**
* Module dependencies.
*/
var tty = require('browser/tty')
, diff = require('browser/diff')
, ms = require('../ms');
/**
* Save timer references to avoid Sinon interfering (see GH-237).
*/
var Date = global.Date
, setTimeout = global.setTimeout
, setInterval = global.setInterval
, clearTimeout = global.clearTimeout
, clearInterval = global.clearInterval;
/**