59
modules/angular2/src/http/backends/browser_jsonp.dart
Normal file
59
modules/angular2/src/http/backends/browser_jsonp.dart
Normal file
@ -0,0 +1,59 @@
|
||||
library angular2.src.http.backends.browser_jsonp;
|
||||
import 'package:angular2/di.dart';
|
||||
import 'dart:html' show document;
|
||||
import 'dart:js' show context, JsObject, JsArray;
|
||||
|
||||
int _nextRequestId = 0;
|
||||
const JSONP_HOME = '__ng_jsonp__';
|
||||
|
||||
var _jsonpConnections = null;
|
||||
|
||||
JsObject _getJsonpConnections() {
|
||||
if (_jsonpConnections == null) {
|
||||
_jsonpConnections = context[JSONP_HOME] = new JsObject(context['Object']);
|
||||
}
|
||||
return _jsonpConnections;
|
||||
}
|
||||
|
||||
// Make sure not to evaluate this in a non-browser environment!
|
||||
@Injectable()
|
||||
class BrowserJsonp {
|
||||
// Construct a <script> element with the specified URL
|
||||
dynamic build(String url) {
|
||||
var node = document.createElement('script');
|
||||
node.src = url;
|
||||
return node;
|
||||
}
|
||||
|
||||
nextRequestID() {
|
||||
return "__req${_nextRequestId++}";
|
||||
}
|
||||
|
||||
requestCallback(String id) {
|
||||
return """${JSONP_HOME}.${id}.finished""";
|
||||
}
|
||||
|
||||
exposeConnection(String id, dynamic connection) {
|
||||
var connections = _getJsonpConnections();
|
||||
var wrapper = new JsObject(context['Object']);
|
||||
|
||||
wrapper['_id'] = id;
|
||||
wrapper['__dart__'] = connection;
|
||||
wrapper['finished'] = ([dynamic data]) => connection.finished(data);
|
||||
|
||||
connections[id] = wrapper;
|
||||
}
|
||||
|
||||
removeConnection(String id) {
|
||||
var connections = _getJsonpConnections();
|
||||
connections[id] = null;
|
||||
}
|
||||
|
||||
// Attach the <script> element to the DOM
|
||||
send(dynamic node) { document.body.append(node); }
|
||||
|
||||
// Remove <script> element from the DOM
|
||||
cleanup(dynamic node) {
|
||||
node.remove();
|
||||
}
|
||||
}
|
48
modules/angular2/src/http/backends/browser_jsonp.ts
Normal file
48
modules/angular2/src/http/backends/browser_jsonp.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import {Injectable} from 'angular2/di';
|
||||
import {global} from 'angular2/src/facade/lang';
|
||||
|
||||
let _nextRequestId = 0;
|
||||
export const JSONP_HOME = '__ng_jsonp__';
|
||||
var _jsonpConnections = null;
|
||||
|
||||
function _getJsonpConnections(): {[key: string]: any} {
|
||||
if (_jsonpConnections === null) {
|
||||
_jsonpConnections = global[JSONP_HOME] = {};
|
||||
}
|
||||
return _jsonpConnections;
|
||||
}
|
||||
|
||||
// Make sure not to evaluate this in a non-browser environment!
|
||||
@Injectable()
|
||||
export class BrowserJsonp {
|
||||
// Construct a <script> element with the specified URL
|
||||
build(url: string): any {
|
||||
let node = document.createElement('script');
|
||||
node.src = url;
|
||||
return node;
|
||||
}
|
||||
|
||||
nextRequestID(): string { return `__req${_nextRequestId++}`; }
|
||||
|
||||
requestCallback(id: string): string { return `${JSONP_HOME}.${id}.finished`; }
|
||||
|
||||
exposeConnection(id: string, connection: any) {
|
||||
let connections = _getJsonpConnections();
|
||||
connections[id] = connection;
|
||||
}
|
||||
|
||||
removeConnection(id: string) {
|
||||
var connections = _getJsonpConnections();
|
||||
connections[id] = null;
|
||||
}
|
||||
|
||||
// Attach the <script> element to the DOM
|
||||
send(node: any) { document.body.appendChild(<Node>(node)); }
|
||||
|
||||
// Remove <script> element from the DOM
|
||||
cleanup(node: any) {
|
||||
if (node.parentNode) {
|
||||
node.parentNode.removeChild(<Node>(node));
|
||||
}
|
||||
}
|
||||
}
|
97
modules/angular2/src/http/backends/jsonp_backend.ts
Normal file
97
modules/angular2/src/http/backends/jsonp_backend.ts
Normal file
@ -0,0 +1,97 @@
|
||||
import {ConnectionBackend, Connection} from '../interfaces';
|
||||
import {ReadyStates, RequestMethods, RequestMethodsMap} 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/facade/async';
|
||||
import {StringWrapper, isPresent, ENUM_INDEX, makeTypeError} from 'angular2/src/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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user