1347 lines
43 KiB
JavaScript
1347 lines
43 KiB
JavaScript
|
// Copyright (c) Microsoft, All rights reserved. See License.txt in the project root for license information.
|
||
|
|
||
|
;(function (undefined) {
|
||
|
|
||
|
var objectTypes = {
|
||
|
'function': true,
|
||
|
'object': true
|
||
|
};
|
||
|
|
||
|
function checkGlobal(value) {
|
||
|
return (value && value.Object === Object) ? value : null;
|
||
|
}
|
||
|
|
||
|
var freeExports = (objectTypes[typeof exports] && exports && !exports.nodeType) ? exports : null;
|
||
|
var freeModule = (objectTypes[typeof module] && module && !module.nodeType) ? module : null;
|
||
|
var freeGlobal = checkGlobal(freeExports && freeModule && typeof global === 'object' && global);
|
||
|
var freeSelf = checkGlobal(objectTypes[typeof self] && self);
|
||
|
var freeWindow = checkGlobal(objectTypes[typeof window] && window);
|
||
|
var moduleExports = (freeModule && freeModule.exports === freeExports) ? freeExports : null;
|
||
|
var thisGlobal = checkGlobal(objectTypes[typeof this] && this);
|
||
|
var root = freeGlobal || ((freeWindow !== (thisGlobal && thisGlobal.window)) && freeWindow) || freeSelf || thisGlobal || Function('return this')();
|
||
|
|
||
|
var Rx = {
|
||
|
internals: {},
|
||
|
config: {
|
||
|
Promise: root.Promise
|
||
|
},
|
||
|
helpers: { }
|
||
|
};
|
||
|
|
||
|
// Defaults
|
||
|
var
|
||
|
noop = Rx.helpers.noop = function () { },
|
||
|
defaultNow = Rx.helpers.defaultNow = (function () { return !!Date.now ? Date.now : function () { return +new Date; }; }()),
|
||
|
defaultError = Rx.helpers.defaultError = function (err) { throw err; },
|
||
|
isPromise = Rx.helpers.isPromise = function (p) { return !!p && !isFunction(p.subscribe) && isFunction(p.then); },
|
||
|
defaultSubComparer = Rx.helpers.defaultSubComparer = function (x, y) { return x > y ? 1 : (x < y ? -1 : 0); }
|
||
|
isFunction = Rx.helpers.isFunction = (function () {
|
||
|
var isFn = function (value) {
|
||
|
return typeof value == 'function' || false;
|
||
|
};
|
||
|
|
||
|
// fallback for older versions of Chrome and Safari
|
||
|
if (isFn(/x/)) {
|
||
|
isFn = function(value) {
|
||
|
return typeof value == 'function' && toString.call(value) == '[object Function]';
|
||
|
};
|
||
|
}
|
||
|
return isFn;
|
||
|
}());
|
||
|
|
||
|
var NotImplementedError = Rx.NotImplementedError = function (message) {
|
||
|
this.message = message || 'This operation is not implemented';
|
||
|
Error.call(this);
|
||
|
};
|
||
|
NotImplementedError.prototype = Error.prototype;
|
||
|
|
||
|
var NotSupportedError = Rx.NotSupportedError = function (message) {
|
||
|
this.message = message || 'This operation is not supported';
|
||
|
Error.call(this);
|
||
|
};
|
||
|
NotSupportedError.prototype = Error.prototype;
|
||
|
|
||
|
var notImplemented = Rx.helpers.notImplemented = function () {
|
||
|
throw new NotImplementedError();
|
||
|
};
|
||
|
|
||
|
var notSupported = Rx.helpers.notSupported = function () {
|
||
|
throw new NotSupportedError();
|
||
|
};
|
||
|
|
||
|
var errorObj = {e: {}};
|
||
|
|
||
|
function tryCatcherGen(tryCatchTarget) {
|
||
|
return function tryCatcher() {
|
||
|
try {
|
||
|
return tryCatchTarget.apply(this, arguments);
|
||
|
} catch (e) {
|
||
|
errorObj.e = e;
|
||
|
return errorObj;
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var tryCatch = Rx.internals.tryCatch = function tryCatch(fn) {
|
||
|
if (!isFunction(fn)) { throw new TypeError('fn must be a function'); }
|
||
|
return tryCatcherGen(fn);
|
||
|
};
|
||
|
|
||
|
function thrower(e) {
|
||
|
throw e;
|
||
|
}
|
||
|
|
||
|
Rx.config.longStackSupport = false;
|
||
|
var hasStacks = false, stacks = tryCatch(function () { throw new Error(); })();
|
||
|
hasStacks = !!stacks.e && !!stacks.e.stack;
|
||
|
|
||
|
// All code after this point will be filtered from stack traces reported by RxJS
|
||
|
var rStartingLine = captureLine(), rFileName;
|
||
|
|
||
|
var STACK_JUMP_SEPARATOR = 'From previous event:';
|
||
|
|
||
|
function makeStackTraceLong(error, observable) {
|
||
|
// If possible, transform the error stack trace by removing Node and RxJS
|
||
|
// cruft, then concatenating with the stack trace of `observable`.
|
||
|
if (hasStacks &&
|
||
|
observable.stack &&
|
||
|
typeof error === 'object' &&
|
||
|
error !== null &&
|
||
|
error.stack &&
|
||
|
error.stack.indexOf(STACK_JUMP_SEPARATOR) === -1
|
||
|
) {
|
||
|
var stacks = [];
|
||
|
for (var o = observable; !!o; o = o.source) {
|
||
|
if (o.stack) {
|
||
|
stacks.unshift(o.stack);
|
||
|
}
|
||
|
}
|
||
|
stacks.unshift(error.stack);
|
||
|
|
||
|
var concatedStacks = stacks.join('\n' + STACK_JUMP_SEPARATOR + '\n');
|
||
|
error.stack = filterStackString(concatedStacks);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function filterStackString(stackString) {
|
||
|
var lines = stackString.split('\n'), desiredLines = [];
|
||
|
for (var i = 0, len = lines.length; i < len; i++) {
|
||
|
var line = lines[i];
|
||
|
|
||
|
if (!isInternalFrame(line) && !isNodeFrame(line) && line) {
|
||
|
desiredLines.push(line);
|
||
|
}
|
||
|
}
|
||
|
return desiredLines.join('\n');
|
||
|
}
|
||
|
|
||
|
function isInternalFrame(stackLine) {
|
||
|
var fileNameAndLineNumber = getFileNameAndLineNumber(stackLine);
|
||
|
if (!fileNameAndLineNumber) {
|
||
|
return false;
|
||
|
}
|
||
|
var fileName = fileNameAndLineNumber[0], lineNumber = fileNameAndLineNumber[1];
|
||
|
|
||
|
return fileName === rFileName &&
|
||
|
lineNumber >= rStartingLine &&
|
||
|
lineNumber <= rEndingLine;
|
||
|
}
|
||
|
|
||
|
function isNodeFrame(stackLine) {
|
||
|
return stackLine.indexOf('(module.js:') !== -1 ||
|
||
|
stackLine.indexOf('(node.js:') !== -1;
|
||
|
}
|
||
|
|
||
|
function captureLine() {
|
||
|
if (!hasStacks) { return; }
|
||
|
|
||
|
try {
|
||
|
throw new Error();
|
||
|
} catch (e) {
|
||
|
var lines = e.stack.split('\n');
|
||
|
var firstLine = lines[0].indexOf('@') > 0 ? lines[1] : lines[2];
|
||
|
var fileNameAndLineNumber = getFileNameAndLineNumber(firstLine);
|
||
|
if (!fileNameAndLineNumber) { return; }
|
||
|
|
||
|
rFileName = fileNameAndLineNumber[0];
|
||
|
return fileNameAndLineNumber[1];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function getFileNameAndLineNumber(stackLine) {
|
||
|
// Named functions: 'at functionName (filename:lineNumber:columnNumber)'
|
||
|
var attempt1 = /at .+ \((.+):(\d+):(?:\d+)\)$/.exec(stackLine);
|
||
|
if (attempt1) { return [attempt1[1], Number(attempt1[2])]; }
|
||
|
|
||
|
// Anonymous functions: 'at filename:lineNumber:columnNumber'
|
||
|
var attempt2 = /at ([^ ]+):(\d+):(?:\d+)$/.exec(stackLine);
|
||
|
if (attempt2) { return [attempt2[1], Number(attempt2[2])]; }
|
||
|
|
||
|
// Firefox style: 'function@filename:lineNumber or @filename:lineNumber'
|
||
|
var attempt3 = /.*@(.+):(\d+)$/.exec(stackLine);
|
||
|
if (attempt3) { return [attempt3[1], Number(attempt3[2])]; }
|
||
|
}
|
||
|
|
||
|
var hasProp = {}.hasOwnProperty,
|
||
|
slice = Array.prototype.slice;
|
||
|
|
||
|
var inherits = Rx.internals.inherits = function (child, parent) {
|
||
|
function __() { this.constructor = child; }
|
||
|
__.prototype = parent.prototype;
|
||
|
child.prototype = new __();
|
||
|
};
|
||
|
|
||
|
var addProperties = Rx.internals.addProperties = function (obj) {
|
||
|
for(var sources = [], i = 1, len = arguments.length; i < len; i++) { sources.push(arguments[i]); }
|
||
|
for (var idx = 0, ln = sources.length; idx < ln; idx++) {
|
||
|
var source = sources[idx];
|
||
|
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 BinaryDisposable(r.getDisposable(), xs.subscribe(observer));
|
||
|
});
|
||
|
};
|
||
|
|
||
|
function arrayInitialize(count, factory) {
|
||
|
var a = new Array(count);
|
||
|
for (var i = 0; i < count; i++) {
|
||
|
a[i] = factory();
|
||
|
}
|
||
|
return a;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Represents a group of disposable resources that are disposed together.
|
||
|
* @constructor
|
||
|
*/
|
||
|
var CompositeDisposable = Rx.CompositeDisposable = function () {
|
||
|
var args = [], i, len;
|
||
|
if (Array.isArray(arguments[0])) {
|
||
|
args = arguments[0];
|
||
|
} else {
|
||
|
len = arguments.length;
|
||
|
args = new Array(len);
|
||
|
for(i = 0; i < len; i++) { args[i] = arguments[i]; }
|
||
|
}
|
||
|
this.disposables = args;
|
||
|
this.isDisposed = false;
|
||
|
this.length = args.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 len = this.disposables.length, currentDisposables = new Array(len);
|
||
|
for(var i = 0; i < len; i++) { currentDisposables[i] = this.disposables[i]; }
|
||
|
this.disposables = [];
|
||
|
this.length = 0;
|
||
|
|
||
|
for (i = 0; i < len; i++) {
|
||
|
currentDisposables[i].dispose();
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Provides a set of static methods for creating Disposables.
|
||
|
* @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 };
|
||
|
|
||
|
/**
|
||
|
* Validates whether the given object is a disposable
|
||
|
* @param {Object} Object to test whether it has a dispose method
|
||
|
* @returns {Boolean} true if a disposable object, else false.
|
||
|
*/
|
||
|
var isDisposable = Disposable.isDisposable = function (d) {
|
||
|
return d && isFunction(d.dispose);
|
||
|
};
|
||
|
|
||
|
var checkDisposed = Disposable.checkDisposed = function (disposable) {
|
||
|
if (disposable.isDisposed) { throw new ObjectDisposedError(); }
|
||
|
};
|
||
|
|
||
|
var disposableFixup = Disposable._fixup = function (result) {
|
||
|
return isDisposable(result) ? result : disposableEmpty;
|
||
|
};
|
||
|
|
||
|
// Single assignment
|
||
|
var SingleAssignmentDisposable = Rx.SingleAssignmentDisposable = function () {
|
||
|
this.isDisposed = false;
|
||
|
this.current = null;
|
||
|
};
|
||
|
SingleAssignmentDisposable.prototype.getDisposable = function () {
|
||
|
return this.current;
|
||
|
};
|
||
|
SingleAssignmentDisposable.prototype.setDisposable = function (value) {
|
||
|
if (this.current) { throw new Error('Disposable has already been assigned'); }
|
||
|
var shouldDispose = this.isDisposed;
|
||
|
!shouldDispose && (this.current = value);
|
||
|
shouldDispose && value && value.dispose();
|
||
|
};
|
||
|
SingleAssignmentDisposable.prototype.dispose = function () {
|
||
|
if (!this.isDisposed) {
|
||
|
this.isDisposed = true;
|
||
|
var old = this.current;
|
||
|
this.current = null;
|
||
|
old && old.dispose();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Multiple assignment disposable
|
||
|
var SerialDisposable = Rx.SerialDisposable = function () {
|
||
|
this.isDisposed = false;
|
||
|
this.current = null;
|
||
|
};
|
||
|
SerialDisposable.prototype.getDisposable = function () {
|
||
|
return this.current;
|
||
|
};
|
||
|
SerialDisposable.prototype.setDisposable = function (value) {
|
||
|
var shouldDispose = this.isDisposed;
|
||
|
if (!shouldDispose) {
|
||
|
var old = this.current;
|
||
|
this.current = value;
|
||
|
}
|
||
|
old && old.dispose();
|
||
|
shouldDispose && value && value.dispose();
|
||
|
};
|
||
|
SerialDisposable.prototype.dispose = function () {
|
||
|
if (!this.isDisposed) {
|
||
|
this.isDisposed = true;
|
||
|
var old = this.current;
|
||
|
this.current = null;
|
||
|
}
|
||
|
old && old.dispose();
|
||
|
};
|
||
|
|
||
|
var BinaryDisposable = Rx.BinaryDisposable = function (first, second) {
|
||
|
this._first = first;
|
||
|
this._second = second;
|
||
|
this.isDisposed = false;
|
||
|
};
|
||
|
|
||
|
BinaryDisposable.prototype.dispose = function () {
|
||
|
if (!this.isDisposed) {
|
||
|
this.isDisposed = true;
|
||
|
var old1 = this._first;
|
||
|
this._first = null;
|
||
|
old1 && old1.dispose();
|
||
|
var old2 = this._second;
|
||
|
this._second = null;
|
||
|
old2 && old2.dispose();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var NAryDisposable = Rx.NAryDisposable = function (disposables) {
|
||
|
this._disposables = disposables;
|
||
|
this.isDisposed = false;
|
||
|
};
|
||
|
|
||
|
NAryDisposable.prototype.dispose = function () {
|
||
|
if (!this.isDisposed) {
|
||
|
this.isDisposed = true;
|
||
|
for (var i = 0, len = this._disposables.length; i < len; i++) {
|
||
|
this._disposables[i].dispose();
|
||
|
}
|
||
|
this._disposables.length = 0;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
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 disposableFixup(this.action(this.scheduler, this.state));
|
||
|
};
|
||
|
|
||
|
/** Provides a set of static properties to access commonly used schedulers. */
|
||
|
var Scheduler = Rx.Scheduler = (function () {
|
||
|
|
||
|
function Scheduler() { }
|
||
|
|
||
|
/** Determines whether the given object is a scheduler */
|
||
|
Scheduler.isScheduler = function (s) {
|
||
|
return s instanceof Scheduler;
|
||
|
};
|
||
|
|
||
|
var schedulerProto = Scheduler.prototype;
|
||
|
|
||
|
/**
|
||
|
* 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.schedule = function (state, action) {
|
||
|
throw new NotImplementedError();
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* 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.scheduleFuture = function (state, dueTime, action) {
|
||
|
var dt = dueTime;
|
||
|
dt instanceof Date && (dt = dt - this.now());
|
||
|
dt = Scheduler.normalize(dt);
|
||
|
|
||
|
if (dt === 0) { return this.schedule(state, action); }
|
||
|
|
||
|
return this._scheduleFuture(state, dt, action);
|
||
|
};
|
||
|
|
||
|
schedulerProto._scheduleFuture = function (state, dueTime, action) {
|
||
|
throw new NotImplementedError();
|
||
|
};
|
||
|
|
||
|
/** Gets the current time according to the local machine's system clock. */
|
||
|
Scheduler.now = defaultNow;
|
||
|
|
||
|
/** Gets the current time according to the local machine's system clock. */
|
||
|
Scheduler.prototype.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) {
|
||
|
timeSpan < 0 && (timeSpan = 0);
|
||
|
return timeSpan;
|
||
|
};
|
||
|
|
||
|
return Scheduler;
|
||
|
}());
|
||
|
|
||
|
var normalizeTime = Scheduler.normalize, isScheduler = Scheduler.isScheduler;
|
||
|
|
||
|
(function (schedulerProto) {
|
||
|
|
||
|
function invokeRecImmediate(scheduler, pair) {
|
||
|
var state = pair[0], action = pair[1], group = new CompositeDisposable();
|
||
|
action(state, innerAction);
|
||
|
return group;
|
||
|
|
||
|
function innerAction(state2) {
|
||
|
var isAdded = false, isDone = false;
|
||
|
|
||
|
var d = scheduler.schedule(state2, scheduleWork);
|
||
|
if (!isDone) {
|
||
|
group.add(d);
|
||
|
isAdded = true;
|
||
|
}
|
||
|
|
||
|
function scheduleWork(_, state3) {
|
||
|
if (isAdded) {
|
||
|
group.remove(d);
|
||
|
} else {
|
||
|
isDone = true;
|
||
|
}
|
||
|
action(state3, innerAction);
|
||
|
return disposableEmpty;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function invokeRecDate(scheduler, pair) {
|
||
|
var state = pair[0], action = pair[1], group = new CompositeDisposable();
|
||
|
action(state, innerAction);
|
||
|
return group;
|
||
|
|
||
|
function innerAction(state2, dueTime1) {
|
||
|
var isAdded = false, isDone = false;
|
||
|
|
||
|
var d = scheduler.scheduleFuture(state2, dueTime1, scheduleWork);
|
||
|
if (!isDone) {
|
||
|
group.add(d);
|
||
|
isAdded = true;
|
||
|
}
|
||
|
|
||
|
function scheduleWork(_, state3) {
|
||
|
if (isAdded) {
|
||
|
group.remove(d);
|
||
|
} else {
|
||
|
isDone = true;
|
||
|
}
|
||
|
action(state3, innerAction);
|
||
|
return disposableEmpty;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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.scheduleRecursive = function (state, action) {
|
||
|
return this.schedule([state, action], invokeRecImmediate);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Schedules an action to be executed recursively after a specified relative or 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 | Date} dueTime Relative or absolute 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.scheduleRecursiveFuture = function (state, dueTime, action) {
|
||
|
return this.scheduleFuture([state, action], dueTime, invokeRecDate);
|
||
|
};
|
||
|
|
||
|
}(Scheduler.prototype));
|
||
|
|
||
|
(function (schedulerProto) {
|
||
|
|
||
|
/**
|
||
|
* 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.schedulePeriodic = function(state, period, action) {
|
||
|
if (typeof root.setInterval === 'undefined') { throw new NotSupportedError(); }
|
||
|
period = normalizeTime(period);
|
||
|
var s = state, id = root.setInterval(function () { s = action(s); }, period);
|
||
|
return disposableCreate(function () { root.clearInterval(id); });
|
||
|
};
|
||
|
|
||
|
}(Scheduler.prototype));
|
||
|
|
||
|
var SchedulePeriodicRecursive = Rx.internals.SchedulePeriodicRecursive = (function () {
|
||
|
function createTick(self) {
|
||
|
return function tick(command, recurse) {
|
||
|
recurse(0, self._period);
|
||
|
var state = tryCatch(self._action)(self._state);
|
||
|
if (state === errorObj) {
|
||
|
self._cancel.dispose();
|
||
|
thrower(state.e);
|
||
|
}
|
||
|
self._state = state;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
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.scheduleRecursiveFuture(0, this._period, createTick(this)));
|
||
|
|
||
|
return d;
|
||
|
};
|
||
|
|
||
|
return SchedulePeriodicRecursive;
|
||
|
}());
|
||
|
|
||
|
/** Gets a scheduler that schedules work immediately on the current thread. */
|
||
|
var ImmediateScheduler = (function (__super__) {
|
||
|
inherits(ImmediateScheduler, __super__);
|
||
|
function ImmediateScheduler() {
|
||
|
__super__.call(this);
|
||
|
}
|
||
|
|
||
|
ImmediateScheduler.prototype.schedule = function (state, action) {
|
||
|
return disposableFixup(action(this, state));
|
||
|
};
|
||
|
|
||
|
return ImmediateScheduler;
|
||
|
}(Scheduler));
|
||
|
|
||
|
var immediateScheduler = Scheduler.immediate = new ImmediateScheduler();
|
||
|
|
||
|
/**
|
||
|
* Gets a scheduler that schedules work as soon as possible on the current thread.
|
||
|
*/
|
||
|
var CurrentThreadScheduler = (function (__super__) {
|
||
|
var queue;
|
||
|
|
||
|
function runTrampoline () {
|
||
|
while (queue.length > 0) {
|
||
|
var item = queue.dequeue();
|
||
|
!item.isCancelled() && item.invoke();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inherits(CurrentThreadScheduler, __super__);
|
||
|
function CurrentThreadScheduler() {
|
||
|
__super__.call(this);
|
||
|
}
|
||
|
|
||
|
CurrentThreadScheduler.prototype.schedule = function (state, action) {
|
||
|
var si = new ScheduledItem(this, state, action, this.now());
|
||
|
|
||
|
if (!queue) {
|
||
|
queue = new PriorityQueue(4);
|
||
|
queue.enqueue(si);
|
||
|
|
||
|
var result = tryCatch(runTrampoline)();
|
||
|
queue = null;
|
||
|
if (result === errorObj) { thrower(result.e); }
|
||
|
} else {
|
||
|
queue.enqueue(si);
|
||
|
}
|
||
|
return si.disposable;
|
||
|
};
|
||
|
|
||
|
CurrentThreadScheduler.prototype.scheduleRequired = function () { return !queue; };
|
||
|
|
||
|
return CurrentThreadScheduler;
|
||
|
}(Scheduler));
|
||
|
|
||
|
var currentThreadScheduler = Scheduler.currentThread = new CurrentThreadScheduler();
|
||
|
|
||
|
var scheduleMethod, clearMethod;
|
||
|
|
||
|
var localTimer = (function () {
|
||
|
var localSetTimeout, localClearTimeout = noop;
|
||
|
if (!!root.setTimeout) {
|
||
|
localSetTimeout = root.setTimeout;
|
||
|
localClearTimeout = root.clearTimeout;
|
||
|
} else if (!!root.WScript) {
|
||
|
localSetTimeout = function (fn, time) {
|
||
|
root.WScript.Sleep(time);
|
||
|
fn();
|
||
|
};
|
||
|
} else {
|
||
|
throw new NotSupportedError();
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
setTimeout: localSetTimeout,
|
||
|
clearTimeout: localClearTimeout
|
||
|
};
|
||
|
}());
|
||
|
var localSetTimeout = localTimer.setTimeout,
|
||
|
localClearTimeout = localTimer.clearTimeout;
|
||
|
|
||
|
(function () {
|
||
|
|
||
|
var nextHandle = 1, tasksByHandle = {}, currentlyRunning = false;
|
||
|
|
||
|
clearMethod = function (handle) {
|
||
|
delete tasksByHandle[handle];
|
||
|
};
|
||
|
|
||
|
function runTask(handle) {
|
||
|
if (currentlyRunning) {
|
||
|
localSetTimeout(function () { runTask(handle); }, 0);
|
||
|
} else {
|
||
|
var task = tasksByHandle[handle];
|
||
|
if (task) {
|
||
|
currentlyRunning = true;
|
||
|
var result = tryCatch(task)();
|
||
|
clearMethod(handle);
|
||
|
currentlyRunning = false;
|
||
|
if (result === errorObj) { thrower(result.e); }
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var reNative = new RegExp('^' +
|
||
|
String(toString)
|
||
|
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
||
|
.replace(/toString| for [^\]]+/g, '.*?') + '$'
|
||
|
);
|
||
|
|
||
|
var setImmediate = typeof (setImmediate = freeGlobal && moduleExports && freeGlobal.setImmediate) == 'function' &&
|
||
|
!reNative.test(setImmediate) && setImmediate;
|
||
|
|
||
|
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, setImmediate, nextTick, postMessage, MessageChannel, script readystatechanged, setTimeout
|
||
|
if (isFunction(setImmediate)) {
|
||
|
scheduleMethod = function (action) {
|
||
|
var id = nextHandle++;
|
||
|
tasksByHandle[id] = action;
|
||
|
setImmediate(function () { runTask(id); });
|
||
|
|
||
|
return id;
|
||
|
};
|
||
|
} else if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
|
||
|
scheduleMethod = function (action) {
|
||
|
var id = nextHandle++;
|
||
|
tasksByHandle[id] = action;
|
||
|
process.nextTick(function () { runTask(id); });
|
||
|
|
||
|
return id;
|
||
|
};
|
||
|
} else if (postMessageSupported()) {
|
||
|
var MSG_PREFIX = 'ms.rx.schedule' + Math.random();
|
||
|
|
||
|
var onGlobalPostMessage = function (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) {
|
||
|
runTask(event.data.substring(MSG_PREFIX.length));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
root.addEventListener('message', onGlobalPostMessage, false);
|
||
|
|
||
|
scheduleMethod = function (action) {
|
||
|
var id = nextHandle++;
|
||
|
tasksByHandle[id] = action;
|
||
|
root.postMessage(MSG_PREFIX + id, '*');
|
||
|
return id;
|
||
|
};
|
||
|
} else if (!!root.MessageChannel) {
|
||
|
var channel = new root.MessageChannel();
|
||
|
|
||
|
channel.port1.onmessage = function (e) { runTask(e.data); };
|
||
|
|
||
|
scheduleMethod = function (action) {
|
||
|
var id = nextHandle++;
|
||
|
tasksByHandle[id] = action;
|
||
|
channel.port2.postMessage(id);
|
||
|
return id;
|
||
|
};
|
||
|
} else if ('document' in root && 'onreadystatechange' in root.document.createElement('script')) {
|
||
|
|
||
|
scheduleMethod = function (action) {
|
||
|
var scriptElement = root.document.createElement('script');
|
||
|
var id = nextHandle++;
|
||
|
tasksByHandle[id] = action;
|
||
|
|
||
|
scriptElement.onreadystatechange = function () {
|
||
|
runTask(id);
|
||
|
scriptElement.onreadystatechange = null;
|
||
|
scriptElement.parentNode.removeChild(scriptElement);
|
||
|
scriptElement = null;
|
||
|
};
|
||
|
root.document.documentElement.appendChild(scriptElement);
|
||
|
return id;
|
||
|
};
|
||
|
|
||
|
} else {
|
||
|
scheduleMethod = function (action) {
|
||
|
var id = nextHandle++;
|
||
|
tasksByHandle[id] = action;
|
||
|
localSetTimeout(function () {
|
||
|
runTask(id);
|
||
|
}, 0);
|
||
|
|
||
|
return id;
|
||
|
};
|
||
|
}
|
||
|
}());
|
||
|
|
||
|
/**
|
||
|
* Gets a scheduler that schedules work via a timed callback based upon platform.
|
||
|
*/
|
||
|
var DefaultScheduler = (function (__super__) {
|
||
|
inherits(DefaultScheduler, __super__);
|
||
|
function DefaultScheduler() {
|
||
|
__super__.call(this);
|
||
|
}
|
||
|
|
||
|
function scheduleAction(disposable, action, scheduler, state) {
|
||
|
return function schedule() {
|
||
|
disposable.setDisposable(Disposable._fixup(action(scheduler, state)));
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function ClearDisposable(id) {
|
||
|
this._id = id;
|
||
|
this.isDisposed = false;
|
||
|
}
|
||
|
|
||
|
ClearDisposable.prototype.dispose = function () {
|
||
|
if (!this.isDisposed) {
|
||
|
this.isDisposed = true;
|
||
|
clearMethod(this._id);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
function LocalClearDisposable(id) {
|
||
|
this._id = id;
|
||
|
this.isDisposed = false;
|
||
|
}
|
||
|
|
||
|
LocalClearDisposable.prototype.dispose = function () {
|
||
|
if (!this.isDisposed) {
|
||
|
this.isDisposed = true;
|
||
|
localClearTimeout(this._id);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
DefaultScheduler.prototype.schedule = function (state, action) {
|
||
|
var disposable = new SingleAssignmentDisposable(),
|
||
|
id = scheduleMethod(scheduleAction(disposable, action, this, state));
|
||
|
return new BinaryDisposable(disposable, new ClearDisposable(id));
|
||
|
};
|
||
|
|
||
|
DefaultScheduler.prototype._scheduleFuture = function (state, dueTime, action) {
|
||
|
if (dueTime === 0) { return this.schedule(state, action); }
|
||
|
var disposable = new SingleAssignmentDisposable(),
|
||
|
id = localSetTimeout(scheduleAction(disposable, action, this, state), dueTime);
|
||
|
return new BinaryDisposable(disposable, new LocalClearDisposable(id));
|
||
|
};
|
||
|
|
||
|
function scheduleLongRunning(state, action, disposable) {
|
||
|
return function () { action(state, disposable); };
|
||
|
}
|
||
|
|
||
|
DefaultScheduler.prototype.scheduleLongRunning = function (state, action) {
|
||
|
var disposable = disposableCreate(noop);
|
||
|
scheduleMethod(scheduleLongRunning(state, action, disposable));
|
||
|
return disposable;
|
||
|
};
|
||
|
|
||
|
return DefaultScheduler;
|
||
|
}(Scheduler));
|
||
|
|
||
|
var defaultScheduler = Scheduler['default'] = Scheduler.async = new DefaultScheduler();
|
||
|
|
||
|
function IndexedItem(id, value) {
|
||
|
this.id = id;
|
||
|
this.value = value;
|
||
|
}
|
||
|
|
||
|
IndexedItem.prototype.compareTo = function (other) {
|
||
|
var c = this.value.compareTo(other.value);
|
||
|
c === 0 && (c = this.id - other.id);
|
||
|
return c;
|
||
|
};
|
||
|
|
||
|
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) {
|
||
|
+index || (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];
|
||
|
this.items[this.length] = undefined;
|
||
|
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;
|
||
|
|
||
|
/**
|
||
|
* Supports push-style iteration over an observable sequence.
|
||
|
*/
|
||
|
var Observer = Rx.Observer = function () { };
|
||
|
|
||
|
/**
|
||
|
* Creates an observer from the specified OnNext, along with optional OnError, and OnCompleted actions.
|
||
|
* @param {Function} [onNext] Observer's OnNext action implementation.
|
||
|
* @param {Function} [onError] Observer's OnError action implementation.
|
||
|
* @param {Function} [onCompleted] Observer's OnCompleted action implementation.
|
||
|
* @returns {Observer} The observer object implemented using the given actions.
|
||
|
*/
|
||
|
var observerCreate = Observer.create = function (onNext, onError, onCompleted) {
|
||
|
onNext || (onNext = noop);
|
||
|
onError || (onError = defaultError);
|
||
|
onCompleted || (onCompleted = noop);
|
||
|
return new AnonymousObserver(onNext, onError, onCompleted);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Abstract base class for implementations of the Observer class.
|
||
|
* This base class enforces the grammar of observers where OnError and OnCompleted are terminal messages.
|
||
|
*/
|
||
|
var AbstractObserver = Rx.internals.AbstractObserver = (function (__super__) {
|
||
|
inherits(AbstractObserver, __super__);
|
||
|
|
||
|
/**
|
||
|
* Creates a new observer in a non-stopped state.
|
||
|
*/
|
||
|
function AbstractObserver() {
|
||
|
this.isStopped = false;
|
||
|
}
|
||
|
|
||
|
// Must be implemented by other observers
|
||
|
AbstractObserver.prototype.next = notImplemented;
|
||
|
AbstractObserver.prototype.error = notImplemented;
|
||
|
AbstractObserver.prototype.completed = notImplemented;
|
||
|
|
||
|
/**
|
||
|
* Notifies the observer of a new element in the sequence.
|
||
|
* @param {Any} value Next element in the sequence.
|
||
|
*/
|
||
|
AbstractObserver.prototype.onNext = function (value) {
|
||
|
!this.isStopped && this.next(value);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Notifies the observer that an exception has occurred.
|
||
|
* @param {Any} error The error that has occurred.
|
||
|
*/
|
||
|
AbstractObserver.prototype.onError = function (error) {
|
||
|
if (!this.isStopped) {
|
||
|
this.isStopped = true;
|
||
|
this.error(error);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Notifies the observer of the end of the sequence.
|
||
|
*/
|
||
|
AbstractObserver.prototype.onCompleted = function () {
|
||
|
if (!this.isStopped) {
|
||
|
this.isStopped = true;
|
||
|
this.completed();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Disposes the observer, causing it to transition to the stopped state.
|
||
|
*/
|
||
|
AbstractObserver.prototype.dispose = function () { this.isStopped = true; };
|
||
|
|
||
|
AbstractObserver.prototype.fail = function (e) {
|
||
|
if (!this.isStopped) {
|
||
|
this.isStopped = true;
|
||
|
this.error(e);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
return AbstractObserver;
|
||
|
}(Observer));
|
||
|
|
||
|
/**
|
||
|
* Class to create an Observer instance from delegate-based implementations of the on* methods.
|
||
|
*/
|
||
|
var AnonymousObserver = Rx.AnonymousObserver = (function (__super__) {
|
||
|
inherits(AnonymousObserver, __super__);
|
||
|
|
||
|
/**
|
||
|
* Creates an observer from the specified OnNext, OnError, and OnCompleted actions.
|
||
|
* @param {Any} onNext Observer's OnNext action implementation.
|
||
|
* @param {Any} onError Observer's OnError action implementation.
|
||
|
* @param {Any} onCompleted Observer's OnCompleted action implementation.
|
||
|
*/
|
||
|
function AnonymousObserver(onNext, onError, onCompleted) {
|
||
|
__super__.call(this);
|
||
|
this._onNext = onNext;
|
||
|
this._onError = onError;
|
||
|
this._onCompleted = onCompleted;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Calls the onNext action.
|
||
|
* @param {Any} value Next element in the sequence.
|
||
|
*/
|
||
|
AnonymousObserver.prototype.next = function (value) {
|
||
|
this._onNext(value);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Calls the onError action.
|
||
|
* @param {Any} error The error that has occurred.
|
||
|
*/
|
||
|
AnonymousObserver.prototype.error = function (error) {
|
||
|
this._onError(error);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Calls the onCompleted action.
|
||
|
*/
|
||
|
AnonymousObserver.prototype.completed = function () {
|
||
|
this._onCompleted();
|
||
|
};
|
||
|
|
||
|
return AnonymousObserver;
|
||
|
}(AbstractObserver));
|
||
|
|
||
|
var observableProto;
|
||
|
|
||
|
/**
|
||
|
* Represents a push-style collection.
|
||
|
*/
|
||
|
var Observable = Rx.Observable = (function () {
|
||
|
|
||
|
function makeSubscribe(self, subscribe) {
|
||
|
return function (o) {
|
||
|
var oldOnError = o.onError;
|
||
|
o.onError = function (e) {
|
||
|
makeStackTraceLong(e, self);
|
||
|
oldOnError.call(o, e);
|
||
|
};
|
||
|
|
||
|
return subscribe.call(self, o);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function Observable() {
|
||
|
if (Rx.config.longStackSupport && hasStacks) {
|
||
|
var oldSubscribe = this._subscribe;
|
||
|
var e = tryCatch(thrower)(new Error()).e;
|
||
|
this.stack = e.stack.substring(e.stack.indexOf('\n') + 1);
|
||
|
this._subscribe = makeSubscribe(this, oldSubscribe);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
observableProto = Observable.prototype;
|
||
|
|
||
|
/**
|
||
|
* Determines whether the given object is an Observable
|
||
|
* @param {Any} An object to determine whether it is an Observable
|
||
|
* @returns {Boolean} true if an Observable, else false.
|
||
|
*/
|
||
|
Observable.isObservable = function (o) {
|
||
|
return o && isFunction(o.subscribe);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Subscribes an o to the observable sequence.
|
||
|
* @param {Mixed} [oOrOnNext] The object that is to receive notifications or an action to invoke for each element in the observable sequence.
|
||
|
* @param {Function} [onError] Action to invoke upon exceptional termination of the observable sequence.
|
||
|
* @param {Function} [onCompleted] Action to invoke upon graceful termination of the observable sequence.
|
||
|
* @returns {Diposable} A disposable handling the subscriptions and unsubscriptions.
|
||
|
*/
|
||
|
observableProto.subscribe = observableProto.forEach = function (oOrOnNext, onError, onCompleted) {
|
||
|
return this._subscribe(typeof oOrOnNext === 'object' ?
|
||
|
oOrOnNext :
|
||
|
observerCreate(oOrOnNext, onError, onCompleted));
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Subscribes to the next value in the sequence with an optional "this" argument.
|
||
|
* @param {Function} onNext The function to invoke on each element in the observable sequence.
|
||
|
* @param {Any} [thisArg] Object to use as this when executing callback.
|
||
|
* @returns {Disposable} A disposable handling the subscriptions and unsubscriptions.
|
||
|
*/
|
||
|
observableProto.subscribeOnNext = function (onNext, thisArg) {
|
||
|
return this._subscribe(observerCreate(typeof thisArg !== 'undefined' ? function(x) { onNext.call(thisArg, x); } : onNext));
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Subscribes to an exceptional condition in the sequence with an optional "this" argument.
|
||
|
* @param {Function} onError The function to invoke upon exceptional termination of the observable sequence.
|
||
|
* @param {Any} [thisArg] Object to use as this when executing callback.
|
||
|
* @returns {Disposable} A disposable handling the subscriptions and unsubscriptions.
|
||
|
*/
|
||
|
observableProto.subscribeOnError = function (onError, thisArg) {
|
||
|
return this._subscribe(observerCreate(null, typeof thisArg !== 'undefined' ? function(e) { onError.call(thisArg, e); } : onError));
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Subscribes to the next value in the sequence with an optional "this" argument.
|
||
|
* @param {Function} onCompleted The function to invoke upon graceful termination of the observable sequence.
|
||
|
* @param {Any} [thisArg] Object to use as this when executing callback.
|
||
|
* @returns {Disposable} A disposable handling the subscriptions and unsubscriptions.
|
||
|
*/
|
||
|
observableProto.subscribeOnCompleted = function (onCompleted, thisArg) {
|
||
|
return this._subscribe(observerCreate(null, null, typeof thisArg !== 'undefined' ? function() { onCompleted.call(thisArg); } : onCompleted));
|
||
|
};
|
||
|
|
||
|
return Observable;
|
||
|
})();
|
||
|
|
||
|
var AnonymousObservable = Rx.AnonymousObservable = (function (__super__) {
|
||
|
inherits(AnonymousObservable, __super__);
|
||
|
|
||
|
// Fix subscriber to check for undefined or function returned to decorate as Disposable
|
||
|
function fixSubscriber(subscriber) {
|
||
|
return subscriber && isFunction(subscriber.dispose) ? subscriber :
|
||
|
isFunction(subscriber) ? disposableCreate(subscriber) : disposableEmpty;
|
||
|
}
|
||
|
|
||
|
function setDisposable(s, state) {
|
||
|
var ado = state[0], self = state[1];
|
||
|
var sub = tryCatch(self.__subscribe).call(self, ado);
|
||
|
if (sub === errorObj && !ado.fail(errorObj.e)) { thrower(errorObj.e); }
|
||
|
ado.setDisposable(fixSubscriber(sub));
|
||
|
}
|
||
|
|
||
|
function AnonymousObservable(subscribe, parent) {
|
||
|
this.source = parent;
|
||
|
this.__subscribe = subscribe;
|
||
|
__super__.call(this);
|
||
|
}
|
||
|
|
||
|
AnonymousObservable.prototype._subscribe = function (o) {
|
||
|
var ado = new AutoDetachObserver(o), state = [ado, this];
|
||
|
|
||
|
if (currentThreadScheduler.scheduleRequired()) {
|
||
|
currentThreadScheduler.schedule(state, setDisposable);
|
||
|
} else {
|
||
|
setDisposable(null, state);
|
||
|
}
|
||
|
return ado;
|
||
|
};
|
||
|
|
||
|
return AnonymousObservable;
|
||
|
|
||
|
}(Observable));
|
||
|
|
||
|
var ObservableBase = Rx.ObservableBase = (function (__super__) {
|
||
|
inherits(ObservableBase, __super__);
|
||
|
|
||
|
function fixSubscriber(subscriber) {
|
||
|
return subscriber && isFunction(subscriber.dispose) ? subscriber :
|
||
|
isFunction(subscriber) ? disposableCreate(subscriber) : disposableEmpty;
|
||
|
}
|
||
|
|
||
|
function setDisposable(s, state) {
|
||
|
var ado = state[0], self = state[1];
|
||
|
var sub = tryCatch(self.subscribeCore).call(self, ado);
|
||
|
if (sub === errorObj && !ado.fail(errorObj.e)) { thrower(errorObj.e); }
|
||
|
ado.setDisposable(fixSubscriber(sub));
|
||
|
}
|
||
|
|
||
|
function ObservableBase() {
|
||
|
__super__.call(this);
|
||
|
}
|
||
|
|
||
|
ObservableBase.prototype._subscribe = function (o) {
|
||
|
var ado = new AutoDetachObserver(o), state = [ado, this];
|
||
|
|
||
|
if (currentThreadScheduler.scheduleRequired()) {
|
||
|
currentThreadScheduler.schedule(state, setDisposable);
|
||
|
} else {
|
||
|
setDisposable(null, state);
|
||
|
}
|
||
|
return ado;
|
||
|
};
|
||
|
|
||
|
ObservableBase.prototype.subscribeCore = notImplemented;
|
||
|
|
||
|
return ObservableBase;
|
||
|
}(Observable));
|
||
|
|
||
|
var AutoDetachObserver = (function (__super__) {
|
||
|
inherits(AutoDetachObserver, __super__);
|
||
|
|
||
|
function AutoDetachObserver(observer) {
|
||
|
__super__.call(this);
|
||
|
this.observer = observer;
|
||
|
this.m = new SingleAssignmentDisposable();
|
||
|
}
|
||
|
|
||
|
var AutoDetachObserverPrototype = AutoDetachObserver.prototype;
|
||
|
|
||
|
AutoDetachObserverPrototype.next = function (value) {
|
||
|
var result = tryCatch(this.observer.onNext).call(this.observer, value);
|
||
|
if (result === errorObj) {
|
||
|
this.dispose();
|
||
|
thrower(result.e);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
AutoDetachObserverPrototype.error = function (err) {
|
||
|
var result = tryCatch(this.observer.onError).call(this.observer, err);
|
||
|
this.dispose();
|
||
|
result === errorObj && thrower(result.e);
|
||
|
};
|
||
|
|
||
|
AutoDetachObserverPrototype.completed = function () {
|
||
|
var result = tryCatch(this.observer.onCompleted).call(this.observer);
|
||
|
this.dispose();
|
||
|
result === errorObj && thrower(result.e);
|
||
|
};
|
||
|
|
||
|
AutoDetachObserverPrototype.setDisposable = function (value) { this.m.setDisposable(value); };
|
||
|
AutoDetachObserverPrototype.getDisposable = function () { return this.m.getDisposable(); };
|
||
|
|
||
|
AutoDetachObserverPrototype.dispose = function () {
|
||
|
__super__.prototype.dispose.call(this);
|
||
|
this.m.dispose();
|
||
|
};
|
||
|
|
||
|
return AutoDetachObserver;
|
||
|
}(AbstractObserver));
|
||
|
|
||
|
/**
|
||
|
* Creates an observable sequence from a specified subscribe method implementation.
|
||
|
* @example
|
||
|
* var res = Rx.Observable.create(function (observer) { return function () { } );
|
||
|
* var res = Rx.Observable.create(function (observer) { return Rx.Disposable.empty; } );
|
||
|
* var res = Rx.Observable.create(function (observer) { } );
|
||
|
* @param {Function} subscribe Implementation of the resulting observable sequence's subscribe method, returning a function that will be wrapped in a Disposable.
|
||
|
* @returns {Observable} The observable sequence with the specified implementation for the Subscribe method.
|
||
|
*/
|
||
|
Observable.create = function (subscribe, parent) {
|
||
|
return new AnonymousObservable(subscribe, parent);
|
||
|
};
|
||
|
|
||
|
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
|
||
|
root.Rx = Rx;
|
||
|
|
||
|
define(function() {
|
||
|
return Rx;
|
||
|
});
|
||
|
} else if (freeExports && freeModule) {
|
||
|
// in Node.js or RingoJS
|
||
|
if (moduleExports) {
|
||
|
(freeModule.exports = Rx).Rx = Rx;
|
||
|
} else {
|
||
|
freeExports.Rx = Rx;
|
||
|
}
|
||
|
} else {
|
||
|
// in a browser or Rhino
|
||
|
root.Rx = Rx;
|
||
|
}
|
||
|
|
||
|
// All code before this point will be filtered from stack traces.
|
||
|
var rEndingLine = captureLine();
|
||
|
|
||
|
}.call(this));
|