UNPKG

five-bells-visualization

Version:
435 lines (384 loc) 11.1 kB
<!-- Copyright (c) 2014 The Polymer Project Authors. All rights reserved. This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as part of the polymer project is also subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt --> <!-- @group Polymer Core Elements The `core-ajax` element exposes `XMLHttpRequest` functionality. <core-ajax auto url="http://gdata.youtube.com/feeds/api/videos/" params='{"alt":"json", "q":"chrome"}' handleAs="json" on-core-response="{{handleResponse}}"></core-ajax> With `auto` set to `true`, the element performs a request whenever its `url`, `params` or `body` properties are changed. Note: The `params` attribute must be double quoted JSON. You can trigger a request explicitly by calling `go` on the element. @element core-ajax @status beta @homepage github.io --> <link rel="import" href="core-xhr.html"> <polymer-element name="core-ajax" hidden attributes="url handleAs auto params response error method headers body contentType withCredentials progress loading"> <script> Polymer('core-ajax', { /** * Fired when a response is received. * * @event core-response */ /** * Fired when an error is received. * * @event core-error */ /** * Fired whenever a response or an error is received. * * @event core-complete */ /** * The URL target of the request. * * @attribute url * @type string * @default '' */ url: '', /** * Specifies what data to store in the `response` property, and * to deliver as `event.response` in `response` events. * * One of: * * `text`: uses `XHR.responseText`. * * `xml`: uses `XHR.responseXML`. * * `json`: uses `XHR.responseText` parsed as JSON. * * `arraybuffer`: uses `XHR.response`. * * `blob`: uses `XHR.response`. * * `document`: uses `XHR.response`. * * @attribute handleAs * @type string * @default 'text' */ handleAs: '', /** * If true, automatically performs an Ajax request when either `url` or `params` changes. * * @attribute auto * @type boolean * @default false */ auto: false, /** * Parameters to send to the specified URL, as JSON. * * @attribute params * @type string * @default '' */ params: '', /** * The response for the current request, or null if it hasn't * completed yet or the request resulted in error. * * @attribute response * @type Object * @default null */ response: null, /** * The error for the current request, or null if it hasn't * completed yet or the request resulted in success. * * @attribute error * @type Object * @default null */ error: null, /** * Whether the current request is currently loading. * * @attribute loading * @type boolean * @default false */ loading: false, /** * The progress of the current request. * * @attribute progress * @type {loaded: number, total: number, lengthComputable: boolean} * @default {} */ progress: null, /** * The HTTP method to use such as 'GET', 'POST', 'PUT', or 'DELETE'. * Default is 'GET'. * * @attribute method * @type string * @default '' */ method: '', /** * HTTP request headers to send. * * Example: * * <core-ajax * auto * url="http://somesite.com" * headers='{"X-Requested-With": "XMLHttpRequest"}' * handleAs="json" * on-core-response="{{handleResponse}}"></core-ajax> * * @attribute headers * @type Object * @default null */ headers: null, /** * Optional raw body content to send when method === "POST". * * Example: * * <core-ajax method="POST" auto url="http://somesite.com" * body='{"foo":1, "bar":2}'> * </core-ajax> * * @attribute body * @type Object * @default null */ body: null, /** * Content type to use when sending data. * * @attribute contentType * @type string * @default 'application/x-www-form-urlencoded' */ contentType: 'application/x-www-form-urlencoded', /** * Set the withCredentials flag on the request. * * @attribute withCredentials * @type boolean * @default false */ withCredentials: false, /** * Additional properties to send to core-xhr. * * Can be set to an object containing default properties * to send as arguments to the `core-xhr.request()` method * which implements the low-level communication. * * @property xhrArgs * @type Object * @default null */ xhrArgs: null, created: function() { this.progress = {}; }, ready: function() { this.xhr = document.createElement('core-xhr'); }, receive: function(response, xhr) { if (this.isSuccess(xhr)) { this.processResponse(xhr); } else { this.processError(xhr); } this.complete(xhr); }, isSuccess: function(xhr) { var status = xhr.status || 0; return (status >= 200 && status < 300); }, processResponse: function(xhr) { var response = this.evalResponse(xhr); if (xhr === this.activeRequest) { this.response = response; } this.fire('core-response', {response: response, xhr: xhr}); }, processError: function(xhr) { var response = this.evalResponse(xhr); var error = { statusCode: xhr.status, response: response }; if (xhr === this.activeRequest) { this.error = error; } this.fire('core-error', {response: error, xhr: xhr}); }, processProgress: function(progress, xhr) { if (xhr !== this.activeRequest) { return; } // We create a proxy object here because these fields // on the progress event are readonly properties, which // causes problems in common use cases (e.g. binding to // <paper-progress> attributes). var progressProxy = { lengthComputable: progress.lengthComputable, loaded: progress.loaded, total: progress.total } this.progress = progressProxy; }, complete: function(xhr) { if (xhr === this.activeRequest) { this.loading = false; } this.fire('core-complete', {response: xhr.status, xhr: xhr}); }, evalResponse: function(xhr) { return this[(this.handleAs || 'text') + 'Handler'](xhr); }, xmlHandler: function(xhr) { return xhr.responseXML; }, textHandler: function(xhr) { return xhr.responseText; }, jsonHandler: function(xhr) { var r = xhr.responseText; try { return JSON.parse(r); } catch (x) { console.warn('core-ajax caught an exception trying to parse response as JSON:'); console.warn('url:', this.url); console.warn(x); return r; } }, documentHandler: function(xhr) { return xhr.response; }, blobHandler: function(xhr) { return xhr.response; }, arraybufferHandler: function(xhr) { return xhr.response; }, urlChanged: function() { if (!this.handleAs) { var ext = String(this.url).split('.').pop(); switch (ext) { case 'json': this.handleAs = 'json'; break; } } this.autoGo(); }, paramsChanged: function() { this.autoGo(); }, bodyChanged: function() { this.autoGo(); }, autoChanged: function() { this.autoGo(); }, // TODO(sorvell): multiple side-effects could call autoGo // during one micro-task, use a job to have only one action // occur autoGo: function() { if (this.auto) { this.goJob = this.job(this.goJob, this.go, 0); } }, getParams: function(params) { params = this.params || params; if (params && typeof(params) == 'string') { params = JSON.parse(params); } return params; }, /** * Performs an Ajax request to the specified URL. * * @method go */ go: function() { var args = this.xhrArgs || {}; // TODO(sjmiles): we may want XHR to default to POST if body is set args.body = this.body || args.body; args.params = this.getParams(args.params); args.headers = this.headers || args.headers || {}; if (args.headers && typeof(args.headers) == 'string') { args.headers = JSON.parse(args.headers); } var hasContentType = Object.keys(args.headers).some(function (header) { return header.toLowerCase() === 'content-type'; }); // No Content-Type should be specified if sending `FormData`. // The UA must set the Content-Type w/ a calculated multipart boundary ID. if (args.body instanceof FormData) { delete args.headers['Content-Type']; } else if (!hasContentType && this.contentType) { args.headers['Content-Type'] = this.contentType; } if (this.handleAs === 'arraybuffer' || this.handleAs === 'blob' || this.handleAs === 'document') { args.responseType = this.handleAs; } args.withCredentials = this.withCredentials; args.callback = this.receive.bind(this); args.url = this.url; args.method = this.method; this.response = this.error = this.progress = null; this.activeRequest = args.url && this.xhr.request(args); if (this.activeRequest) { this.loading = true; var activeRequest = this.activeRequest; // IE < 10 doesn't support progress events. if ('onprogress' in activeRequest) { this.activeRequest.addEventListener( 'progress', function(progress) { this.processProgress(progress, activeRequest); }.bind(this), false); } else { this.progress = { lengthComputable: false, } } } return this.activeRequest; }, /** * Aborts the current active request if there is one and resets internal * state appropriately. * * @method abort */ abort: function() { if (!this.activeRequest) return; this.activeRequest.abort(); this.activeRequest = null; this.progress = {}; this.loading = false; } }); </script> </polymer-element>