From 2f92cb3ff481ac1ae03f47ceb4a9660954418cd7 Mon Sep 17 00:00:00 2001 From: Hristo Deshev Date: Sat, 17 Oct 2015 18:59:26 +0300 Subject: [PATCH] Implement XHR addEventListener/removeEventListener events. - Used by the Angular XHRBackend service. - Only supporting 'load' and 'error' now. - Not implemented as weak events. Client responsible for detaching or not keeping a reference to the XHR object forever. (NG XHRBackend does so) --- apps/tests/xhr-tests.ts | 29 +++++++++++++++++++++++++ xhr/xhr.ts | 48 +++++++++++++++++++++++++++++++++-------- 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/apps/tests/xhr-tests.ts b/apps/tests/xhr-tests.ts index 811ae4769..9756fa880 100644 --- a/apps/tests/xhr-tests.ts +++ b/apps/tests/xhr-tests.ts @@ -221,6 +221,35 @@ export function test_raises_onload_Event(done) { xhr.send(); } +export function test_xhr_events(done) { + let xhr = new XMLHttpRequest(); + + let loadCallbackFired = false, loadEventFired = false; + xhr.onload = () => loadCallbackFired = true; + let badEvent = () => { throw new Error("Shouldn't call me") } + xhr.addEventListener('load', () => loadEventFired = true); + xhr.addEventListener('load', badEvent); + xhr.removeEventListener('load', badEvent); + + xhr._errorFlag = false; + xhr._setReadyState(xhr.DONE); + TKUnit.assertTrue(loadCallbackFired); + TKUnit.assertTrue(loadEventFired); + + let errorCallbackData = null, errorEventData = null; + xhr.onerror = (e) => errorCallbackData = e; + xhr.addEventListener('error', (e) => errorEventData = e); + xhr.addEventListener('error', badEvent); + xhr.removeEventListener('error', badEvent); + + xhr._errorFlag = true; + xhr._setReadyState(xhr.DONE, 'error data'); + TKUnit.assertEqual(errorCallbackData, 'error data'); + TKUnit.assertEqual(errorEventData, 'error data'); + + done(null); +} + export function test_sets_status_and_statusText(done) { let xhr = new XMLHttpRequest(); xhr.onreadystatechange = () => { diff --git a/xhr/xhr.ts b/xhr/xhr.ts index b9dc5b2e5..f4268cfed 100644 --- a/xhr/xhr.ts +++ b/xhr/xhr.ts @@ -15,7 +15,7 @@ export class XMLHttpRequest { public DONE = 4; public onload: () => void; - public onerror: () => void; + public onerror: (any) => void; private _options: http.HttpRequestOptions; private _readyState: number; @@ -99,11 +99,36 @@ export class XMLHttpRequest { }).catch(e => { this._errorFlag = true; - this._setReadyState(this.DONE); + this._setReadyState(this.DONE, e); }); } } + private _listeners: Map> = new Map>(); + + public addEventListener(eventName: string, handler: Function) { + if (eventName !== 'load' && eventName !== 'error') { + throw new Error('Event not supported: ' + eventName); + } + + let handlers = this._listeners.get(eventName) || []; + handlers.push(handler); + this._listeners.set(eventName, handlers); + } + + public removeEventListener(eventName: string, toDetach: Function) { + let handlers = this._listeners.get(eventName) || []; + handlers = handlers.filter((handler) => handler !== toDetach); + this._listeners.set(eventName, handlers); + } + + private emitEvent(eventName: string, ...args: Array) { + let handlers = this._listeners.get(eventName) || []; + handlers.forEach((handler) => { + handler(...args); + }); + } + public setRequestHeader(header: string, value: string) { if (types.isDefined(this._options) && types.isString(header) && types.isString(value)) { this._options.headers[header] = value; @@ -158,7 +183,7 @@ export class XMLHttpRequest { } } - private _setReadyState(value: number) { + private _setReadyState(value: number, error?: any) { if (this._readyState !== value) { this._readyState = value; @@ -168,11 +193,16 @@ export class XMLHttpRequest { } if (this._readyState === this.DONE) { - if (this._errorFlag && types.isFunction(this.onerror)) { - this.onerror(); - } - if (!this._errorFlag && types.isFunction(this.onload)) { - this.onload(); + if (this._errorFlag) { + if (types.isFunction(this.onerror)) { + this.onerror(error); + } + this.emitEvent('error', error); + } else { + if (types.isFunction(this.onload)) { + this.onload(); + } + this.emitEvent('load'); } } } @@ -264,4 +294,4 @@ export class FormData { return arr.join("&"); } -} \ No newline at end of file +}