///
import h = require('./Headers');
import utils = require('../Utils');
import log = require('../Log');
import context = require('../Context');
import ajaxObserver = require('../AjaxObserver');
import r = require('./Response');
/**
* TODO @see https://github.com/github/fetch/blob/master/fetch.js
*/
export class Request extends h.Headers {
public async:boolean;
public method:string;
public url:string;
public query:any;
public body:any;
public xhr:XMLHttpRequest;
private observer:ajaxObserver.AjaxObserver;
constructor(context:context.Context) {
super(context);
this.async = true;
this.method = '';
this.url = '';
this.query = null;
this.body = {};
this.context = context;
this.xhr = null;
this.observer = ajaxObserver.$get(context);
}
isLoaded():boolean {
return !!this.xhr;
}
setOptions(options?:IAjaxOptions):Request {
options = options || {};
// backwards compatibility
if (!('body' in options) && options.post) options.body = options.post;
if (!('query' in options) && options.get) options.query = options.get;
if ('method' in options) this.method = options.method;
if ('url' in options) this.url = options.url;
if ('query' in options) this.query = options.query;
if ('body' in options) this.body = options.body;
if ('headers' in options) this.setHeaders(options.headers);
if ('async' in options) this.async = !!options.async;
return this;
}
/**
* Checks the send options, defaulting various of the options,
* and consuming / transforming some of the options (like get).
*/
checkOptions() {
if (!this.url) throw new Error('Url is not defined');
if (!this.hasHeader('Accept')) this.setHeader('Accept', h.Headers.jsonContentType);
if (!this.hasHeader('Content-Type')) this.setHeader('Content-Type', h.Headers.jsonContentType);
this.method = this.method ? this.method.toUpperCase() : 'GET';
if (['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD'].indexOf(this.method) < 0) throw new Error('Method has wrong value');
return this;
}
getEncodedBody() {
if (this.method === 'GET') return null;
if (typeof this.body === 'string') {
return this.body;
} else if (this.isJson()) {
return JSON.stringify(this.body);
} else if (this.isUrlEncoded()) {
return this.utils.queryStringify(this.body);
} else {
return this.body;
}
}
send():Promise {
this.observer.emit(this.observer.events.beforeRequest, this);
var responsePromise = new (this.context.getPromise())((resolve, reject) => {
this.checkOptions();
var xhr = this.getXHR(),
url = this.url + (!!this.query ? ((this.url.indexOf('?') > -1 ? '&' : '?') + this.utils.queryStringify(this.query)) : '');
xhr.open(this.method, url, this.async);
//@see http://stackoverflow.com/questions/19666809/cors-withcredentials-support-limited
xhr.withCredentials = true;
xhr.onload = () => {
//TODO http://jira.ringcentral.com/browse/PLA-10585
var response = r.$get(this.context, xhr.status, xhr.statusText, xhr.responseText, xhr.getAllResponseHeaders());
if (response.error) {
var e = response.error;
e.ajax = response; // backwards compatibility
e.response = response; //FIXME Circular
e.request = this;
reject(e);
} else {
resolve(response);
}
};
xhr.onerror = (event) => { // CORS or network issue
var e = new Error('The request cannot be sent' + (event ? ' (' + event.toString() + ')' : ''));
e.request = this;
e.response = null;
e.ajax = null; // backwards compatibility
reject(e);
};
this.utils.forEach(this.headers, (value, header) => {
if (!!value) xhr.setRequestHeader(header, value);
});
xhr.send(this.getEncodedBody());
this.xhr = xhr;
});
return responsePromise.then((response:r.Response) => {
this.observer.emit(this.observer.events.requestSuccess, response, this);
return response;
}).catch((e):any => { //TODO Replace any with something
this.observer.emit(this.observer.events.requestError, e);
throw e;
});
}
getXHR():XMLHttpRequest {
return this.context.getXHR();
}
destroy() {
if (this.xhr) this.xhr.abort();
}
}
export function $get(context:context.Context):Request {
return new Request(context);
}
export interface IAjaxError extends Error {
ajax?:r.Response;
response?:r.Response;
request?:Request;
}
export interface IAjaxOptions {
url?:string;
method?:string;
async?:boolean;
query?:any;
body?:any;
headers?:h.IHeadersObject;
post?:any; // @deprecated
get?:any; // @deprecated
}