box-chrome-sdk
Version:
A Chrome App SDK for the Box V2 API
1,339 lines (1,167 loc) • 1.37 MB
JavaScript
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
;(function (undefined) {
var objectTypes = {
'boolean': false,
'function': true,
'object': true,
'number': false,
'string': false,
'undefined': false
};
var root = (objectTypes[typeof window] && window) || this,
freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports,
freeModule = objectTypes[typeof module] && module && !module.nodeType && module,
moduleExports = freeModule && freeModule.exports === freeExports && freeExports,
freeGlobal = objectTypes[typeof global] && global;
if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
root = freeGlobal;
}
var Rx = {
internals: {},
config: {
Promise: root.Promise // Detect if promise exists
},
helpers: { }
};
// Defaults
var noop = Rx.helpers.noop = function () { },
identity = Rx.helpers.identity = function (x) { return x; },
pluck = Rx.helpers.pluck = function (property) { return function (x) { return x[property]; }; },
just = Rx.helpers.just = function (value) { return function () { return value; }; },
defaultNow = Rx.helpers.defaultNow = Date.now,
defaultComparer = Rx.helpers.defaultComparer = function (x, y) { return isEqual(x, y); },
defaultSubComparer = Rx.helpers.defaultSubComparer = function (x, y) { return x > y ? 1 : (x < y ? -1 : 0); },
defaultKeySerializer = Rx.helpers.defaultKeySerializer = function (x) { return x.toString(); },
defaultError = Rx.helpers.defaultError = function (err) { throw err; },
isPromise = Rx.helpers.isPromise = function (p) { return !!p && typeof p.then === 'function' && p.then !== Rx.Observable.prototype.then; },
asArray = Rx.helpers.asArray = function () { return Array.prototype.slice.call(arguments); },
not = Rx.helpers.not = function (a) { return !a; };
// Errors
var sequenceContainsNoElements = 'Sequence contains no elements.';
var argumentOutOfRange = 'Argument out of range';
var objectDisposed = 'Object has been disposed';
function checkDisposed() { if (this.isDisposed) { throw new Error(objectDisposed); } }
// Shim in iterator support
var $iterator$ = (typeof Symbol === 'object' && Symbol.iterator) ||
'_es6shim_iterator_';
// Firefox ships a partial implementation using the name @@iterator.
// https://bugzilla.mozilla.org/show_bug.cgi?id=907077#c14
// So use that name if we detect it.
if (root.Set && typeof new root.Set()['@@iterator'] === 'function') {
$iterator$ = '@@iterator';
}
var doneEnumerator = { done: true, value: undefined };
/** `Object#toString` result shortcuts */
var argsClass = '[object Arguments]',
arrayClass = '[object Array]',
boolClass = '[object Boolean]',
dateClass = '[object Date]',
errorClass = '[object Error]',
funcClass = '[object Function]',
numberClass = '[object Number]',
objectClass = '[object Object]',
regexpClass = '[object RegExp]',
stringClass = '[object String]';
var toString = Object.prototype.toString,
hasOwnProperty = Object.prototype.hasOwnProperty,
supportsArgsClass = toString.call(arguments) == argsClass, // For less <IE9 && FF<4
suportNodeClass,
errorProto = Error.prototype,
objectProto = Object.prototype,
propertyIsEnumerable = objectProto.propertyIsEnumerable;
try {
suportNodeClass = !(toString.call(document) == objectClass && !({ 'toString': 0 } + ''));
} catch(e) {
suportNodeClass = true;
}
var shadowedProps = [
'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf'
];
var nonEnumProps = {};
nonEnumProps[arrayClass] = nonEnumProps[dateClass] = nonEnumProps[numberClass] = { 'constructor': true, 'toLocaleString': true, 'toString': true, 'valueOf': true };
nonEnumProps[boolClass] = nonEnumProps[stringClass] = { 'constructor': true, 'toString': true, 'valueOf': true };
nonEnumProps[errorClass] = nonEnumProps[funcClass] = nonEnumProps[regexpClass] = { 'constructor': true, 'toString': true };
nonEnumProps[objectClass] = { 'constructor': true };
var support = {};
(function () {
var ctor = function() { this.x = 1; },
props = [];
ctor.prototype = { 'valueOf': 1, 'y': 1 };
for (var key in new ctor) { props.push(key); }
for (key in arguments) { }
// Detect if `name` or `message` properties of `Error.prototype` are enumerable by default.
support.enumErrorProps = propertyIsEnumerable.call(errorProto, 'message') || propertyIsEnumerable.call(errorProto, 'name');
// Detect if `prototype` properties are enumerable by default.
support.enumPrototypes = propertyIsEnumerable.call(ctor, 'prototype');
// Detect if `arguments` object indexes are non-enumerable
support.nonEnumArgs = key != 0;
// Detect if properties shadowing those on `Object.prototype` are non-enumerable.
support.nonEnumShadows = !/valueOf/.test(props);
}(1));
function isObject(value) {
// check if the value is the ECMAScript language type of Object
// http://es5.github.io/#x8
// and avoid a V8 bug
// https://code.google.com/p/v8/issues/detail?id=2291
var type = typeof value;
return value && (type == 'function' || type == 'object') || false;
}
function keysIn(object) {
var result = [];
if (!isObject(object)) {
return result;
}
if (support.nonEnumArgs && object.length && isArguments(object)) {
object = slice.call(object);
}
var skipProto = support.enumPrototypes && typeof object == 'function',
skipErrorProps = support.enumErrorProps && (object === errorProto || object instanceof Error);
for (var key in object) {
if (!(skipProto && key == 'prototype') &&
!(skipErrorProps && (key == 'message' || key == 'name'))) {
result.push(key);
}
}
if (support.nonEnumShadows && object !== objectProto) {
var ctor = object.constructor,
index = -1,
length = shadowedProps.length;
if (object === (ctor && ctor.prototype)) {
var className = object === stringProto ? stringClass : object === errorProto ? errorClass : toString.call(object),
nonEnum = nonEnumProps[className];
}
while (++index < length) {
key = shadowedProps[index];
if (!(nonEnum && nonEnum[key]) && hasOwnProperty.call(object, key)) {
result.push(key);
}
}
}
return result;
}
function internalFor(object, callback, keysFunc) {
var index = -1,
props = keysFunc(object),
length = props.length;
while (++index < length) {
var key = props[index];
if (callback(object[key], key, object) === false) {
break;
}
}
return object;
}
function internalForIn(object, callback) {
return internalFor(object, callback, keysIn);
}
function isNode(value) {
// IE < 9 presents DOM nodes as `Object` objects except they have `toString`
// methods that are `typeof` "string" and still can coerce nodes to strings
return typeof value.toString != 'function' && typeof (value + '') == 'string';
}
function isArguments(value) {
return (value && typeof value == 'object') ? toString.call(value) == argsClass : false;
}
// fallback for browsers that can't detect `arguments` objects by [[Class]]
if (!supportsArgsClass) {
isArguments = function(value) {
return (value && typeof value == 'object') ? hasOwnProperty.call(value, 'callee') : false;
};
}
function isFunction(value) {
return typeof value == 'function' || false;
}
// fallback for older versions of Chrome and Safari
if (isFunction(/x/)) {
isFunction = function(value) {
return typeof value == 'function' && toString.call(value) == funcClass;
};
}
var isEqual = Rx.internals.isEqual = function (x, y) {
return deepEquals(x, y, [], []);
};
/** @private
* Used for deep comparison
**/
function deepEquals(a, b, stackA, stackB) {
// exit early for identical values
if (a === b) {
// treat `+0` vs. `-0` as not equal
return a !== 0 || (1 / a == 1 / b);
}
var type = typeof a,
otherType = typeof b;
// exit early for unlike primitive values
if (a === a && (a == null || b == null ||
(type != 'function' && type != 'object' && otherType != 'function' && otherType != 'object'))) {
return false;
}
// compare [[Class]] names
var className = toString.call(a),
otherClass = toString.call(b);
if (className == argsClass) {
className = objectClass;
}
if (otherClass == argsClass) {
otherClass = objectClass;
}
if (className != otherClass) {
return false;
}
switch (className) {
case boolClass:
case dateClass:
// coerce dates and booleans to numbers, dates to milliseconds and booleans
// to `1` or `0` treating invalid dates coerced to `NaN` as not equal
return +a == +b;
case numberClass:
// treat `NaN` vs. `NaN` as equal
return (a != +a)
? b != +b
// but treat `-0` vs. `+0` as not equal
: (a == 0 ? (1 / a == 1 / b) : a == +b);
case regexpClass:
case stringClass:
// coerce regexes to strings (http://es5.github.io/#x15.10.6.4)
// treat string primitives and their corresponding object instances as equal
return a == String(b);
}
var isArr = className == arrayClass;
if (!isArr) {
// exit for functions and DOM nodes
if (className != objectClass || (!support.nodeClass && (isNode(a) || isNode(b)))) {
return false;
}
// in older versions of Opera, `arguments` objects have `Array` constructors
var ctorA = !support.argsObject && isArguments(a) ? Object : a.constructor,
ctorB = !support.argsObject && isArguments(b) ? Object : b.constructor;
// non `Object` object instances with different constructors are not equal
if (ctorA != ctorB &&
!(hasOwnProperty.call(a, 'constructor') && hasOwnProperty.call(b, 'constructor')) &&
!(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) &&
('constructor' in a && 'constructor' in b)
) {
return false;
}
}
// assume cyclic structures are equal
// the algorithm for detecting cyclic structures is adapted from ES 5.1
// section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3)
var initedStack = !stackA;
stackA || (stackA = []);
stackB || (stackB = []);
var length = stackA.length;
while (length--) {
if (stackA[length] == a) {
return stackB[length] == b;
}
}
var size = 0;
result = true;
// add `a` and `b` to the stack of traversed objects
stackA.push(a);
stackB.push(b);
// recursively compare objects and arrays (susceptible to call stack limits)
if (isArr) {
// compare lengths to determine if a deep comparison is necessary
length = a.length;
size = b.length;
result = size == length;
if (result) {
// deep compare the contents, ignoring non-numeric properties
while (size--) {
var index = length,
value = b[size];
if (!(result = deepEquals(a[size], value, stackA, stackB))) {
break;
}
}
}
}
else {
// deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
// which, in this case, is more costly
internalForIn(b, function(value, key, b) {
if (hasOwnProperty.call(b, key)) {
// count the number of properties.
size++;
// deep compare each property value.
return (result = hasOwnProperty.call(a, key) && deepEquals(a[key], value, stackA, stackB));
}
});
if (result) {
// ensure both objects have the same number of properties
internalForIn(a, function(value, key, a) {
if (hasOwnProperty.call(a, key)) {
// `size` will be `-1` if `a` has more properties than `b`
return (result = --size > -1);
}
});
}
}
stackA.pop();
stackB.pop();
return result;
}
var slice = Array.prototype.slice;
function argsOrArray(args, idx) {
return args.length === 1 && Array.isArray(args[idx]) ?
args[idx] :
slice.call(args);
}
var hasProp = {}.hasOwnProperty;
/** @private */
var inherits = this.inherits = Rx.internals.inherits = function (child, parent) {
function __() { this.constructor = child; }
__.prototype = parent.prototype;
child.prototype = new __();
};
/** @private */
var addProperties = Rx.internals.addProperties = function (obj) {
var sources = slice.call(arguments, 1);
for (var i = 0, len = sources.length; i < len; i++) {
var source = sources[i];
for (var prop in source) {
obj[prop] = source[prop];
}
}
};
// Rx Utils
var addRef = Rx.internals.addRef = function (xs, r) {
return new AnonymousObservable(function (observer) {
return new CompositeDisposable(r.getDisposable(), xs.subscribe(observer));
});
};
// Collection polyfills
function arrayInitialize(count, factory) {
var a = new Array(count);
for (var i = 0; i < count; i++) {
a[i] = factory();
}
return a;
}
// Collections
var IndexedItem = function (id, value) {
this.id = id;
this.value = value;
};
IndexedItem.prototype.compareTo = function (other) {
var c = this.value.compareTo(other.value);
if (c === 0) {
c = this.id - other.id;
}
return c;
};
// Priority Queue for Scheduling
var PriorityQueue = Rx.internals.PriorityQueue = function (capacity) {
this.items = new Array(capacity);
this.length = 0;
};
var priorityProto = PriorityQueue.prototype;
priorityProto.isHigherPriority = function (left, right) {
return this.items[left].compareTo(this.items[right]) < 0;
};
priorityProto.percolate = function (index) {
if (index >= this.length || index < 0) {
return;
}
var parent = index - 1 >> 1;
if (parent < 0 || parent === index) {
return;
}
if (this.isHigherPriority(index, parent)) {
var temp = this.items[index];
this.items[index] = this.items[parent];
this.items[parent] = temp;
this.percolate(parent);
}
};
priorityProto.heapify = function (index) {
if (index === undefined) {
index = 0;
}
if (index >= this.length || index < 0) {
return;
}
var left = 2 * index + 1,
right = 2 * index + 2,
first = index;
if (left < this.length && this.isHigherPriority(left, first)) {
first = left;
}
if (right < this.length && this.isHigherPriority(right, first)) {
first = right;
}
if (first !== index) {
var temp = this.items[index];
this.items[index] = this.items[first];
this.items[first] = temp;
this.heapify(first);
}
};
priorityProto.peek = function () { return this.items[0].value; };
priorityProto.removeAt = function (index) {
this.items[index] = this.items[--this.length];
delete this.items[this.length];
this.heapify();
};
priorityProto.dequeue = function () {
var result = this.peek();
this.removeAt(0);
return result;
};
priorityProto.enqueue = function (item) {
var index = this.length++;
this.items[index] = new IndexedItem(PriorityQueue.count++, item);
this.percolate(index);
};
priorityProto.remove = function (item) {
for (var i = 0; i < this.length; i++) {
if (this.items[i].value === item) {
this.removeAt(i);
return true;
}
}
return false;
};
PriorityQueue.count = 0;
/**
* Represents a group of disposable resources that are disposed together.
* @constructor
*/
var CompositeDisposable = Rx.CompositeDisposable = function () {
this.disposables = argsOrArray(arguments, 0);
this.isDisposed = false;
this.length = this.disposables.length;
};
var CompositeDisposablePrototype = CompositeDisposable.prototype;
/**
* Adds a disposable to the CompositeDisposable or disposes the disposable if the CompositeDisposable is disposed.
* @param {Mixed} item Disposable to add.
*/
CompositeDisposablePrototype.add = function (item) {
if (this.isDisposed) {
item.dispose();
} else {
this.disposables.push(item);
this.length++;
}
};
/**
* Removes and disposes the first occurrence of a disposable from the CompositeDisposable.
* @param {Mixed} item Disposable to remove.
* @returns {Boolean} true if found; false otherwise.
*/
CompositeDisposablePrototype.remove = function (item) {
var shouldDispose = false;
if (!this.isDisposed) {
var idx = this.disposables.indexOf(item);
if (idx !== -1) {
shouldDispose = true;
this.disposables.splice(idx, 1);
this.length--;
item.dispose();
}
}
return shouldDispose;
};
/**
* Disposes all disposables in the group and removes them from the group.
*/
CompositeDisposablePrototype.dispose = function () {
if (!this.isDisposed) {
this.isDisposed = true;
var currentDisposables = this.disposables.slice(0);
this.disposables = [];
this.length = 0;
for (var i = 0, len = currentDisposables.length; i < len; i++) {
currentDisposables[i].dispose();
}
}
};
/**
* Removes and disposes all disposables from the CompositeDisposable, but does not dispose the CompositeDisposable.
*/
CompositeDisposablePrototype.clear = function () {
var currentDisposables = this.disposables.slice(0);
this.disposables = [];
this.length = 0;
for (var i = 0, len = currentDisposables.length; i < len; i++) {
currentDisposables[i].dispose();
}
};
/**
* Determines whether the CompositeDisposable contains a specific disposable.
* @param {Mixed} item Disposable to search for.
* @returns {Boolean} true if the disposable was found; otherwise, false.
*/
CompositeDisposablePrototype.contains = function (item) {
return this.disposables.indexOf(item) !== -1;
};
/**
* Converts the existing CompositeDisposable to an array of disposables
* @returns {Array} An array of disposable objects.
*/
CompositeDisposablePrototype.toArray = function () {
return this.disposables.slice(0);
};
/**
* Provides a set of static methods for creating Disposables.
*
* @constructor
* @param {Function} dispose Action to run during the first call to dispose. The action is guaranteed to be run at most once.
*/
var Disposable = Rx.Disposable = function (action) {
this.isDisposed = false;
this.action = action || noop;
};
/** Performs the task of cleaning up resources. */
Disposable.prototype.dispose = function () {
if (!this.isDisposed) {
this.action();
this.isDisposed = true;
}
};
/**
* Creates a disposable object that invokes the specified action when disposed.
* @param {Function} dispose Action to run during the first call to dispose. The action is guaranteed to be run at most once.
* @return {Disposable} The disposable object that runs the given action upon disposal.
*/
var disposableCreate = Disposable.create = function (action) { return new Disposable(action); };
/**
* Gets the disposable that does nothing when disposed.
*/
var disposableEmpty = Disposable.empty = { dispose: noop };
var BooleanDisposable = (function () {
function BooleanDisposable (isSingle) {
this.isSingle = isSingle;
this.isDisposed = false;
this.current = null;
}
var booleanDisposablePrototype = BooleanDisposable.prototype;
/**
* Gets the underlying disposable.
* @return The underlying disposable.
*/
booleanDisposablePrototype.getDisposable = function () {
return this.current;
};
/**
* Sets the underlying disposable.
* @param {Disposable} value The new underlying disposable.
*/
booleanDisposablePrototype.setDisposable = function (value) {
if (this.current && this.isSingle) {
throw new Error('Disposable has already been assigned');
}
var shouldDispose = this.isDisposed, old;
if (!shouldDispose) {
old = this.current;
this.current = value;
}
if (old) {
old.dispose();
}
if (shouldDispose && value) {
value.dispose();
}
};
/**
* Disposes the underlying disposable as well as all future replacements.
*/
booleanDisposablePrototype.dispose = function () {
var old;
if (!this.isDisposed) {
this.isDisposed = true;
old = this.current;
this.current = null;
}
if (old) {
old.dispose();
}
};
return BooleanDisposable;
}());
/**
* Represents a disposable resource which only allows a single assignment of its underlying disposable resource.
* If an underlying disposable resource has already been set, future attempts to set the underlying disposable resource will throw an Error.
*/
var SingleAssignmentDisposable = Rx.SingleAssignmentDisposable = (function (super_) {
inherits(SingleAssignmentDisposable, super_);
function SingleAssignmentDisposable() {
super_.call(this, true);
}
return SingleAssignmentDisposable;
}(BooleanDisposable));
/**
* Represents a disposable resource whose underlying disposable resource can be replaced by another disposable resource, causing automatic disposal of the previous underlying disposable resource.
*/
var SerialDisposable = Rx.SerialDisposable = (function (super_) {
inherits(SerialDisposable, super_);
function SerialDisposable() {
super_.call(this, false);
}
return SerialDisposable;
}(BooleanDisposable));
/**
* Represents a disposable resource that only disposes its underlying disposable resource when all dependent disposable objects have been disposed.
*/
var RefCountDisposable = Rx.RefCountDisposable = (function () {
function InnerDisposable(disposable) {
this.disposable = disposable;
this.disposable.count++;
this.isInnerDisposed = false;
}
InnerDisposable.prototype.dispose = function () {
if (!this.disposable.isDisposed) {
if (!this.isInnerDisposed) {
this.isInnerDisposed = true;
this.disposable.count--;
if (this.disposable.count === 0 && this.disposable.isPrimaryDisposed) {
this.disposable.isDisposed = true;
this.disposable.underlyingDisposable.dispose();
}
}
}
};
/**
* Initializes a new instance of the RefCountDisposable with the specified disposable.
* @constructor
* @param {Disposable} disposable Underlying disposable.
*/
function RefCountDisposable(disposable) {
this.underlyingDisposable = disposable;
this.isDisposed = false;
this.isPrimaryDisposed = false;
this.count = 0;
}
/**
* Disposes the underlying disposable only when all dependent disposables have been disposed
*/
RefCountDisposable.prototype.dispose = function () {
if (!this.isDisposed) {
if (!this.isPrimaryDisposed) {
this.isPrimaryDisposed = true;
if (this.count === 0) {
this.isDisposed = true;
this.underlyingDisposable.dispose();
}
}
}
};
/**
* Returns a dependent disposable that when disposed decreases the refcount on the underlying disposable.
* @returns {Disposable} A dependent disposable contributing to the reference count that manages the underlying disposable's lifetime.
*/
RefCountDisposable.prototype.getDisposable = function () {
return this.isDisposed ? disposableEmpty : new InnerDisposable(this);
};
return RefCountDisposable;
})();
function ScheduledDisposable(scheduler, disposable) {
this.scheduler = scheduler;
this.disposable = disposable;
this.isDisposed = false;
}
ScheduledDisposable.prototype.dispose = function () {
var parent = this;
this.scheduler.schedule(function () {
if (!parent.isDisposed) {
parent.isDisposed = true;
parent.disposable.dispose();
}
});
};
var ScheduledItem = Rx.internals.ScheduledItem = function (scheduler, state, action, dueTime, comparer) {
this.scheduler = scheduler;
this.state = state;
this.action = action;
this.dueTime = dueTime;
this.comparer = comparer || defaultSubComparer;
this.disposable = new SingleAssignmentDisposable();
}
ScheduledItem.prototype.invoke = function () {
this.disposable.setDisposable(this.invokeCore());
};
ScheduledItem.prototype.compareTo = function (other) {
return this.comparer(this.dueTime, other.dueTime);
};
ScheduledItem.prototype.isCancelled = function () {
return this.disposable.isDisposed;
};
ScheduledItem.prototype.invokeCore = function () {
return this.action(this.scheduler, this.state);
};
/** Provides a set of static properties to access commonly used schedulers. */
var Scheduler = Rx.Scheduler = (function () {
/**
* @constructor
* @private
*/
function Scheduler(now, schedule, scheduleRelative, scheduleAbsolute) {
this.now = now;
this._schedule = schedule;
this._scheduleRelative = scheduleRelative;
this._scheduleAbsolute = scheduleAbsolute;
}
function invokeRecImmediate(scheduler, pair) {
var state = pair.first, action = pair.second, group = new CompositeDisposable(),
recursiveAction = function (state1) {
action(state1, function (state2) {
var isAdded = false, isDone = false,
d = scheduler.scheduleWithState(state2, function (scheduler1, state3) {
if (isAdded) {
group.remove(d);
} else {
isDone = true;
}
recursiveAction(state3);
return disposableEmpty;
});
if (!isDone) {
group.add(d);
isAdded = true;
}
});
};
recursiveAction(state);
return group;
}
function invokeRecDate(scheduler, pair, method) {
var state = pair.first, action = pair.second, group = new CompositeDisposable(),
recursiveAction = function (state1) {
action(state1, function (state2, dueTime1) {
var isAdded = false, isDone = false,
d = scheduler[method].call(scheduler, state2, dueTime1, function (scheduler1, state3) {
if (isAdded) {
group.remove(d);
} else {
isDone = true;
}
recursiveAction(state3);
return disposableEmpty;
});
if (!isDone) {
group.add(d);
isAdded = true;
}
});
};
recursiveAction(state);
return group;
}
function invokeAction(scheduler, action) {
action();
return disposableEmpty;
}
var schedulerProto = Scheduler.prototype;
/**
* Returns a scheduler that wraps the original scheduler, adding exception handling for scheduled actions.
* @param {Function} handler Handler that's run if an exception is caught. The exception will be rethrown if the handler returns false.
* @returns {Scheduler} Wrapper around the original scheduler, enforcing exception handling.
*/
schedulerProto.catchException = schedulerProto['catch'] = function (handler) {
return new CatchScheduler(this, handler);
};
/**
* Schedules a periodic piece of work by dynamically discovering the scheduler's capabilities. The periodic task will be scheduled using window.setInterval for the base implementation.
* @param {Number} period Period for running the work periodically.
* @param {Function} action Action to be executed.
* @returns {Disposable} The disposable object used to cancel the scheduled recurring action (best effort).
*/
schedulerProto.schedulePeriodic = function (period, action) {
return this.schedulePeriodicWithState(null, period, function () {
action();
});
};
/**
* Schedules a periodic piece of work by dynamically discovering the scheduler's capabilities. The periodic task will be scheduled using window.setInterval for the base implementation.
* @param {Mixed} state Initial state passed to the action upon the first iteration.
* @param {Number} period Period for running the work periodically.
* @param {Function} action Action to be executed, potentially updating the state.
* @returns {Disposable} The disposable object used to cancel the scheduled recurring action (best effort).
*/
schedulerProto.schedulePeriodicWithState = function (state, period, action) {
var s = state, id = setInterval(function () {
s = action(s);
}, period);
return disposableCreate(function () {
clearInterval(id);
});
};
/**
* Schedules an action to be executed.
* @param {Function} action Action to execute.
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort).
*/
schedulerProto.schedule = function (action) {
return this._schedule(action, invokeAction);
};
/**
* Schedules an action to be executed.
* @param state State passed to the action to be executed.
* @param {Function} action Action to be executed.
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort).
*/
schedulerProto.scheduleWithState = function (state, action) {
return this._schedule(state, action);
};
/**
* Schedules an action to be executed after the specified relative due time.
* @param {Function} action Action to execute.
* @param {Number} dueTime Relative time after which to execute the action.
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort).
*/
schedulerProto.scheduleWithRelative = function (dueTime, action) {
return this._scheduleRelative(action, dueTime, invokeAction);
};
/**
* Schedules an action to be executed after dueTime.
* @param state State passed to the action to be executed.
* @param {Function} action Action to be executed.
* @param {Number} dueTime Relative time after which to execute the action.
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort).
*/
schedulerProto.scheduleWithRelativeAndState = function (state, dueTime, action) {
return this._scheduleRelative(state, dueTime, action);
};
/**
* Schedules an action to be executed at the specified absolute due time.
* @param {Function} action Action to execute.
* @param {Number} dueTime Absolute time at which to execute the action.
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort).
*/
schedulerProto.scheduleWithAbsolute = function (dueTime, action) {
return this._scheduleAbsolute(action, dueTime, invokeAction);
};
/**
* Schedules an action to be executed at dueTime.
* @param {Mixed} state State passed to the action to be executed.
* @param {Function} action Action to be executed.
* @param {Number}dueTime Absolute time at which to execute the action.
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort).
*/
schedulerProto.scheduleWithAbsoluteAndState = function (state, dueTime, action) {
return this._scheduleAbsolute(state, dueTime, action);
};
/**
* Schedules an action to be executed recursively.
* @param {Function} action Action to execute recursively. The parameter passed to the action is used to trigger recursive scheduling of the action.
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort).
*/
schedulerProto.scheduleRecursive = function (action) {
return this.scheduleRecursiveWithState(action, function (_action, self) {
_action(function () {
self(_action);
});
});
};
/**
* Schedules an action to be executed recursively.
* @param {Mixed} state State passed to the action to be executed.
* @param {Function} action Action to execute recursively. The last parameter passed to the action is used to trigger recursive scheduling of the action, passing in recursive invocation state.
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort).
*/
schedulerProto.scheduleRecursiveWithState = function (state, action) {
return this.scheduleWithState({ first: state, second: action }, function (s, p) {
return invokeRecImmediate(s, p);
});
};
/**
* Schedules an action to be executed recursively after a specified relative due time.
* @param {Function} action Action to execute recursively. The parameter passed to the action is used to trigger recursive scheduling of the action at the specified relative time.
* @param {Number}dueTime Relative time after which to execute the action for the first time.
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort).
*/
schedulerProto.scheduleRecursiveWithRelative = function (dueTime, action) {
return this.scheduleRecursiveWithRelativeAndState(action, dueTime, function (_action, self) {
_action(function (dt) {
self(_action, dt);
});
});
};
/**
* Schedules an action to be executed recursively after a specified relative due time.
* @param {Mixed} state State passed to the action to be executed.
* @param {Function} action Action to execute recursively. The last parameter passed to the action is used to trigger recursive scheduling of the action, passing in the recursive due time and invocation state.
* @param {Number}dueTime Relative time after which to execute the action for the first time.
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort).
*/
schedulerProto.scheduleRecursiveWithRelativeAndState = function (state, dueTime, action) {
return this._scheduleRelative({ first: state, second: action }, dueTime, function (s, p) {
return invokeRecDate(s, p, 'scheduleWithRelativeAndState');
});
};
/**
* Schedules an action to be executed recursively at a specified absolute due time.
* @param {Function} action Action to execute recursively. The parameter passed to the action is used to trigger recursive scheduling of the action at the specified absolute time.
* @param {Number}dueTime Absolute time at which to execute the action for the first time.
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort).
*/
schedulerProto.scheduleRecursiveWithAbsolute = function (dueTime, action) {
return this.scheduleRecursiveWithAbsoluteAndState(action, dueTime, function (_action, self) {
_action(function (dt) {
self(_action, dt);
});
});
};
/**
* Schedules an action to be executed recursively at a specified absolute due time.
* @param {Mixed} state State passed to the action to be executed.
* @param {Function} action Action to execute recursively. The last parameter passed to the action is used to trigger recursive scheduling of the action, passing in the recursive due time and invocation state.
* @param {Number}dueTime Absolute time at which to execute the action for the first time.
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort).
*/
schedulerProto.scheduleRecursiveWithAbsoluteAndState = function (state, dueTime, action) {
return this._scheduleAbsolute({ first: state, second: action }, dueTime, function (s, p) {
return invokeRecDate(s, p, 'scheduleWithAbsoluteAndState');
});
};
/** Gets the current time according to the local machine's system clock. */
Scheduler.now = defaultNow;
/**
* Normalizes the specified TimeSpan value to a positive value.
* @param {Number} timeSpan The time span value to normalize.
* @returns {Number} The specified TimeSpan value if it is zero or positive; otherwise, 0
*/
Scheduler.normalize = function (timeSpan) {
if (timeSpan < 0) {
timeSpan = 0;
}
return timeSpan;
};
return Scheduler;
}());
var normalizeTime = Scheduler.normalize;
var SchedulePeriodicRecursive = Rx.internals.SchedulePeriodicRecursive = (function () {
function tick(command, recurse) {
recurse(0, this._period);
try {
this._state = this._action(this._state);
} catch (e) {
this._cancel.dispose();
throw e;
}
}
function SchedulePeriodicRecursive(scheduler, state, period, action) {
this._scheduler = scheduler;
this._state = state;
this._period = period;
this._action = action;
}
SchedulePeriodicRecursive.prototype.start = function () {
var d = new SingleAssignmentDisposable();
this._cancel = d;
d.setDisposable(this._scheduler.scheduleRecursiveWithRelativeAndState(0, this._period, tick.bind(this)));
return d;
};
return SchedulePeriodicRecursive;
}());
/**
* Gets a scheduler that schedules work immediately on the current thread.
*/
var immediateScheduler = Scheduler.immediate = (function () {
function scheduleNow(state, action) { return action(this, state); }
function scheduleRelative(state, dueTime, action) {
var dt = normalizeTime(dt);
while (dt - this.now() > 0) { }
return action(this, state);
}
function scheduleAbsolute(state, dueTime, action) {
return this.scheduleWithRelativeAndState(state, dueTime - this.now(), action);
}
return new Scheduler(defaultNow, scheduleNow, scheduleRelative, scheduleAbsolute);
}());
/**
* Gets a scheduler that schedules work as soon as possible on the current thread.
*/
var currentThreadScheduler = Scheduler.currentThread = (function () {
var queue;
function runTrampoline (q) {
var item;
while (q.length > 0) {
item = q.dequeue();
if (!item.isCancelled()) {
// Note, do not schedule blocking work!
while (item.dueTime - Scheduler.now() > 0) {
}
if (!item.isCancelled()) {
item.invoke();
}
}
}
}
function scheduleNow(state, action) {
return this.scheduleWithRelativeAndState(state, 0, action);
}
function scheduleRelative(state, dueTime, action) {
var dt = this.now() + Scheduler.normalize(dueTime),
si = new ScheduledItem(this, state, action, dt),
t;
if (!queue) {
queue = new PriorityQueue(4);
queue.enqueue(si);
try {
runTrampoline(queue);
} catch (e) {
throw e;
} finally {
queue = null;
}
} else {
queue.enqueue(si);
}
return si.disposable;
}
function scheduleAbsolute(state, dueTime, action) {
return this.scheduleWithRelativeAndState(state, dueTime - this.now(), action);
}
var currentScheduler = new Scheduler(defaultNow, scheduleNow, scheduleRelative, scheduleAbsolute);
currentScheduler.scheduleRequired = function () { return queue === null; };
currentScheduler.ensureTrampoline = function (action) {
if (queue === null) {
return this.schedule(action);
} else {
return action();
}
};
return currentScheduler;
}());
var scheduleMethod, clearMethod = noop;
(function () {
var reNative = RegExp('^' +
String(toString)
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
.replace(/toString| for [^\]]+/g, '.*?') + '$'
);
var setImmediate = typeof (setImmediate = freeGlobal && moduleExports && freeGlobal.setImmediate) == 'function' &&
!reNative.test(setImmediate) && setImmediate,
clearImmediate = typeof (clearImmediate = freeGlobal && moduleExports && freeGlobal.clearImmediate) == 'function' &&
!reNative.test(clearImmediate) && clearImmediate;
function postMessageSupported () {
// Ensure not in a worker
if (!root.postMessage || root.importScripts) { return false; }
var isAsync = false,
oldHandler = root.onmessage;
// Test for async
root.onmessage = function () { isAsync = true; };
root.postMessage('','*');
root.onmessage = oldHandler;
return isAsync;
}
// Use in order, nextTick, setImmediate, postMessage, MessageChannel, script readystatechanged, setTimeout
if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
scheduleMethod = process.nextTick;
} else if (typeof setImmediate === 'function') {
scheduleMethod = setImmediate;
clearMethod = clearImmediate;
} else if (postMessageSupported()) {
var MSG_PREFIX = 'ms.rx.schedule' + Math.random(),
tasks = {},
taskId = 0;
function onGlobalPostMessage(event) {
// Only if we're a match to avoid any other global events
if (typeof event.data === 'string' && event.data.substring(0, MSG_PREFIX.length) === MSG_PREFIX) {
var handleId = event.data.substring(MSG_PREFIX.length),
action = tasks[handleId];
action();
delete tasks[handleId];
}
}
if (root.addEventListener) {
root.addEventListener('message', onGlobalPostMessage, false);
} else {
root.attachEvent('onmessage', onGlobalPostMessage, false);
}
scheduleMethod = function (action) {
var currentId = taskId++;
tasks[currentId] = action;
root.postMessage(MSG_PREFIX + currentId, '*');
};
} else if (!!root.MessageChannel) {
var channel = new root.MessageChannel(),
channelTasks = {},
channelTaskId = 0;
channel.port1.onmessage = function (event) {
var id = event.data,
action = channelTasks[id];
action();
delete channelTasks[id];
};
scheduleMethod = function (action) {
var id = channelTaskId++;
channelTasks[id] = action;
channel.port2.postMessage(id);
};
} else if ('document' in root && 'onreadystatechange' in root.document.createElement('script')) {
scheduleMethod = function (action) {
var scriptElement = root.document.createElement('script');
scriptElement.onreadystatechange = function () {
action();
scriptElement.onreadystatechange = null;
scriptElement.parentNode.removeChild(scriptElement);
scriptElement = null;
};
root.document.documentElement.appendChild(scriptElement);
};
} else {
scheduleMethod = function (action) { return setTimeout(action, 0); };
clearMethod = clearTimeout;
}
}());
/**
* Gets a scheduler that schedules work via a timed callback based upon platform.
*/
var timeoutScheduler = Scheduler.timeout = (function () {
function scheduleNow(state, action) {
var scheduler = this,
disposable = new SingleAssignmentDisposable();
var id = scheduleMethod(function () {
if (!disposable.isDisposed) {
disposable.setDisposable(action(scheduler, state));
}
});
return new CompositeDisposable(disposable, disposableCreate(function () {
clearMethod(id);
}));
}
function scheduleRelative(state, dueTime, action) {
var scheduler = this,
dt = Scheduler.normalize(dueTime);
if (dt === 0) {
return scheduler.scheduleWithState(state, action);
}
var disposable = new SingleAssignmentDisposable();
var id = setTimeout(function () {
if (!disposable.isDisposed) {
disposable.setDisposable(action(scheduler, state));
}
}, dt);
return new CompositeDisposable(disposable, disposableCreate(function () {
clearTimeout(id);
}));
}
function scheduleAbsolute(state, dueTime, action) {
return this.scheduleWithRelativeAndState(state, dueTime - this.now(), action);
}
return new Scheduler(defaultNow, scheduleNow, scheduleRelative, scheduleAbsolute);
})();
/** @private */
var CatchScheduler = (function (_super) {
function localNow() {
return this._scheduler.now();
}
function scheduleNow(state, action) {
return this._scheduler.scheduleWithState(state, this._wrap(action));
}
function scheduleRelative(state, dueTime, action) {
return this._scheduler.scheduleWithRelativeAndState(state, dueTime, this._wrap(action));
}
function scheduleAbsolute(state, dueTime, action) {
return this._scheduler.scheduleWithAbsoluteAndState(state, dueTime, this._wrap(action));
}
inherits(CatchScheduler, _super);
/** @private */
function CatchScheduler(scheduler, handler) {
this._scheduler = scheduler;
this._