Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(206)

Side by Side Diff: third_party/polymer/components/iron-ajax/iron-request.html

Issue 2906483004: [pinpoint] Add iron-form and paper-checkbox to polymer components. (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 <!--
2 @license
3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
4 This code may only be used under the BSD style license found at http://polymer.g ithub.io/LICENSE.txt
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6 The complete set of contributors may be found at http://polymer.github.io/CONTRI BUTORS.txt
7 Code distributed by Google as part of the polymer project is also
8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN TS.txt
9 -->
10
11 <link rel="import" href="../polymer/polymer.html">
12 <link rel="import" href="../promise-polyfill/promise-polyfill-lite.html">
13
14 <!--
15 iron-request can be used to perform XMLHttpRequests.
16
17 <iron-request id="xhr"></iron-request>
18 ...
19 this.$.xhr.send({url: url, body: params});
20 -->
21 <script>
22 'use strict';
23
24 Polymer({
25 is: 'iron-request',
26
27 hostAttributes: {
28 hidden: true
29 },
30
31 properties: {
32
33 /**
34 * A reference to the XMLHttpRequest instance used to generate the
35 * network request.
36 *
37 * @type {XMLHttpRequest}
38 */
39 xhr: {
40 type: Object,
41 notify: true,
42 readOnly: true,
43 value: function() {
44 return new XMLHttpRequest();
45 }
46 },
47
48 /**
49 * A reference to the parsed response body, if the `xhr` has completely
50 * resolved.
51 *
52 * @type {*}
53 * @default null
54 */
55 response: {
56 type: Object,
57 notify: true,
58 readOnly: true,
59 value: function() {
60 return null;
61 }
62 },
63
64 /**
65 * A reference to the status code, if the `xhr` has completely resolved.
66 */
67 status: {
68 type: Number,
69 notify: true,
70 readOnly: true,
71 value: 0
72 },
73
74 /**
75 * A reference to the status text, if the `xhr` has completely resolved.
76 */
77 statusText: {
78 type: String,
79 notify: true,
80 readOnly: true,
81 value: ''
82 },
83
84 /**
85 * A promise that resolves when the `xhr` response comes back, or rejects
86 * if there is an error before the `xhr` completes.
87 *
88 * @type {Promise}
89 */
90 completes: {
91 type: Object,
92 readOnly: true,
93 notify: true,
94 value: function() {
95 return new Promise(function (resolve, reject) {
96 this.resolveCompletes = resolve;
97 this.rejectCompletes = reject;
98 }.bind(this));
99 }
100 },
101
102 /**
103 * An object that contains progress information emitted by the XHR if
104 * available.
105 *
106 * @default {}
107 */
108 progress: {
109 type: Object,
110 notify: true,
111 readOnly: true,
112 value: function() {
113 return {};
114 }
115 },
116
117 /**
118 * Aborted will be true if an abort of the request is attempted.
119 */
120 aborted: {
121 type: Boolean,
122 notify: true,
123 readOnly: true,
124 value: false,
125 },
126
127 /**
128 * Errored will be true if the browser fired an error event from the
129 * XHR object (mainly network errors).
130 */
131 errored: {
132 type: Boolean,
133 notify: true,
134 readOnly: true,
135 value: false
136 },
137
138 /**
139 * TimedOut will be true if the XHR threw a timeout event.
140 */
141 timedOut: {
142 type: Boolean,
143 notify: true,
144 readOnly: true,
145 value: false
146 }
147 },
148
149 /**
150 * Succeeded is true if the request succeeded. The request succeeded if it
151 * loaded without error, wasn't aborted, and the status code is ≥ 200, and
152 * < 300, or if the status code is 0.
153 *
154 * The status code 0 is accepted as a success because some schemes - e.g.
155 * file:// - don't provide status codes.
156 *
157 * @return {boolean}
158 */
159 get succeeded() {
160 if (this.errored || this.aborted || this.timedOut) {
161 return false;
162 }
163 var status = this.xhr.status || 0;
164
165 // Note: if we are using the file:// protocol, the status code will be 0
166 // for all outcomes (successful or otherwise).
167 return status === 0 ||
168 (status >= 200 && status < 300);
169 },
170
171 /**
172 * Sends an HTTP request to the server and returns the XHR object.
173 *
174 * The handling of the `body` parameter will vary based on the Content-Type
175 * header. See the docs for iron-ajax's `body` param for details.
176 *
177 * @param {{
178 * url: string,
179 * method: (string|undefined),
180 * async: (boolean|undefined),
181 * body: (ArrayBuffer|ArrayBufferView|Blob|Document|FormData|null|string|u ndefined|Object),
182 * headers: (Object|undefined),
183 * handleAs: (string|undefined),
184 * jsonPrefix: (string|undefined),
185 * withCredentials: (boolean|undefined)}} options -
186 * url The url to which the request is sent.
187 * method The HTTP method to use, default is GET.
188 * async By default, all requests are sent asynchronously. To send synch ronous requests,
189 * set to false.
190 * body The content for the request body for POST method.
191 * headers HTTP request headers.
192 * handleAs The response type. Default is 'text'.
193 * withCredentials Whether or not to send credentials on the request. De fault is false.
194 * timeout: (Number|undefined)
195 * @return {Promise}
196 */
197 send: function (options) {
198 var xhr = this.xhr;
199
200 if (xhr.readyState > 0) {
201 return null;
202 }
203
204 xhr.addEventListener('progress', function (progress) {
205 this._setProgress({
206 lengthComputable: progress.lengthComputable,
207 loaded: progress.loaded,
208 total: progress.total
209 });
210 }.bind(this))
211
212 xhr.addEventListener('error', function (error) {
213 this._setErrored(true);
214 this._updateStatus();
215 this.rejectCompletes(error);
216 }.bind(this));
217
218 xhr.addEventListener('timeout', function (error) {
219 this._setTimedOut(true);
220 this._updateStatus();
221 this.rejectCompletes(error);
222 }.bind(this));
223
224 xhr.addEventListener('abort', function () {
225 this._updateStatus();
226 this.rejectCompletes(new Error('Request aborted.'));
227 }.bind(this));
228
229 // Called after all of the above.
230 xhr.addEventListener('loadend', function () {
231 this._updateStatus();
232 this._setResponse(this.parseResponse());
233
234 if (!this.succeeded) {
235 this.rejectCompletes(new Error('The request failed with status code: ' + this.xhr.status));
236 return;
237 }
238
239 this.resolveCompletes(this);
240 }.bind(this));
241
242 this.url = options.url;
243 xhr.open(
244 options.method || 'GET',
245 options.url,
246 options.async !== false
247 );
248
249 var acceptType = {
250 'json': 'application/json',
251 'text': 'text/plain',
252 'html': 'text/html',
253 'xml': 'application/xml',
254 'arraybuffer': 'application/octet-stream'
255 }[options.handleAs];
256 var headers = options.headers || Object.create(null);
257 var newHeaders = Object.create(null);
258 for (var key in headers) {
259 newHeaders[key.toLowerCase()] = headers[key];
260 }
261 headers = newHeaders;
262
263 if (acceptType && !headers['accept']) {
264 headers['accept'] = acceptType;
265 }
266 Object.keys(headers).forEach(function (requestHeader) {
267 if (/[A-Z]/.test(requestHeader)) {
268 Polymer.Base._error('Headers must be lower case, got', requestHeader);
269 }
270 xhr.setRequestHeader(
271 requestHeader,
272 headers[requestHeader]
273 );
274 }, this);
275
276 if (options.async !== false) {
277 if (options.async) {
278 xhr.timeout = options.timeout;
279 }
280
281 var handleAs = options.handleAs;
282
283 // If a JSON prefix is present, the responseType must be 'text' or the
284 // browser won’t be able to parse the response.
285 if (!!options.jsonPrefix || !handleAs) {
286 handleAs = 'text';
287 }
288
289 // In IE, `xhr.responseType` is an empty string when the response
290 // returns. Hence, caching it as `xhr._responseType`.
291 xhr.responseType = xhr._responseType = handleAs;
292
293 // Cache the JSON prefix, if it exists.
294 if (!!options.jsonPrefix) {
295 xhr._jsonPrefix = options.jsonPrefix;
296 }
297 }
298
299 xhr.withCredentials = !!options.withCredentials;
300
301
302 var body = this._encodeBodyObject(options.body, headers['content-type']);
303
304 xhr.send(
305 /** @type {ArrayBuffer|ArrayBufferView|Blob|Document|FormData|
306 null|string|undefined} */
307 (body));
308
309 return this.completes;
310 },
311
312 /**
313 * Attempts to parse the response body of the XHR. If parsing succeeds,
314 * the value returned will be deserialized based on the `responseType`
315 * set on the XHR.
316 *
317 * @return {*} The parsed response,
318 * or undefined if there was an empty response or parsing failed.
319 */
320 parseResponse: function () {
321 var xhr = this.xhr;
322 var responseType = xhr.responseType || xhr._responseType;
323 var preferResponseText = !this.xhr.responseType;
324 var prefixLen = (xhr._jsonPrefix && xhr._jsonPrefix.length) || 0;
325
326 try {
327 switch (responseType) {
328 case 'json':
329 // If the xhr object doesn't have a natural `xhr.responseType`,
330 // we can assume that the browser hasn't parsed the response for us,
331 // and so parsing is our responsibility. Likewise if response is
332 // undefined, as there's no way to encode undefined in JSON.
333 if (preferResponseText || xhr.response === undefined) {
334 // Try to emulate the JSON section of the response body section of
335 // the spec: https://xhr.spec.whatwg.org/#response-body
336 // That is to say, we try to parse as JSON, but if anything goes
337 // wrong return null.
338 try {
339 return JSON.parse(xhr.responseText);
340 } catch (_) {
341 return null;
342 }
343 }
344
345 return xhr.response;
346 case 'xml':
347 return xhr.responseXML;
348 case 'blob':
349 case 'document':
350 case 'arraybuffer':
351 return xhr.response;
352 case 'text':
353 default: {
354 // If `prefixLen` is set, it implies the response should be parsed
355 // as JSON once the prefix of length `prefixLen` is stripped from
356 // it. Emulate the behavior above where null is returned on failure
357 // to parse.
358 if (prefixLen) {
359 try {
360 return JSON.parse(xhr.responseText.substring(prefixLen));
361 } catch (_) {
362 return null;
363 }
364 }
365 return xhr.responseText;
366 }
367 }
368 } catch (e) {
369 this.rejectCompletes(new Error('Could not parse response. ' + e.message) );
370 }
371 },
372
373 /**
374 * Aborts the request.
375 */
376 abort: function () {
377 this._setAborted(true);
378 this.xhr.abort();
379 },
380
381 /**
382 * @param {*} body The given body of the request to try and encode.
383 * @param {?string} contentType The given content type, to infer an encoding
384 * from.
385 * @return {*} Either the encoded body as a string, if successful,
386 * or the unaltered body object if no encoding could be inferred.
387 */
388 _encodeBodyObject: function(body, contentType) {
389 if (typeof body == 'string') {
390 return body; // Already encoded.
391 }
392 var bodyObj = /** @type {Object} */ (body);
393 switch(contentType) {
394 case('application/json'):
395 return JSON.stringify(bodyObj);
396 case('application/x-www-form-urlencoded'):
397 return this._wwwFormUrlEncode(bodyObj);
398 }
399 return body;
400 },
401
402 /**
403 * @param {Object} object The object to encode as x-www-form-urlencoded.
404 * @return {string} .
405 */
406 _wwwFormUrlEncode: function(object) {
407 if (!object) {
408 return '';
409 }
410 var pieces = [];
411 Object.keys(object).forEach(function(key) {
412 // TODO(rictic): handle array values here, in a consistent way with
413 // iron-ajax params.
414 pieces.push(
415 this._wwwFormUrlEncodePiece(key) + '=' +
416 this._wwwFormUrlEncodePiece(object[key]));
417 }, this);
418 return pieces.join('&');
419 },
420
421 /**
422 * @param {*} str A key or value to encode as x-www-form-urlencoded.
423 * @return {string} .
424 */
425 _wwwFormUrlEncodePiece: function(str) {
426 // Spec says to normalize newlines to \r\n and replace %20 spaces with +.
427 // jQuery does this as well, so this is likely to be widely compatible.
428 if (str === null) {
429 return '';
430 }
431 return encodeURIComponent(str.toString().replace(/\r?\n/g, '\r\n'))
432 .replace(/%20/g, '+');
433 },
434
435 /**
436 * Updates the status code and status text.
437 */
438 _updateStatus: function() {
439 this._setStatus(this.xhr.status);
440 this._setStatusText((this.xhr.statusText === undefined) ? '' : this.xhr.st atusText);
441 }
442 });
443 </script>
OLDNEW
« no previous file with comments | « third_party/polymer/components/iron-ajax/iron-ajax.html ('k') | third_party/polymer/components/iron-ajax/test/index.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698