// 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'], 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')); } 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, isFunction = Rx.helpers.isFunction, 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) { return; } this.isStopped = true; for (var i = 0, os = this.observers.slice(0), 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.call(this); if (this.isStopped) { return; } this.isStopped = true; this.hasError = true; this.error = error; for (var i = 0, os = this.observers.slice(0), 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.call(this); if (this.isStopped) { return; } this.value = value; for (var i = 0, os = this.observers.slice(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 createRemovableDisposable(subject, observer) { return disposableCreate(function () { observer.dispose(); !subject.isDisposed && subject.observers.splice(subject.observers.indexOf(observer), 1); }); } function subscribe(observer) { var so = new ScheduledObserver(this.scheduler, observer), subscription = createRemovableDisposable(this, so); checkDisposed.call(this); 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; } 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.prototype, { /** * 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; }, _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.call(this); if (this.isStopped) { return; } 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++) { var 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) { checkDisposed.call(this); if (this.isStopped) { return; } 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++) { var observer = o[i]; observer.onError(error); observer.ensureActive(); } this.observers = []; }, /** * Notifies all subscribed observers about the end of the sequence. */ onCompleted: function () { checkDisposed.call(this); if (this.isStopped) { return; } 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++) { var 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)); var ConnectableObservable = Rx.ConnectableObservable = (function (__super__) { inherits(ConnectableObservable, __super__); function ConnectableObservable(source, subject) { var hasSubscription = false, subscription, sourceObservable = source.asObservable(); this.connect = function () { if (!hasSubscription) { hasSubscription = true; subscription = new CompositeDisposable(sourceObservable.subscribe(subject), disposableCreate(function () { hasSubscription = false; })); } return subscription; }; __super__.call(this, function (o) { return subject.subscribe(o); }); } ConnectableObservable.prototype.refCount = function () { var connectableSubscription, count = 0, source = this; return new AnonymousObservable(function (observer) { var shouldConnect = ++count === 1, subscription = source.subscribe(observer); shouldConnect && (connectableSubscription = source.connect()); return function () { subscription.dispose(); --count === 0 && connectableSubscription.dispose(); }; }); }; return ConnectableObservable; }(Observable)); return Rx; }));