-
Notifications
You must be signed in to change notification settings - Fork 155
/
Copy pathajax.ts
236 lines (224 loc) · 7.65 KB
/
ajax.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
import { isNullOrUndefined, merge } from './util';
const headerRegex: RegExp = /^(.*?):[ \t]*([^\r\n]*)$/gm;
const defaultType: string = 'GET';
/**
* Ajax class provides ability to make asynchronous HTTP request to the server
* ```typescript
* var ajax = new Ajax("index.html", "GET", true);
* ajax.send().then(
* function (value) {
* console.log(value);
* },
* function (reason) {
* console.log(reason);
* });
* ```
*/
export class Ajax {
/**
* Specifies the URL to which request to be sent.
*
* @default null
*/
public url: string;
/**
* Specifies which HTTP request method to be used. For ex., GET, POST
*
* @default GET
*/
public type: string;
/**
* Specifies the data to be sent.
*
* @default null
*/
public data: string | Object;
/**
* A boolean value indicating whether the request should be sent asynchronous or not.
*
* @default true
*/
public mode: boolean = true;
/**
* Specifies the callback for creating the XMLHttpRequest object.
*
* @default null
*/
public httpRequest: XMLHttpRequest;
/**
* A boolean value indicating whether to ignore the promise reject.
*
* @private
* @default true
*/
public emitError: boolean = true;
private options: Object = {};
public onLoad: (this: XMLHttpRequest, ev: Event) => Object;
public onProgress: (this: XMLHttpRequest, ev: Event) => Object;
public onError: (this: XMLHttpRequest, ev: Event) => Object;
public onAbort: (this: XMLHttpRequest, ev: Event) => Object;
public onUploadProgress: (this: XMLHttpRequest, ev: Event) => Object;
private contentType: string;
private dataType: string;
/**
* Constructor for Ajax class
*
* @param {string|Object} options ?
* @param {string} type ?
* @param {boolean} async ?
* @returns defaultType any
*/
constructor(options?: string | Object, type?: string, async?: boolean, contentType?: string) {
if (typeof options === 'string') {
this.url = options;
this.type = type ? type.toUpperCase() : defaultType;
this.mode = !isNullOrUndefined(async) ? async : true;
} else if (typeof options === 'object') {
this.options = options;
merge(this, this.options);
}
this.type = this.type ? this.type.toUpperCase() : defaultType;
this.contentType = (this.contentType !== undefined) ? this.contentType : contentType;
}
/**
*
* Send the request to server.
*
* @param {any} data - To send the user data
* @returns {Promise} ?
*/
public send(data?: string | Object): Promise<Ajax> {
this.data = isNullOrUndefined(data) ? this.data : data;
const eventArgs: BeforeSendEventArgs = {
cancel: false,
httpRequest: null
};
const promise: Promise<Ajax> = new Promise((resolve: Function, reject: Function) => {
this.httpRequest = new XMLHttpRequest();
this.httpRequest.onreadystatechange = () => { this.stateChange(resolve, reject); };
if (!isNullOrUndefined(this.onLoad)) {
this.httpRequest.onload = this.onLoad;
}
if (!isNullOrUndefined(this.onProgress)) {
this.httpRequest.onprogress = this.onProgress;
}
/* istanbul ignore next */
if (!isNullOrUndefined(this.onAbort)) {
this.httpRequest.onabort = this.onAbort;
}
/* istanbul ignore next */
if (!isNullOrUndefined(this.onError)) {
this.httpRequest.onerror = this.onError;
}
//** Upload Events **/
/* istanbul ignore next */
if (!isNullOrUndefined(this.onUploadProgress)) {
this.httpRequest.upload.onprogress = this.onUploadProgress;
}
this.httpRequest.open(this.type, this.url, this.mode);
// Set default headers
if (!isNullOrUndefined(this.data) && this.contentType !== null) {
this.httpRequest.setRequestHeader('Content-Type', this.contentType || 'application/json; charset=utf-8');
}
if (this.beforeSend) {
eventArgs.httpRequest = this.httpRequest;
this.beforeSend(eventArgs);
}
if (!eventArgs.cancel) {
this.httpRequest.send(!isNullOrUndefined(this.data) ? this.data as Document : null);
}
});
return promise;
}
/**
* Specifies the callback function to be triggered before sending request to sever.
* This can be used to modify the XMLHttpRequest object before it is sent.
*
* @event beforeSend
*/
public beforeSend: Function;
/**
* Specifies callback function to be triggered after XmlHttpRequest is succeeded.
* The callback will contain server response as the parameter.
*
* @event onSuccess
*/
public onSuccess: Function;
/**
* Triggers when XmlHttpRequest is failed.
*
* @event onFailure
*/
public onFailure: Function;
private successHandler(data: string): string {
if (this.onSuccess) {
this.onSuccess(data, this);
}
return data;
}
private failureHandler(reason: string): string {
if (this.onFailure) {
this.onFailure(this.httpRequest);
}
return reason;
}
private stateChange(resolve: Function, reject: Function): void {
let data: string = this.httpRequest.responseText;
if (this.dataType && this.dataType.toLowerCase() === 'json') {
if (data === '') {
data = undefined;
} else {
try {
data = JSON.parse(data);
} catch (error) {
// no exception handle
}
}
}
if (this.httpRequest.readyState === 4) {
//success range should be 200 to 299
if ((this.httpRequest.status >= 200 && this.httpRequest.status <= 299) || this.httpRequest.status === 304) {
resolve(this.successHandler(data));
} else {
if (this.emitError) {
reject(new Error(this.failureHandler(this.httpRequest.statusText)));
} else {
resolve();
}
}
}
}
/**
* To get the response header from XMLHttpRequest
*
* @param {string} key Key to search in the response header
* @returns {string} ?
*/
public getResponseHeader(key: string): string {
const responseHeaders: { [key: string]: string } = {};
let headers: string[] = headerRegex.exec(this.httpRequest.getAllResponseHeaders());
while (headers) {
responseHeaders[headers[1].toLowerCase()] = headers[2];
headers = headerRegex.exec(this.httpRequest.getAllResponseHeaders());
}
const header: string = responseHeaders[key.toLowerCase()];
return isNullOrUndefined(header) ? null : header;
}
}
export interface HeaderOptions {
readyState?: number;
getResponseHeader?: Function;
setRequestHeader?: Function;
overrideMimeType?: Function;
}
/**
* Specifies the ajax beforeSend event arguments
*
* @event BeforeSendEventArgs
*/
export interface BeforeSendEventArgs {
/** To cancel the ajax request in beforeSend */
cancel?: boolean;
/** Returns the request sent from the client end */
httpRequest?: XMLHttpRequest;
}