Add an exponential backoff to rechecking the app list doodle.
[chromium-blink-merge.git] / third_party / polymer / components-chromium / core-ajax / core-ajax-extracted.js
blob3ffdb142afbd8a6f0036776f690811a5fc625cb7
3   Polymer('core-ajax', {
4     /**
5      * Fired when a response is received.
6      *
7      * @event core-response
8      */
10     /**
11      * Fired when an error is received.
12      *
13      * @event core-error
14      */
16     /**
17      * Fired whenever a response or an error is received.
18      *
19      * @event core-complete
20      */
22     /**
23      * The URL target of the request.
24      *
25      * @attribute url
26      * @type string
27      * @default ''
28      */
29     url: '',
31     /**
32      * Specifies what data to store in the `response` property, and
33      * to deliver as `event.response` in `response` events.
34      *
35      * One of:
36      *
37      *    `text`: uses `XHR.responseText`.
38      *
39      *    `xml`: uses `XHR.responseXML`.
40      *
41      *    `json`: uses `XHR.responseText` parsed as JSON.
42      *
43      *    `arraybuffer`: uses `XHR.response`.
44      *
45      *    `blob`: uses `XHR.response`.
46      *
47      *    `document`: uses `XHR.response`.
48      *
49      * @attribute handleAs
50      * @type string
51      * @default 'text'
52      */
53     handleAs: '',
55     /**
56      * If true, automatically performs an Ajax request when either `url` or `params` changes.
57      *
58      * @attribute auto
59      * @type boolean
60      * @default false
61      */
62     auto: false,
64     /**
65      * Parameters to send to the specified URL, as JSON.
66      *
67      * @attribute params
68      * @type string (JSON)
69      * @default ''
70      */
71     params: '',
73     /**
74      * The response for the current request, or null if it hasn't
75      * completed yet or the request resulted in error.
76      *
77      * @attribute response
78      * @type Object
79      * @default null
80      */
81     response: null,
83     /**
84      * The error for the current request, or null if it hasn't
85      * completed yet or the request resulted in success.
86      *
87      * @attribute error
88      * @type Object
89      * @default null
90      */
91     error: null,
93     /**
94      * Whether the current request is currently loading.
95      *
96      * @attribute loading
97      * @type boolean
98      * @default false
99      */
100     loading: false,
102     /**
103      * The progress of the current request.
104      *
105      * @attribute progress
106      * @type {loaded: number, total: number, lengthComputable: boolean}
107      * @default {}
108      */
109     progress: null,
111     /**
112      * The HTTP method to use such as 'GET', 'POST', 'PUT', or 'DELETE'.
113      * Default is 'GET'.
114      *
115      * @attribute method
116      * @type string
117      * @default ''
118      */
119     method: '',
121     /**
122      * HTTP request headers to send.
123      *
124      * Example:
125      *
126      *     <core-ajax
127      *         auto
128      *         url="http://somesite.com"
129      *         headers='{"X-Requested-With": "XMLHttpRequest"}'
130      *         handleAs="json"
131      *         on-core-response="{{handleResponse}}"></core-ajax>
132      *
133      * @attribute headers
134      * @type Object
135      * @default null
136      */
137     headers: null,
139     /**
140      * Optional raw body content to send when method === "POST".
141      *
142      * Example:
143      *
144      *     <core-ajax method="POST" auto url="http://somesite.com"
145      *         body='{"foo":1, "bar":2}'>
146      *     </core-ajax>
147      *
148      * @attribute body
149      * @type Object
150      * @default null
151      */
152     body: null,
154     /**
155      * Content type to use when sending data.
156      *
157      * @attribute contentType
158      * @type string
159      * @default 'application/x-www-form-urlencoded'
160      */
161     contentType: 'application/x-www-form-urlencoded',
163     /**
164      * Set the withCredentials flag on the request.
165      *
166      * @attribute withCredentials
167      * @type boolean
168      * @default false
169      */
170     withCredentials: false,
172     /**
173      * Additional properties to send to core-xhr.
174      *
175      * Can be set to an object containing default properties
176      * to send as arguments to the `core-xhr.request()` method
177      * which implements the low-level communication.
178      *
179      * @property xhrArgs
180      * @type Object
181      * @default null
182      */
183     xhrArgs: null,
185     created: function() {
186       this.progress = {};
187     },
189     ready: function() {
190       this.xhr = document.createElement('core-xhr');
191     },
193     receive: function(response, xhr) {
194       if (this.isSuccess(xhr)) {
195         this.processResponse(xhr);
196       } else {
197         this.processError(xhr);
198       }
199       this.complete(xhr);
200     },
202     isSuccess: function(xhr) {
203       var status = xhr.status || 0;
204       return !status || (status >= 200 && status < 300);
205     },
207     processResponse: function(xhr) {
208       var response = this.evalResponse(xhr);
209       if (xhr === this.activeRequest) {
210         this.response = response;
211       }
212       this.fire('core-response', {response: response, xhr: xhr});
213     },
215     processError: function(xhr) {
216       var response = xhr.status + ': ' + xhr.responseText;
217       if (xhr === this.activeRequest) {
218         this.error = response;
219       }
220       this.fire('core-error', {response: response, xhr: xhr});
221     },
223     processProgress: function(progress, xhr) {
224       if (xhr !== this.activeRequest) {
225         return;
226       }
227       // We create a proxy object here because these fields
228       // on the progress event are readonly properties, which
229       // causes problems in common use cases (e.g. binding to
230       // <paper-progress> attributes).
231       var progressProxy = {
232         lengthComputable: progress.lengthComputable,
233         loaded: progress.loaded,
234         total: progress.total
235       }
236       this.progress = progressProxy;
237     },
239     complete: function(xhr) {
240       if (xhr === this.activeRequest) {
241         this.loading = false;
242       }
243       this.fire('core-complete', {response: xhr.status, xhr: xhr});
244     },
246     evalResponse: function(xhr) {
247       return this[(this.handleAs || 'text') + 'Handler'](xhr);
248     },
250     xmlHandler: function(xhr) {
251       return xhr.responseXML;
252     },
254     textHandler: function(xhr) {
255       return xhr.responseText;
256     },
258     jsonHandler: function(xhr) {
259       var r = xhr.responseText;
260       try {
261         return JSON.parse(r);
262       } catch (x) {
263         console.warn('core-ajax caught an exception trying to parse response as JSON:');
264         console.warn('url:', this.url);
265         console.warn(x);
266         return r;
267       }
268     },
270     documentHandler: function(xhr) {
271       return xhr.response;
272     },
274     blobHandler: function(xhr) {
275       return xhr.response;
276     },
278     arraybufferHandler: function(xhr) {
279       return xhr.response;
280     },
282     urlChanged: function() {
283       if (!this.handleAs) {
284         var ext = String(this.url).split('.').pop();
285         switch (ext) {
286           case 'json':
287             this.handleAs = 'json';
288             break;
289         }
290       }
291       this.autoGo();
292     },
294     paramsChanged: function() {
295       this.autoGo();
296     },
298     bodyChanged: function() {
299       this.autoGo();
300     },
302     autoChanged: function() {
303       this.autoGo();
304     },
306     // TODO(sorvell): multiple side-effects could call autoGo
307     // during one micro-task, use a job to have only one action
308     // occur
309     autoGo: function() {
310       if (this.auto) {
311         this.goJob = this.job(this.goJob, this.go, 0);
312       }
313     },
315     /**
316      * Performs an Ajax request to the specified URL.
317      *
318      * @method go
319      */
320     go: function() {
321       var args = this.xhrArgs || {};
322       // TODO(sjmiles): we may want XHR to default to POST if body is set
323       args.body = this.body || args.body;
324       args.params = this.params || args.params;
325       if (args.params && typeof(args.params) == 'string') {
326         args.params = JSON.parse(args.params);
327       }
328       args.headers = this.headers || args.headers || {};
329       if (args.headers && typeof(args.headers) == 'string') {
330         args.headers = JSON.parse(args.headers);
331       }
332       var hasContentType = Object.keys(args.headers).some(function (header) {
333         return header.toLowerCase() === 'content-type';
334       });
335       // No Content-Type should be specified if sending `FormData`.  
336       // The UA must set the Content-Type w/ a calculated  multipart boundary ID.
337       if (args.body instanceof FormData) {
338         delete args.headers['Content-Type'];
339       } 
340       else if (!hasContentType && this.contentType) {
341         args.headers['Content-Type'] = this.contentType;
342       }
343       if (this.handleAs === 'arraybuffer' || this.handleAs === 'blob' ||
344           this.handleAs === 'document') {
345         args.responseType = this.handleAs;
346       }
347       args.withCredentials = this.withCredentials;
348       args.callback = this.receive.bind(this);
349       args.url = this.url;
350       args.method = this.method;
352       this.response = this.error = this.progress = null;
353       this.activeRequest = args.url && this.xhr.request(args);
354       if (this.activeRequest) {
355         this.loading = true;
356         var activeRequest = this.activeRequest;
357         // IE < 10 doesn't support progress events.
358         if ('onprogress' in activeRequest) {
359           this.activeRequest.addEventListener(
360               'progress',
361               function(progress) {
362                 this.processProgress(progress, activeRequest);
363               }.bind(this), false);
364         } else {
365           this.progress = {
366             lengthComputable: false,
367           }
368         }
369       }
370       return this.activeRequest;
371     }
373   });