
This class was only added to do a reverse lookup of RequestMethods enum to get its name (i.e. "GET") for Dart. Since Dart is no longer supported by Http, method names can just be retrieved with TypeScript's support for enum name lookup, i.e. RequestMethods[RequestMethods.GET] === 'GET', making the RequestMethodsMap utility obsolete. Closes #2904
98 lines
3.4 KiB
TypeScript
98 lines
3.4 KiB
TypeScript
import {ConnectionBackend, Connection} from '../interfaces';
|
|
import {ReadyStates, RequestMethods} from '../enums';
|
|
import {Request} from '../static_request';
|
|
import {Response} from '../static_response';
|
|
import {ResponseOptions, BaseResponseOptions} from '../base_response_options';
|
|
import {Injectable} from 'angular2/di';
|
|
import {BrowserJsonp} from './browser_jsonp';
|
|
import {EventEmitter, ObservableWrapper} from 'angular2/src/core/facade/async';
|
|
import {StringWrapper, isPresent, ENUM_INDEX, makeTypeError} from 'angular2/src/core/facade/lang';
|
|
|
|
export class JSONPConnection implements Connection {
|
|
readyState: ReadyStates;
|
|
request: Request;
|
|
response: EventEmitter;
|
|
private _id: string;
|
|
private _script: Element;
|
|
private _responseData: any;
|
|
private _finished: boolean = false;
|
|
|
|
constructor(req: Request, private _dom: BrowserJsonp,
|
|
private baseResponseOptions?: ResponseOptions) {
|
|
if (req.method !== RequestMethods.GET) {
|
|
throw makeTypeError("JSONP requests must use GET request method.");
|
|
}
|
|
this.request = req;
|
|
this.response = new EventEmitter();
|
|
this.readyState = ReadyStates.LOADING;
|
|
this._id = _dom.nextRequestID();
|
|
|
|
_dom.exposeConnection(this._id, this);
|
|
|
|
// Workaround Dart
|
|
// url = url.replace(/=JSONP_CALLBACK(&|$)/, `generated method`);
|
|
let callback = _dom.requestCallback(this._id);
|
|
let url: string = req.url;
|
|
if (url.indexOf('=JSONP_CALLBACK&') > -1) {
|
|
url = StringWrapper.replace(url, '=JSONP_CALLBACK&', `=${callback}&`);
|
|
} else if (url.lastIndexOf('=JSONP_CALLBACK') === url.length - '=JSONP_CALLBACK'.length) {
|
|
url = StringWrapper.substring(url, 0, url.length - '=JSONP_CALLBACK'.length) + `=${callback}`;
|
|
}
|
|
|
|
let script = this._script = _dom.build(url);
|
|
|
|
script.addEventListener('load', (event) => {
|
|
if (this.readyState === ReadyStates.CANCELLED) return;
|
|
this.readyState = ReadyStates.DONE;
|
|
_dom.cleanup(script);
|
|
if (!this._finished) {
|
|
ObservableWrapper.callThrow(
|
|
this.response, makeTypeError('JSONP injected script did not invoke callback.'));
|
|
return;
|
|
}
|
|
|
|
let responseOptions = new ResponseOptions({body: this._responseData});
|
|
if (isPresent(this.baseResponseOptions)) {
|
|
responseOptions = this.baseResponseOptions.merge(responseOptions);
|
|
}
|
|
|
|
ObservableWrapper.callNext(this.response, new Response(responseOptions));
|
|
});
|
|
|
|
script.addEventListener('error', (error) => {
|
|
if (this.readyState === ReadyStates.CANCELLED) return;
|
|
this.readyState = ReadyStates.DONE;
|
|
_dom.cleanup(script);
|
|
ObservableWrapper.callThrow(this.response, error);
|
|
});
|
|
|
|
_dom.send(script);
|
|
}
|
|
|
|
finished(data?: any) {
|
|
// Don't leak connections
|
|
this._finished = true;
|
|
this._dom.removeConnection(this._id);
|
|
if (this.readyState === ReadyStates.CANCELLED) return;
|
|
this._responseData = data;
|
|
}
|
|
|
|
dispose(): void {
|
|
this.readyState = ReadyStates.CANCELLED;
|
|
let script = this._script;
|
|
this._script = null;
|
|
if (isPresent(script)) {
|
|
this._dom.cleanup(script);
|
|
}
|
|
ObservableWrapper.callReturn(this.response);
|
|
}
|
|
}
|
|
|
|
@Injectable()
|
|
export class JSONPBackend implements ConnectionBackend {
|
|
constructor(private _browserJSONP: BrowserJsonp, private _baseResponseOptions: ResponseOptions) {}
|
|
createConnection(request: Request): JSONPConnection {
|
|
return new JSONPConnection(request, this._browserJSONP, this._baseResponseOptions);
|
|
}
|
|
}
|