// Copyright (c) Microsoft, All rights reserved. See License.txt in the project root for license information. ;(function (factory) { 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')(); // Because of build optimizers if (typeof define === 'function' && define.amd) { define(['./rx.core'], function (Rx, exports) { return factory(root, exports, Rx); }); } else if (typeof module === 'object' && module && module.exports === freeExports) { module.exports = factory(root, module.exports, require('./rx.core')); } else { root.Rx = factory(root, {}, root.Rx); } }.call(this, function (root, exp, Rx, undefined) { var Observable = Rx.Observable, observableProto = Observable.prototype, AnonymousObservable = Rx.AnonymousObservable, ObservableBase = Rx.ObservableBase, Observer = Rx.Observer, AbstractObserver = Rx.internals.AbstractObserver, disposableCreate = Rx.Disposable.create, disposableEmpty = Rx.Disposable.empty, CompositeDisposable = Rx.CompositeDisposable, BinaryDisposable = Rx.BinaryDisposable, SerialDisposable = Rx.SerialDisposable, currentThreadScheduler = Rx.Scheduler.currentThread, isFunction = Rx.helpers.isFunction, inherits = Rx.internals.inherits, addProperties = Rx.internals.addProperties, checkDisposed = Rx.Disposable.checkDisposed; // Utilities function cloneArray(arr) { var len = arr.length, a = new Array(len); for(var i = 0; i < len; i++) { a[i] = arr[i]; } return a; } 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; } var MulticastObservable = (function (__super__) { inherits(MulticastObservable, __super__); function MulticastObservable(source, fn1, fn2) { this.source = source; this._fn1 = fn1; this._fn2 = fn2; __super__.call(this); } MulticastObservable.prototype.subscribeCore = function (o) { var connectable = this.source.multicast(this._fn1()); return new BinaryDisposable(this._fn2(connectable).subscribe(o), connectable.connect()); }; return MulticastObservable; }(ObservableBase)); /** * Multicasts the source sequence notifications through an instantiated subject into all uses of the sequence within a selector function. Each * subscription to the resulting sequence causes a separate multicast invocation, exposing the sequence resulting from the selector function's * invocation. For specializations with fixed subject types, see Publish, PublishLast, and Replay. * * @example * 1 - res = source.multicast(observable); * 2 - res = source.multicast(function () { return new Subject(); }, function (x) { return x; }); * * @param {Function|Subject} subjectOrSubjectSelector * Factory function to create an intermediate subject through which the source sequence's elements will be multicast to the selector function. * Or: * Subject to push source elements into. * * @param {Function} [selector] Optional selector function which can use the multicasted source sequence subject to the policies enforced by the created subject. Specified only if 0) { work = state.queue.shift(); } else { state.isAcquired = false; return; } var res = tryCatch(work)(); if (res === errorObj) { state.queue = []; state.hasFaulted = true; return thrower(res.e); } recurse(state); } ScheduledObserver.prototype.ensureActive = function () { var isOwner = false; if (!this.hasFaulted && this.queue.length > 0) { isOwner = !this.isAcquired; this.isAcquired = true; } isOwner && this.disposable.setDisposable(this.scheduler.scheduleRecursive(this, scheduleMethod)); }; ScheduledObserver.prototype.dispose = function () { __super__.prototype.dispose.call(this); this.disposable.dispose(); }; return ScheduledObserver; }(AbstractObserver)); var InnerSubscription = function (s, o) { this._s = s; this._o = o; }; InnerSubscription.prototype.dispose = function () { if (!this._s.isDisposed && this._o !== null) { var idx = this._s.observers.indexOf(this._o); this._s.observers.splice(idx, 1); this._o = null; } }; /** * Represents an object that is both an observable sequence as well as an observer. * Each notification is broadcasted to all subscribed observers. */ var Subject = Rx.Subject = (function (__super__) { inherits(Subject, __super__); function Subject() { __super__.call(this); this.isDisposed = false; this.isStopped = false; this.observers = []; this.hasError = false; } addProperties(Subject.prototype, Observer.prototype, { _subscribe: function (o) { checkDisposed(this); if (!this.isStopped) { this.observers.push(o); return new InnerSubscription(this, o); } if (this.hasError) { o.onError(this.error); return disposableEmpty; } o.onCompleted(); return disposableEmpty; }, /** * Indicates whether the subject has observers subscribed to it. * @returns {Boolean} Indicates whether the subject has observers subscribed to it. */ hasObservers: function () { checkDisposed(this); return this.observers.length > 0; }, /** * Notifies all subscribed observers about the end of the sequence. */ onCompleted: function () { checkDisposed(this); if (!this.isStopped) { this.isStopped = true; for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) { os[i].onCompleted(); } this.observers.length = 0; } }, /** * Notifies all subscribed observers about the exception. * @param {Mixed} error The exception to send to all observers. */ onError: function (error) { checkDisposed(this); if (!this.isStopped) { this.isStopped = true; this.error = error; this.hasError = true; for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) { os[i].onError(error); } this.observers.length = 0; } }, /** * Notifies all subscribed observers about the arrival of the specified element in the sequence. * @param {Mixed} value The value to send to all observers. */ onNext: function (value) { checkDisposed(this); if (!this.isStopped) { for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) { os[i].onNext(value); } } }, /** * Unsubscribe all observers and release resources. */ dispose: function () { this.isDisposed = true; this.observers = null; } }); /** * Creates a subject from the specified observer and observable. * @param {Observer} observer The observer used to send messages to the subject. * @param {Observable} observable The observable used to subscribe to messages sent from the subject. * @returns {Subject} Subject implemented using the given observer and observable. */ Subject.create = function (observer, observable) { return new AnonymousSubject(observer, observable); }; return Subject; }(Observable)); var AnonymousSubject = Rx.AnonymousSubject = (function (__super__) { inherits(AnonymousSubject, __super__); function AnonymousSubject(observer, observable) { this.observer = observer; this.observable = observable; __super__.call(this); } addProperties(AnonymousSubject.prototype, Observer.prototype, { _subscribe: function (o) { return this.observable.subscribe(o); }, onCompleted: function () { this.observer.onCompleted(); }, onError: function (error) { this.observer.onError(error); }, onNext: function (value) { this.observer.onNext(value); } }); return AnonymousSubject; }(Observable)); /** * Represents the result of an asynchronous operation. * The last value before the OnCompleted notification, or the error received through OnError, is sent to all subscribed observers. */ var AsyncSubject = Rx.AsyncSubject = (function (__super__) { inherits(AsyncSubject, __super__); /** * Creates a subject that can only receive one value and that value is cached for all future observations. * @constructor */ function AsyncSubject() { __super__.call(this); this.isDisposed = false; this.isStopped = false; this.hasValue = false; this.observers = []; this.hasError = false; } addProperties(AsyncSubject.prototype, Observer.prototype, { _subscribe: function (o) { checkDisposed(this); if (!this.isStopped) { this.observers.push(o); return new InnerSubscription(this, o); } if (this.hasError) { o.onError(this.error); } else if (this.hasValue) { o.onNext(this.value); o.onCompleted(); } else { o.onCompleted(); } return disposableEmpty; }, /** * Indicates whether the subject has observers subscribed to it. * @returns {Boolean} Indicates whether the subject has observers subscribed to it. */ hasObservers: function () { checkDisposed(this); return this.observers.length > 0; }, /** * Notifies all subscribed observers about the end of the sequence, also causing the last received value to be sent out (if any). */ onCompleted: function () { var i, len; checkDisposed(this); if (!this.isStopped) { this.isStopped = true; var os = cloneArray(this.observers), len = os.length; if (this.hasValue) { for (i = 0; i < len; i++) { var o = os[i]; o.onNext(this.value); o.onCompleted(); } } else { for (i = 0; i < len; i++) { os[i].onCompleted(); } } this.observers.length = 0; } }, /** * Notifies all subscribed observers about the error. * @param {Mixed} error The Error to send to all observers. */ onError: function (error) { checkDisposed(this); if (!this.isStopped) { this.isStopped = true; this.hasError = true; this.error = error; for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) { os[i].onError(error); } this.observers.length = 0; } }, /** * Sends a value to the subject. The last value received before successful termination will be sent to all subscribed and future observers. * @param {Mixed} value The value to store in the subject. */ onNext: function (value) { checkDisposed(this); if (this.isStopped) { return; } this.value = value; this.hasValue = true; }, /** * Unsubscribe all observers and release resources. */ dispose: function () { this.isDisposed = true; this.observers = null; this.error = null; this.value = null; } }); return AsyncSubject; }(Observable)); /** * Represents a value that changes over time. * Observers can subscribe to the subject to receive the last (or initial) value and all subsequent notifications. */ var BehaviorSubject = Rx.BehaviorSubject = (function (__super__) { inherits(BehaviorSubject, __super__); function BehaviorSubject(value) { __super__.call(this); this.value = value; this.observers = []; this.isDisposed = false; this.isStopped = false; this.hasError = false; } addProperties(BehaviorSubject.prototype, Observer.prototype, { _subscribe: function (o) { checkDisposed(this); if (!this.isStopped) { this.observers.push(o); o.onNext(this.value); return new InnerSubscription(this, o); } if (this.hasError) { o.onError(this.error); } else { o.onCompleted(); } return disposableEmpty; }, /** * Gets the current value or throws an exception. * Value is frozen after onCompleted is called. * After onError is called always throws the specified exception. * An exception is always thrown after dispose is called. * @returns {Mixed} The initial value passed to the constructor until onNext is called; after which, the last value passed to onNext. */ getValue: function () { checkDisposed(this); if (this.hasError) { thrower(this.error); } return this.value; }, /** * Indicates whether the subject has observers subscribed to it. * @returns {Boolean} Indicates whether the subject has observers subscribed to it. */ hasObservers: function () { checkDisposed(this); return this.observers.length > 0; }, /** * Notifies all subscribed observers about the end of the sequence. */ onCompleted: function () { checkDisposed(this); if (this.isStopped) { return; } this.isStopped = true; for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) { os[i].onCompleted(); } this.observers.length = 0; }, /** * Notifies all subscribed observers about the exception. * @param {Mixed} error The exception to send to all observers. */ onError: function (error) { checkDisposed(this); if (this.isStopped) { return; } this.isStopped = true; this.hasError = true; this.error = error; for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) { os[i].onError(error); } this.observers.length = 0; }, /** * Notifies all subscribed observers about the arrival of the specified element in the sequence. * @param {Mixed} value The value to send to all observers. */ onNext: function (value) { checkDisposed(this); if (this.isStopped) { return; } this.value = value; for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) { os[i].onNext(value); } }, /** * Unsubscribe all observers and release resources. */ dispose: function () { this.isDisposed = true; this.observers = null; this.value = null; this.error = null; } }); return BehaviorSubject; }(Observable)); /** * Represents an object that is both an observable sequence as well as an observer. * Each notification is broadcasted to all subscribed and future observers, subject to buffer trimming policies. */ var ReplaySubject = Rx.ReplaySubject = (function (__super__) { var maxSafeInteger = Math.pow(2, 53) - 1; function createRemovableDisposable(subject, observer) { return disposableCreate(function () { observer.dispose(); !subject.isDisposed && subject.observers.splice(subject.observers.indexOf(observer), 1); }); } inherits(ReplaySubject, __super__); /** * Initializes a new instance of the ReplaySubject class with the specified buffer size, window size and scheduler. * @param {Number} [bufferSize] Maximum element count of the replay buffer. * @param {Number} [windowSize] Maximum time length of the replay buffer. * @param {Scheduler} [scheduler] Scheduler the observers are invoked on. */ function ReplaySubject(bufferSize, windowSize, scheduler) { this.bufferSize = bufferSize == null ? maxSafeInteger : bufferSize; this.windowSize = windowSize == null ? maxSafeInteger : windowSize; this.scheduler = scheduler || currentThreadScheduler; this.q = []; this.observers = []; this.isStopped = false; this.isDisposed = false; this.hasError = false; this.error = null; __super__.call(this); } addProperties(ReplaySubject.prototype, Observer.prototype, { _subscribe: function (o) { checkDisposed(this); var so = new ScheduledObserver(this.scheduler, o), subscription = createRemovableDisposable(this, so); this._trim(this.scheduler.now()); this.observers.push(so); for (var i = 0, len = this.q.length; i < len; i++) { so.onNext(this.q[i].value); } if (this.hasError) { so.onError(this.error); } else if (this.isStopped) { so.onCompleted(); } so.ensureActive(); return subscription; }, /** * Indicates whether the subject has observers subscribed to it. * @returns {Boolean} Indicates whether the subject has observers subscribed to it. */ hasObservers: function () { checkDisposed(this); return this.observers.length > 0; }, _trim: function (now) { while (this.q.length > this.bufferSize) { this.q.shift(); } while (this.q.length > 0 && (now - this.q[0].interval) > this.windowSize) { this.q.shift(); } }, /** * Notifies all subscribed observers about the arrival of the specified element in the sequence. * @param {Mixed} value The value to send to all observers. */ onNext: function (value) { checkDisposed(this); if (this.isStopped) { return; } var now = this.scheduler.now(); this.q.push({ interval: now, value: value }); this._trim(now); for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) { var observer = os[i]; observer.onNext(value); observer.ensureActive(); } }, /** * Notifies all subscribed observers about the exception. * @param {Mixed} error The exception to send to all observers. */ onError: function (error) { checkDisposed(this); if (this.isStopped) { return; } this.isStopped = true; this.error = error; this.hasError = true; var now = this.scheduler.now(); this._trim(now); for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) { var observer = os[i]; observer.onError(error); observer.ensureActive(); } this.observers.length = 0; }, /** * Notifies all subscribed observers about the end of the sequence. */ onCompleted: function () { checkDisposed(this); if (this.isStopped) { return; } this.isStopped = true; var now = this.scheduler.now(); this._trim(now); for (var i = 0, os = cloneArray(this.observers), len = os.length; i < len; i++) { var observer = os[i]; observer.onCompleted(); observer.ensureActive(); } this.observers.length = 0; }, /** * Unsubscribe all observers and release resources. */ dispose: function () { this.isDisposed = true; this.observers = null; } }); return ReplaySubject; }(Observable)); var RefCountObservable = (function (__super__) { inherits(RefCountObservable, __super__); function RefCountObservable(source) { this.source = source; this._count = 0; this._connectableSubscription = null; __super__.call(this); } RefCountObservable.prototype.subscribeCore = function (o) { var subscription = this.source.subscribe(o); ++this._count === 1 && (this._connectableSubscription = this.source.connect()); return new RefCountDisposable(this, subscription); }; function RefCountDisposable(p, s) { this._p = p; this._s = s; this.isDisposed = false; } RefCountDisposable.prototype.dispose = function () { if (!this.isDisposed) { this.isDisposed = true; this._s.dispose(); --this._p._count === 0 && this._p._connectableSubscription.dispose(); } }; return RefCountObservable; }(ObservableBase)); var ConnectableObservable = Rx.ConnectableObservable = (function (__super__) { inherits(ConnectableObservable, __super__); function ConnectableObservable(source, subject) { this.source = source; this._connection = null; this._source = source.asObservable(); this._subject = subject; __super__.call(this); } function ConnectDisposable(parent, subscription) { this._p = parent; this._s = subscription; } ConnectDisposable.prototype.dispose = function () { if (this._s) { this._s.dispose(); this._s = null; this._p._connection = null; } }; ConnectableObservable.prototype.connect = function () { if (!this._connection) { if (this._subject.isStopped) { return disposableEmpty; } var subscription = this._source.subscribe(this._subject); this._connection = new ConnectDisposable(this, subscription); } return this._connection; }; ConnectableObservable.prototype._subscribe = function (o) { return this._subject.subscribe(o); }; ConnectableObservable.prototype.refCount = function () { return new RefCountObservable(this); }; return ConnectableObservable; }(Observable)); return Rx; }));