UNPKG

box-chrome-sdk

Version:

A Chrome App SDK for the Box V2 API

664 lines (615 loc) 26.4 kB
// 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) { // References var Observable = Rx.Observable, observableProto = Observable.prototype, observableNever = Observable.never, observableThrow = Observable.throwException, AnonymousObservable = Rx.AnonymousObservable, Observer = Rx.Observer, Subject = Rx.Subject, internals = Rx.internals, helpers = Rx.helpers, ScheduledObserver = internals.ScheduledObserver, SingleAssignmentDisposable = Rx.SingleAssignmentDisposable, CompositeDisposable = Rx.CompositeDisposable, RefCountDisposable = Rx.RefCountDisposable, disposableEmpty = Rx.Disposable.empty, immediateScheduler = Rx.Scheduler.immediate, defaultKeySerializer = helpers.defaultKeySerializer, addRef = Rx.internals.addRef, identity = helpers.identity, isPromise = helpers.isPromise, inherits = internals.inherits, noop = helpers.noop, observableFromPromise = Observable.fromPromise, slice = Array.prototype.slice; function argsOrArray(args, idx) { return args.length === 1 && Array.isArray(args[idx]) ? args[idx] : slice.call(args); } var argumentOutOfRange = 'Argument out of range'; 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 CheckedObserver = (function (_super) { inherits(CheckedObserver, _super); function CheckedObserver(observer) { _super.call(this); this._observer = observer; this._state = 0; // 0 - idle, 1 - busy, 2 - done } var CheckedObserverPrototype = CheckedObserver.prototype; CheckedObserverPrototype.onNext = function (value) { this.checkAccess(); try { this._observer.onNext(value); } catch (e) { throw e; } finally { this._state = 0; } }; CheckedObserverPrototype.onError = function (err) { this.checkAccess(); try { this._observer.onError(err); } catch (e) { throw e; } finally { this._state = 2; } }; CheckedObserverPrototype.onCompleted = function () { this.checkAccess(); try { this._observer.onCompleted(); } catch (e) { throw e; } finally { this._state = 2; } }; CheckedObserverPrototype.checkAccess = function () { if (this._state === 1) { throw new Error('Re-entrancy detected'); } if (this._state === 2) { throw new Error('Observer completed'); } if (this._state === 0) { this._state = 1; } }; return CheckedObserver; }(Observer)); /** @private */ var ObserveOnObserver = (function (_super) { inherits(ObserveOnObserver, _super); /** @private */ function ObserveOnObserver() { _super.apply(this, arguments); } /** @private */ ObserveOnObserver.prototype.next = function (value) { _super.prototype.next.call(this, value); this.ensureActive(); }; /** @private */ ObserveOnObserver.prototype.error = function (e) { _super.prototype.error.call(this, e); this.ensureActive(); }; /** @private */ ObserveOnObserver.prototype.completed = function () { _super.prototype.completed.call(this); this.ensureActive(); }; return ObserveOnObserver; })(ScheduledObserver); /** * Wraps the source sequence in order to run its observer callbacks on the specified scheduler. * * This only invokes observer callbacks on a scheduler. In case the subscription and/or unsubscription actions have side-effects * that require to be run on a scheduler, use subscribeOn. * * @param {Scheduler} scheduler Scheduler to notify observers on. * @returns {Observable} The source sequence whose observations happen on the specified scheduler. */ observableProto.observeOn = function (scheduler) { var source = this; return new AnonymousObservable(function (observer) { return source.subscribe(new ObserveOnObserver(scheduler, observer)); }); }; /** * Wraps the source sequence in order to run its subscription and unsubscription logic on the specified scheduler. This operation is not commonly used; * see the remarks section for more information on the distinction between subscribeOn and observeOn. * This only performs the side-effects of subscription and unsubscription on the specified scheduler. In order to invoke observer * callbacks on a scheduler, use observeOn. * @param {Scheduler} scheduler Scheduler to perform subscription and unsubscription actions on. * @returns {Observable} The source sequence whose subscriptions and unsubscriptions happen on the specified scheduler. */ observableProto.subscribeOn = function (scheduler) { var source = this; return new AnonymousObservable(function (observer) { var m = new SingleAssignmentDisposable(), d = new SerialDisposable(); d.setDisposable(m); m.setDisposable(scheduler.schedule(function () { d.setDisposable(new ScheduledDisposable(scheduler, source.subscribe(observer))); })); return d; }); }; /** * Constructs an observable sequence that depends on a resource object, whose lifetime is tied to the resulting observable sequence's lifetime. * * @example * var res = Rx.Observable.using(function () { return new AsyncSubject(); }, function (s) { return s; }); * @param {Function} resourceFactory Factory function to obtain a resource object. * @param {Function} observableFactory Factory function to obtain an observable sequence that depends on the obtained resource. * @returns {Observable} An observable sequence whose lifetime controls the lifetime of the dependent resource object. */ Observable.using = function (resourceFactory, observableFactory) { return new AnonymousObservable(function (observer) { var disposable = disposableEmpty, resource, source; try { resource = resourceFactory(); if (resource) { disposable = resource; } source = observableFactory(resource); } catch (exception) { return new CompositeDisposable(observableThrow(exception).subscribe(observer), disposable); } return new CompositeDisposable(source.subscribe(observer), disposable); }); }; /** * Propagates the observable sequence or Promise that reacts first. * @param {Observable} rightSource Second observable sequence or Promise. * @returns {Observable} {Observable} An observable sequence that surfaces either of the given sequences, whichever reacted first. */ observableProto.amb = function (rightSource) { var leftSource = this; return new AnonymousObservable(function (observer) { var choice, leftChoice = 'L', rightChoice = 'R', leftSubscription = new SingleAssignmentDisposable(), rightSubscription = new SingleAssignmentDisposable(); isPromise(rightSource) && (rightSource = observableFromPromise(rightSource)); function choiceL() { if (!choice) { choice = leftChoice; rightSubscription.dispose(); } } function choiceR() { if (!choice) { choice = rightChoice; leftSubscription.dispose(); } } leftSubscription.setDisposable(leftSource.subscribe(function (left) { choiceL(); if (choice === leftChoice) { observer.onNext(left); } }, function (err) { choiceL(); if (choice === leftChoice) { observer.onError(err); } }, function () { choiceL(); if (choice === leftChoice) { observer.onCompleted(); } })); rightSubscription.setDisposable(rightSource.subscribe(function (right) { choiceR(); if (choice === rightChoice) { observer.onNext(right); } }, function (err) { choiceR(); if (choice === rightChoice) { observer.onError(err); } }, function () { choiceR(); if (choice === rightChoice) { observer.onCompleted(); } })); return new CompositeDisposable(leftSubscription, rightSubscription); }); }; /** * Propagates the observable sequence or Promise that reacts first. * * @example * var = Rx.Observable.amb(xs, ys, zs); * @returns {Observable} An observable sequence that surfaces any of the given sequences, whichever reacted first. */ Observable.amb = function () { var acc = observableNever(), items = argsOrArray(arguments, 0); function func(previous, current) { return previous.amb(current); } for (var i = 0, len = items.length; i < len; i++) { acc = func(acc, items[i]); } return acc; }; /** * Continues an observable sequence that is terminated normally or by an exception with the next observable sequence. * @param {Observable} second Second observable sequence used to produce results after the first sequence terminates. * @returns {Observable} An observable sequence that concatenates the first and second sequence, even if the first sequence terminates exceptionally. */ observableProto.onErrorResumeNext = function (second) { if (!second) { throw new Error('Second observable is required'); } return onErrorResumeNext([this, second]); }; /** * Continues an observable sequence that is terminated normally or by an exception with the next observable sequence. * * @example * 1 - res = Rx.Observable.onErrorResumeNext(xs, ys, zs); * 1 - res = Rx.Observable.onErrorResumeNext([xs, ys, zs]); * @returns {Observable} An observable sequence that concatenates the source sequences, even if a sequence terminates exceptionally. */ var onErrorResumeNext = Observable.onErrorResumeNext = function () { var sources = argsOrArray(arguments, 0); return new AnonymousObservable(function (observer) { var pos = 0, subscription = new SerialDisposable(), cancelable = immediateScheduler.scheduleRecursive(function (self) { var current, d; if (pos < sources.length) { current = sources[pos++]; isPromise(current) && (current = observableFromPromise(current)); d = new SingleAssignmentDisposable(); subscription.setDisposable(d); d.setDisposable(current.subscribe(observer.onNext.bind(observer), function () { self(); }, function () { self(); })); } else { observer.onCompleted(); } }); return new CompositeDisposable(subscription, cancelable); }); }; /** * Projects each element of an observable sequence into zero or more buffers which are produced based on element count information. * * @example * var res = xs.bufferWithCount(10); * var res = xs.bufferWithCount(10, 1); * @param {Number} count Length of each buffer. * @param {Number} [skip] Number of elements to skip between creation of consecutive buffers. If not provided, defaults to the count. * @returns {Observable} An observable sequence of buffers. */ observableProto.bufferWithCount = function (count, skip) { if (typeof skip !== 'number') { skip = count; } return this.windowWithCount(count, skip).selectMany(function (x) { return x.toArray(); }).where(function (x) { return x.length > 0; }); }; /** * Projects each element of an observable sequence into zero or more windows which are produced based on element count information. * * var res = xs.windowWithCount(10); * var res = xs.windowWithCount(10, 1); * @param {Number} count Length of each window. * @param {Number} [skip] Number of elements to skip between creation of consecutive windows. If not specified, defaults to the count. * @returns {Observable} An observable sequence of windows. */ observableProto.windowWithCount = function (count, skip) { var source = this; if (count <= 0) { throw new Error(argumentOutOfRange); } if (arguments.length === 1) { skip = count; } if (skip <= 0) { throw new Error(argumentOutOfRange); } return new AnonymousObservable(function (observer) { var m = new SingleAssignmentDisposable(), refCountDisposable = new RefCountDisposable(m), n = 0, q = [], createWindow = function () { var s = new Subject(); q.push(s); observer.onNext(addRef(s, refCountDisposable)); }; createWindow(); m.setDisposable(source.subscribe(function (x) { var s; for (var i = 0, len = q.length; i < len; i++) { q[i].onNext(x); } var c = n - count + 1; if (c >= 0 && c % skip === 0) { s = q.shift(); s.onCompleted(); } n++; if (n % skip === 0) { createWindow(); } }, function (exception) { while (q.length > 0) { q.shift().onError(exception); } observer.onError(exception); }, function () { while (q.length > 0) { q.shift().onCompleted(); } observer.onCompleted(); })); return refCountDisposable; }); }; /** * Returns the elements of the specified sequence or the specified value in a singleton sequence if the sequence is empty. * * var res = obs = xs.defaultIfEmpty(); * 2 - obs = xs.defaultIfEmpty(false); * * @memberOf Observable# * @param defaultValue The value to return if the sequence is empty. If not provided, this defaults to null. * @returns {Observable} An observable sequence that contains the specified default value if the source is empty; otherwise, the elements of the source itself. */ observableProto.defaultIfEmpty = function (defaultValue) { var source = this; if (defaultValue === undefined) { defaultValue = null; } return new AnonymousObservable(function (observer) { var found = false; return source.subscribe(function (x) { found = true; observer.onNext(x); }, observer.onError.bind(observer), function () { if (!found) { observer.onNext(defaultValue); } observer.onCompleted(); }); }); }; /** * Returns an observable sequence that contains only distinct elements according to the keySelector and the comparer. * Usage of this operator should be considered carefully due to the maintenance of an internal lookup structure which can grow large. * * @example * var res = obs = xs.distinct(); * 2 - obs = xs.distinct(function (x) { return x.id; }); * 2 - obs = xs.distinct(function (x) { return x.id; }, function (x) { return x.toString(); }); * @param {Function} [keySelector] A function to compute the comparison key for each element. * @param {Function} [keySerializer] Used to serialize the given object into a string for object comparison. * @returns {Observable} An observable sequence only containing the distinct elements, based on a computed key value, from the source sequence. */ observableProto.distinct = function (keySelector, keySerializer) { var source = this; keySelector || (keySelector = identity); keySerializer || (keySerializer = defaultKeySerializer); return new AnonymousObservable(function (observer) { var hashSet = {}; return source.subscribe(function (x) { var key, serializedKey, otherKey, hasMatch = false; try { key = keySelector(x); serializedKey = keySerializer(key); } catch (exception) { observer.onError(exception); return; } for (otherKey in hashSet) { if (serializedKey === otherKey) { hasMatch = true; break; } } if (!hasMatch) { hashSet[serializedKey] = null; observer.onNext(x); } }, observer.onError.bind(observer), observer.onCompleted.bind(observer)); }); }; /** * Groups the elements of an observable sequence according to a specified key selector function and comparer and selects the resulting elements by using a specified function. * * @example * var res = observable.groupBy(function (x) { return x.id; }); * 2 - observable.groupBy(function (x) { return x.id; }), function (x) { return x.name; }); * 3 - observable.groupBy(function (x) { return x.id; }), function (x) { return x.name; }, function (x) { return x.toString(); }); * @param {Function} keySelector A function to extract the key for each element. * @param {Function} [elementSelector] A function to map each source element to an element in an observable group. * @param {Function} [keySerializer] Used to serialize the given object into a string for object comparison. * @returns {Observable} A sequence of observable groups, each of which corresponds to a unique key value, containing all elements that share that same key value. */ observableProto.groupBy = function (keySelector, elementSelector, keySerializer) { return this.groupByUntil(keySelector, elementSelector, function () { return observableNever(); }, keySerializer); }; /** * Groups the elements of an observable sequence according to a specified key selector function. * A duration selector function is used to control the lifetime of groups. When a group expires, it receives an OnCompleted notification. When a new element with the same * key value as a reclaimed group occurs, the group will be reborn with a new lifetime request. * * @example * var res = observable.groupByUntil(function (x) { return x.id; }, null, function () { return Rx.Observable.never(); }); * 2 - observable.groupBy(function (x) { return x.id; }), function (x) { return x.name; }, function () { return Rx.Observable.never(); }); * 3 - observable.groupBy(function (x) { return x.id; }), function (x) { return x.name; }, function () { return Rx.Observable.never(); }, function (x) { return x.toString(); }); * @param {Function} keySelector A function to extract the key for each element. * @param {Function} durationSelector A function to signal the expiration of a group. * @param {Function} [keySerializer] Used to serialize the given object into a string for object comparison. * @returns {Observable} * A sequence of observable groups, each of which corresponds to a unique key value, containing all elements that share that same key value. * If a group's lifetime expires, a new group with the same key value can be created once an element with such a key value is encoutered. * */ observableProto.groupByUntil = function (keySelector, elementSelector, durationSelector, keySerializer) { var source = this; elementSelector || (elementSelector = identity); keySerializer || (keySerializer = defaultKeySerializer); return new AnonymousObservable(function (observer) { var map = {}, groupDisposable = new CompositeDisposable(), refCountDisposable = new RefCountDisposable(groupDisposable); groupDisposable.add(source.subscribe(function (x) { var duration, durationGroup, element, fireNewMapEntry, group, key, serializedKey, md, writer, w; try { key = keySelector(x); serializedKey = keySerializer(key); } catch (e) { for (w in map) { map[w].onError(e); } observer.onError(e); return; } fireNewMapEntry = false; try { writer = map[serializedKey]; if (!writer) { writer = new Subject(); map[serializedKey] = writer; fireNewMapEntry = true; } } catch (e) { for (w in map) { map[w].onError(e); } observer.onError(e); return; } if (fireNewMapEntry) { group = new GroupedObservable(key, writer, refCountDisposable); durationGroup = new GroupedObservable(key, writer); try { duration = durationSelector(durationGroup); } catch (e) { for (w in map) { map[w].onError(e); } observer.onError(e); return; } observer.onNext(group); md = new SingleAssignmentDisposable(); groupDisposable.add(md); var expire = function () { if (serializedKey in map) { delete map[serializedKey]; writer.onCompleted(); } groupDisposable.remove(md); }; md.setDisposable(duration.take(1).subscribe(noop, function (exn) { for (w in map) { map[w].onError(exn); } observer.onError(exn); }, function () { expire(); })); } try { element = elementSelector(x); } catch (e) { for (w in map) { map[w].onError(e); } observer.onError(e); return; } writer.onNext(element); }, function (ex) { for (var w in map) { map[w].onError(ex); } observer.onError(ex); }, function () { for (var w in map) { map[w].onCompleted(); } observer.onCompleted(); })); return refCountDisposable; }); }; /** @private */ var GroupedObservable = (function (_super) { inherits(GroupedObservable, _super); function subscribe(observer) { return this.underlyingObservable.subscribe(observer); } /** * @constructor * @private */ function GroupedObservable(key, underlyingObservable, mergedDisposable) { _super.call(this, subscribe); this.key = key; this.underlyingObservable = !mergedDisposable ? underlyingObservable : new AnonymousObservable(function (observer) { return new CompositeDisposable(mergedDisposable.getDisposable(), underlyingObservable.subscribe(observer)); }); } return GroupedObservable; }(Observable)); return Rx; }));