diff --git a/spec/observables/fromEventPattern-spec.js b/spec/observables/fromEventPattern-spec.js new file mode 100644 index 0000000000..4258ef3115 --- /dev/null +++ b/spec/observables/fromEventPattern-spec.js @@ -0,0 +1,100 @@ +/* globals describe, it, expect, jasmine */ +var Rx = require('../../dist/cjs/Rx'); +var Observable = Rx.Observable; +var Promise = require('promise'); + +describe('Observable.fromEventPattern', function(){ + it('should call addHandler on subscription', function () { + var addHandlerCalledWith; + var addHandler = function (h) { + addHandlerCalledWith = h; + }; + + var removeHandler = function () { }; + + Observable.fromEventPattern(addHandler, removeHandler) + .subscribe(function () { }); + + expect(typeof addHandlerCalledWith).toBe('function'); + }); + + it('should call removeHandler on unsubscription', function () { + var removeHandlerCalledWith; + var addHandler = function () { }; + var removeHandler = function (h) { + removeHandlerCalledWith = h; + }; + + var subscription = Observable.fromEventPattern(addHandler, removeHandler) + .subscribe(function () { }); + + subscription.unsubscribe(); + + expect(typeof removeHandlerCalledWith).toBe('function'); + }); + + it('should send errors in addHandler down the error path', function () { + Observable.fromEventPattern(function (handler) { + throw 'bad'; + }, function () { }) + .subscribe(function () { }, + function (err) { + expect(err).toBe('bad'); + }); + }); + + it('should accept a selector that maps outgoing values', function (done) { + var target; + var trigger = function () { + if (target) { + target.apply(null, arguments); + } + }; + + var addHandler = function (handler) { + target = handler; + }; + var removeHandler = function (handler) { + target = null; + }; + var selector = function (a, b) { + return a + b + '!'; + }; + + Observable.fromEventPattern(addHandler, removeHandler, selector) + .subscribe(function (x) { + expect(x).toBe('testme!'); + done(); + }); + + trigger('test', 'me'); + }); + + it('should send errors in the selector down the error path', function (done) { + var target; + var trigger = function (value) { + if (target) { + target(value); + } + }; + + var addHandler = function (handler) { + target = handler; + }; + var removeHandler = function (handler) { + target = null; + }; + var selector = function (x) { + throw 'bad'; + }; + + Observable.fromEventPattern(addHandler, removeHandler, selector) + .subscribe(function () { }, + function (err) { + expect(err).toBe('bad'); + done(); + }); + + trigger('test'); + }); +}); \ No newline at end of file diff --git a/src/Observable.ts b/src/Observable.ts index 3da06c02b8..c37f4aecb4 100644 --- a/src/Observable.ts +++ b/src/Observable.ts @@ -72,7 +72,7 @@ export default class Observable { static from: (iterable: any, project?: (x?: any, i?: number) => T, thisArg?: any, scheduler?: Scheduler) => Observable; static fromArray: (array: T[], scheduler?: Scheduler) => Observable; // static fromEvent: (element: any, eventName: string, selector: (event: R) => T) => Observable; - // static fromEventPattern: (addHandler: Function, removeHandler: Function, selector: (event: R) => T) => Observable; + static fromEventPattern: (addHandler: (handler:Function)=>void, removeHandler: (handler:Function) => void, selector?: (...args:Array) => T) => Observable; static throw: (error: T) => Observable; static empty: () => Observable; static never: () => Observable; diff --git a/src/Rx.ts b/src/Rx.ts index 650eeaabac..e6d1e9a139 100644 --- a/src/Rx.ts +++ b/src/Rx.ts @@ -18,6 +18,7 @@ import PromiseObservable from './observables/PromiseObservable'; import RangeObservable from './observables/RangeObservable'; import ScalarObservable from './observables/ScalarObservable'; import TimerObservable from './observables/TimerObservable'; +import FromEventPatternObservable from './observables/FromEventPatternObservable'; Observable.defer = DeferObservable.create; Observable.from = IteratorObservable.create; @@ -25,6 +26,7 @@ Observable.fromArray = ArrayObservable.create; Observable.fromPromise = PromiseObservable.create; Observable.of = ArrayObservable.of; Observable.range = RangeObservable.create; +Observable.fromEventPattern = FromEventPatternObservable.create; Observable.just = ScalarObservable.create; Observable.return = ScalarObservable.create; diff --git a/src/Scheduler.ts b/src/Scheduler.ts index d14e6b89b1..63ce530228 100644 --- a/src/Scheduler.ts +++ b/src/Scheduler.ts @@ -173,7 +173,6 @@ export class FutureAction extends Action { } unsubscribe() { - debugger; const id = this.id; if (id != null) { this.id = void 0; diff --git a/src/observables/FromEventPatternObservable.ts b/src/observables/FromEventPatternObservable.ts new file mode 100644 index 0000000000..909ed4b4a3 --- /dev/null +++ b/src/observables/FromEventPatternObservable.ts @@ -0,0 +1,40 @@ +import Scheduler from '../Scheduler'; +import Observable from '../Observable'; +import Subscription from '../Subscription'; +import tryCatch from '../util/tryCatch'; +import {errorObject} from '../util/errorObject'; + +export default class FromEventPatternObservable extends Observable { + + static create(addHandler: (handler: Function) => any, removeHandler: (handler: Function) => void, selector?: (...args:Array) => T) { + return new FromEventPatternObservable(addHandler, removeHandler, selector);; + } + + constructor(private addHandler: (handler:Function) => any, private removeHandler: (handler:Function) => void, private selector?: (...args:Array) => T) { + super(); + } + + _subscribe(subscriber) { + const addHandler = this.addHandler; + const removeHandler = this.removeHandler; + const selector = this.selector; + + const handler = selector ? function(e) { + let result = tryCatch(selector).apply(null, arguments); + if (result === errorObject) { + subscriber.error(result.e); + } else { + subscriber.next(result); + } + } : function(e) { subscriber.next(e); } + + let result = tryCatch(addHandler)(handler); + if (result === errorObject) { + subscriber.error(result.e); + } + subscriber.add(new Subscription(() => { + //TODO: determine whether or not to forward to error handler + removeHandler(handler) + })); + } +}