OLD | NEW |
| (Empty) |
1 | |
2 Polymer({ | |
3 is: 'iron-request', | |
4 | |
5 properties: { | |
6 | |
7 /** | |
8 * A reference to the XMLHttpRequest instance used to generate the | |
9 * network request. | |
10 * | |
11 * @attribute xhr | |
12 * @type XMLHttpRequest | |
13 * @default `new XMLHttpRequest` | |
14 */ | |
15 xhr: { | |
16 type: Object, | |
17 notify: true, | |
18 readOnly: true, | |
19 value: function() { | |
20 return new XMLHttpRequest(); | |
21 } | |
22 }, | |
23 | |
24 /** | |
25 * A reference to the parsed response body, if the `xhr` has completely | |
26 * resolved. | |
27 * | |
28 * @attribute response | |
29 * @type Object | |
30 * @default null | |
31 */ | |
32 response: { | |
33 type: Object, | |
34 notify: true, | |
35 readOnly: true, | |
36 value: function() { | |
37 return null; | |
38 } | |
39 }, | |
40 | |
41 /** | |
42 * A promise that resolves when the `xhr` response comes back, or rejects | |
43 * if there is an error before the `xhr` completes. | |
44 * | |
45 * @attribute completes | |
46 * @type Promise | |
47 * @default `new Promise` | |
48 */ | |
49 completes: { | |
50 type: Object, | |
51 readOnly: true, | |
52 notify: true, | |
53 value: function() { | |
54 return new Promise(function (resolve, reject) { | |
55 this.resolveCompletes = resolve; | |
56 this.rejectCompletes = reject; | |
57 }.bind(this)); | |
58 } | |
59 }, | |
60 | |
61 /** | |
62 * An object that contains progress information emitted by the XHR if | |
63 * available. | |
64 * | |
65 * @attribute progress | |
66 * @type Object | |
67 * @default {} | |
68 */ | |
69 progress: { | |
70 type: Object, | |
71 notify: true, | |
72 readOnly: true, | |
73 value: function() { | |
74 return {}; | |
75 } | |
76 }, | |
77 | |
78 /** | |
79 * Aborted will be true if an abort of the request is attempted. | |
80 * | |
81 * @attribute aborted | |
82 * @type boolean | |
83 * @default false | |
84 */ | |
85 aborted: { | |
86 type: Boolean, | |
87 notify: true, | |
88 readOnly: true, | |
89 value: false, | |
90 } | |
91 }, | |
92 | |
93 /** | |
94 * Succeeded is true if the request succeeded. The request succeeded if the | |
95 * status code is greater-than-or-equal-to 200, and less-than 300. Also, | |
96 * the status code 0 is accepted as a success even though the outcome may | |
97 * be ambiguous. | |
98 * | |
99 * @return boolean | |
100 */ | |
101 get succeeded() { | |
102 var status = this.xhr.status || 0; | |
103 | |
104 // Note: if we are using the file:// protocol, the status code will be 0 | |
105 // for all outcomes (successful or otherwise). | |
106 return status === 0 || | |
107 (status >= 200 && status < 300); | |
108 }, | |
109 | |
110 /** | |
111 * Sends an HTTP request to the server and returns the XHR object. | |
112 * | |
113 * @method request | |
114 * @param {{ | |
115 * url: string, | |
116 * method: (string|undefined), | |
117 * async: (boolean|undefined), | |
118 * body: (ArrayBuffer|ArrayBufferView|Blob|Document|FormData|null|string|u
ndefined), | |
119 * headers: (Object|undefined), | |
120 * handleAs: (string|undefined), | |
121 * withCredentials: (boolean|undefined)}} options - | |
122 * url The url to which the request is sent. | |
123 * method The HTTP method to use, default is GET. | |
124 * async By default, all requests are sent asynchronously. To send synch
ronous requests, | |
125 * set to true. | |
126 * body The content for the request body for POST method. | |
127 * headers HTTP request headers. | |
128 * handleAs The response type. Default is 'text'. | |
129 * withCredentials Whether or not to send credentials on the request. De
fault is false. | |
130 * @return Promise | |
131 */ | |
132 send: function (options) { | |
133 var xhr = this.xhr; | |
134 | |
135 if (xhr.readyState > 0) { | |
136 return; | |
137 } | |
138 | |
139 xhr.addEventListener('readystatechange', function () { | |
140 if (xhr.readyState === 4 && !this.aborted) { | |
141 | |
142 if (!this.succeeded) { | |
143 this.rejectCompletes(new Error('The request failed with status code:
' + this.xhr.status)); | |
144 return; | |
145 } | |
146 | |
147 this._setResponse(this.parseResponse()); | |
148 this.resolveCompletes(this); | |
149 } | |
150 }.bind(this)); | |
151 | |
152 xhr.addEventListener('progress', function (progress) { | |
153 this._setProgress({ | |
154 lengthComputable: progress.lengthComputable, | |
155 loaded: progress.loaded, | |
156 total: progress.total | |
157 }); | |
158 }.bind(this)) | |
159 | |
160 xhr.addEventListener('error', function (error) { | |
161 this.rejectCompletes(error); | |
162 }.bind(this)); | |
163 | |
164 xhr.addEventListener('abort', function () { | |
165 this.rejectCompletes(new Error('Request aborted.')); | |
166 }.bind(this)); | |
167 | |
168 xhr.open( | |
169 options.method || 'GET', | |
170 options.url, | |
171 options.async !== false | |
172 ); | |
173 | |
174 if (options.headers) { | |
175 Object.keys(options.headers).forEach(function (requestHeader) { | |
176 xhr.setRequestHeader( | |
177 requestHeader, | |
178 options.headers[requestHeader] | |
179 ); | |
180 }, this); | |
181 } | |
182 | |
183 // In IE, `xhr.responseType` is an empty string when the response | |
184 // returns. Hence, caching it as `xhr._responseType`. | |
185 xhr.responseType = xhr._responseType = (options.handleAs || 'text'); | |
186 xhr.withCredentials = !!options.withCredentials; | |
187 | |
188 xhr.send(options.body); | |
189 | |
190 return this.completes; | |
191 }, | |
192 | |
193 parseResponse: function () { | |
194 var xhr = this.xhr; | |
195 var responseType = this.xhr.responseType || | |
196 this.xhr._responseType; | |
197 // If we don't have a natural `xhr.responseType`, we prefer parsing | |
198 // `xhr.responseText` over returning `xhr.response`.. | |
199 var preferResponseText = !this.xhr.responseType; | |
200 | |
201 try { | |
202 switch (responseType) { | |
203 case 'json': | |
204 // If xhr.response is undefined, responseType `json` may | |
205 // not be supported. | |
206 if (preferResponseText || xhr.response === undefined) { | |
207 // If accessing `xhr.responseText` throws, responseType `json` | |
208 // is supported and the result is rightly `undefined`. | |
209 try { | |
210 xhr.responseText; | |
211 } catch (e) { | |
212 return xhr.response; | |
213 } | |
214 | |
215 // Otherwise, attempt to parse `xhr.responseText` as JSON. | |
216 if (xhr.responseText) { | |
217 return JSON.parse(xhr.responseText); | |
218 } | |
219 } | |
220 | |
221 return xhr.response; | |
222 case 'xml': | |
223 return xhr.responseXML; | |
224 case 'blob': | |
225 case 'document': | |
226 case 'arraybuffer': | |
227 return xhr.response; | |
228 case 'text': | |
229 default: | |
230 return xhr.responseText; | |
231 } | |
232 } catch (e) { | |
233 this.rejectCompletes(new Error('Could not parse response. ' + e.message)
); | |
234 } | |
235 }, | |
236 | |
237 abort: function () { | |
238 this._setAborted(true); | |
239 this.xhr.abort(); | |
240 } | |
241 }); | |
OLD | NEW |