// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. ;(function (factory) { 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; } // Because of build optimizers if (typeof define === 'function' && define.amd) { define(['rx', 'exports'], function (Rx, exports) { root.Rx = factory(root, exports, Rx); return root.Rx; }); } else if (typeof module === 'object' && module && module.exports === freeExports) { module.exports = factory(root, module.exports, require('./rx')); } else { root.Rx = factory(root, {}, root.Rx); } }.call(this, function (root, exp, Rx, undefined) { var Observable = Rx.Observable, observableProto = Observable.prototype, AnonymousObservable = Rx.AnonymousObservable, Subject = Rx.Subject, AsyncSubject = Rx.AsyncSubject, Observer = Rx.Observer, ScheduledObserver = Rx.internals.ScheduledObserver, disposableCreate = Rx.Disposable.create, disposableEmpty = Rx.Disposable.empty, CompositeDisposable = Rx.CompositeDisposable, currentThreadScheduler = Rx.Scheduler.currentThread, inherits = Rx.internals.inherits, addProperties = Rx.internals.addProperties; // Utilities var objectDisposed = 'Object has been disposed'; function checkDisposed() { if (this.isDisposed) { throw new Error(objectDisposed); } } /** * 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; }, /** * Notifies all subscribed observers about the end of the sequence. */ onCompleted: function () { checkDisposed.call(this); if (!this.isStopped) { var os = this.observers.slice(0); this.isStopped = true; for (var i = 0, len = os.length; i < len; i++) { os[i].onCompleted(); } this.observers = []; } }, /** * Notifies all subscribed observers about the exception. * @param {Mixed} error The exception to send to all observers. */ onError: function (error) { checkDisposed.call(this); if (!this.isStopped) { var os = this.observers.slice(0); this.isStopped = true; this.exception = error; for (var i = 0, len = os.length; i < len; i++) { os[i].onError(error); } this.observers = []; } }, /** * 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.call(this); if (!this.isStopped) { this.value = value; var os = this.observers.slice(0); for (var i = 0, 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.exception = 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) { function RemovableDisposable (subject, observer) { this.subject = subject; this.observer = observer; }; RemovableDisposable.prototype.dispose = function () { this.observer.dispose(); if (!this.subject.isDisposed) { var idx = this.subject.observers.indexOf(this.observer); this.subject.observers.splice(idx, 1); } }; function subscribe(observer) { var so = new ScheduledObserver(this.scheduler, observer), subscription = new RemovableDisposable(this, so); checkDisposed.call(this); this._trim(this.scheduler.now()); this.observers.push(so); var n = this.q.length; for (var i = 0, len = this.q.length; i < len; i++) { so.onNext(this.q[i].value); } if (this.hasError) { n++; so.onError(this.error); } else if (this.isStopped) { n++; so.onCompleted(); } so.ensureActive(n); return subscription; } 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 ? Number.MAX_VALUE : bufferSize; this.windowSize = windowSize == null ? Number.MAX_VALUE : windowSize; this.scheduler = scheduler || currentThreadScheduler; this.q = []; this.observers = []; this.isStopped = false; this.isDisposed = false; this.hasError = false; this.error = null; _super.call(this, subscribe); } addProperties(ReplaySubject.prototype, Observer, { /** * Indicates whether the subject has observers subscribed to it. * @returns {Boolean} Indicates whether the subject has observers subscribed to it. */ hasObservers: function () { return this.observers.length > 0; }, /* @private */ _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) { var observer; checkDisposed.call(this); if (!this.isStopped) { var now = this.scheduler.now(); this.q.push({ interval: now, value: value }); this._trim(now); var o = this.observers.slice(0); for (var i = 0, len = o.length; i < len; i++) { observer = o[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) { var observer; checkDisposed.call(this); if (!this.isStopped) { this.isStopped = true; this.error = error; this.hasError = true; var now = this.scheduler.now(); this._trim(now); var o = this.observers.slice(0); for (var i = 0, len = o.length; i < len; i++) { observer = o[i]; observer.onError(error); observer.ensureActive(); } this.observers = []; } }, /** * Notifies all subscribed observers about the end of the sequence. */ onCompleted: function () { var observer; checkDisposed.call(this); if (!this.isStopped) { this.isStopped = true; var now = this.scheduler.now(); this._trim(now); var o = this.observers.slice(0); for (var i = 0, len = o.length; i < len; i++) { observer = o[i]; observer.onCompleted(); observer.ensureActive(); } this.observers = []; } }, /** * Unsubscribe all observers and release resources. */ dispose: function () { this.isDisposed = true; this.observers = null; } }); return ReplaySubject; }(Observable)); /** @private */ var ConnectableObservable = Rx.ConnectableObservable = (function (_super) { inherits(ConnectableObservable, _super); /** * @constructor * @private */ function ConnectableObservable(source, subject) { var state = { subject: subject, source: source.asObservable(), hasSubscription: false, subscription: null }; this.connect = function () { if (!state.hasSubscription) { state.hasSubscription = true; state.subscription = new CompositeDisposable(state.source.subscribe(state.subject), disposableCreate(function () { state.hasSubscription = false; })); } return state.subscription; }; function subscribe(observer) { return state.subject.subscribe(observer); } _super.call(this, subscribe); } /** * @private * @memberOf ConnectableObservable */ ConnectableObservable.prototype.connect = function () { return this.connect(); }; /** * @private * @memberOf ConnectableObservable */ ConnectableObservable.prototype.refCount = function () { var connectableSubscription = null, count = 0, source = this; return new AnonymousObservable(function (observer) { var shouldConnect, subscription; count++; shouldConnect = count === 1; subscription = source.subscribe(observer); if (shouldConnect) { connectableSubscription = source.connect(); } return disposableCreate(function () { subscription.dispose(); count--; if (count === 0) { connectableSubscription.dispose(); } }); }); }; return ConnectableObservable; }(Observable)); return Rx; }));