UNPKG

ares-ide

Version:

A browser-based code editor and UI designer for Enyo 2 projects

283 lines (274 loc) 8.08 kB
/** _enyo.Ajax_ is a wrapper for _XmlHttpRequest_ that uses the <a href="#enyo.Async">enyo.Async</a> API. _enyo.Ajax_ publishes all the properties of the <a href="#enyo.AjaxProperties">enyo.AjaxProperties</a> object. Like _enyo.Async_, _enyo.Ajax_ is an **Object**, not a **Component**. Do not try to make _enyo.Ajax_ objects inside a _components_ block. If you want to use _enyo.Ajax_ as a component, you should probably be using <a href="#enyo.WebService">enyo.WebService</a> instead. If you make changes to _enyo.Ajax_, be sure to add or update the appropriate [unit tests](https://github.com/enyojs/enyo/tree/master/tools/test/ajax/tests). For more information, see the documentation on [Consuming Web Services](building-apps/managing-data/consuming-web-services.html) in the Enyo Developer Guide. */ enyo.kind({ name: "enyo.Ajax", kind: "enyo.Async", //* See <a href="#enyo.AjaxProperties">enyo.AjaxProperties</a> for the list of properties //* published by _enyo.Ajax_. published: enyo.AjaxProperties, //* @protected constructor: enyo.inherit(function (sup) { return function(inParams) { enyo.mixin(this, inParams); sup.apply(this, arguments); }; }), destroy: enyo.inherit(function (sup) { return function() { // explicilty release any XHR refs this.xhr = null; sup.apply(this, arguments); }; }), //* @public /** Sends the Ajax request with parameters _inParams_. _inParams_ values may be either Strings or Objects. _inParams_ as an Object is converted into the url query string. For instance, passing _{q: "searchTerm"}_ will result in the addition of the string _q="searchTerm"_ to the current url query string. _inParams_ as a String is used as the query part of the URL directly. _inParams_ will not be converted into a POST body, it will always be used as part of the URL query string if provided. Use the _postBody_ property for specifying a body. When the request is completed, the code will set an _xhrResponse_ property on the _enyo.Ajax_ object with the subproperties _status_, _headers_, and _body_. These cache the results from the XHR for later use. The keys for the _headers_ object are converted to all lowercase, as HTTP headers are case-insensitive. */ go: function(inParams) { this.failed = false; this.startTimer(); this.request(inParams); return this; }, //* @protected request: function(inParams) { var parts = this.url.split("?"); var uri = parts.shift() || ""; var args = parts.length ? (parts.join("?").split("&")) : []; // var query = null; // if(enyo.isString(inParams)){ //If inParams parameter is a string, use it as request body query = inParams; } else{ //If inParams parameter is not a string, build a query from it if(inParams){ query = enyo.Ajax.objectToQuery(inParams); } } // if (query) { args.push(query); query = null; } if (this.cacheBust) { args.push(Math.random()); } // var url = args.length ? [uri, args.join("&")].join("?") : uri; // var xhr_headers = {}; var body; if (this.method != "GET") { body = this.postBody; if (this.method === "POST" && body instanceof enyo.FormData) { if (body.fake) { xhr_headers["Content-Type"] = body.getContentType(); body = body.toString(); } else { // Nothing to do as the // content-type will be // automagically set according // to the FormData } } else { xhr_headers["Content-Type"] = this.contentType; if (body instanceof Object) { if (this.contentType.match(/^application\/json(;.*)?$/) !== null) { body = JSON.stringify(body); } else if (this.contentType === "application/x-www-form-urlencoded") { body = enyo.Ajax.objectToQuery(body); } else { body = body.toString(); } } } } enyo.mixin(xhr_headers, this.headers); // don't pass in headers structure if there are no headers defined as this messes // up CORS code for IE8-9 if (enyo.keys(xhr_headers).length === 0) { xhr_headers = undefined; } // try { this.xhr = enyo.xhr.request({ url: url, method: this.method, callback: this.bindSafely("receive"), body: body, headers: xhr_headers, sync: this.sync, username: this.username, password: this.password, xhrFields: enyo.mixin({onprogress: this.bindSafely(this.updateProgress)}, this.xhrFields), mimeType: this.mimeType }); } catch (e) { // IE can throw errors here if the XHR would fail CORS checks, // so catch and turn into a failure. this.fail(e); } }, receive: function(inText, inXhr) { if (!this.failed && !this.destroyed) { var body; if (typeof inXhr.responseText === "string") { body = inXhr.responseText; } else { // IE carrying a binary body = inXhr.responseBody; } this.xhrResponse = { status: inXhr.status, headers: enyo.Ajax.parseResponseHeaders(inXhr), body: body }; if (this.isFailure(inXhr)) { this.fail(inXhr.status); } else { this.respond(this.xhrToResponse(inXhr)); } } }, fail: enyo.inherit(function (sup) { return function(inError) { // on failure, explicitly cancel the XHR to prevent // further responses. cancellation also resets the // response headers & body, if (this.xhr) { enyo.xhr.cancel(this.xhr); this.xhr = null; } sup.apply(this, arguments); }; }), xhrToResponse: function(inXhr) { if (inXhr) { return this[(this.handleAs || "text") + "Handler"](inXhr); } }, isFailure: function(inXhr) { // if any exceptions are thrown while checking fields in the xhr, // assume a failure. try { var text = ""; // work around IE8-9 bug where accessing responseText will thrown error // for binary requests. if (typeof inXhr.responseText === "string") { text = inXhr.responseText; } // Follow same failure policy as jQuery's Ajax code // CORS failures on FireFox will have status 0 and no responseText, // so treat that as failure. if (inXhr.status === 0 && text === "") { return true; } // Otherwise, status 0 may be good for local file access. We treat the range // 1-199 and 300+ as failure (only 200-series code are OK). return (inXhr.status !== 0) && (inXhr.status < 200 || inXhr.status >= 300); } catch (e) { return true; } }, xmlHandler: function(inXhr) { return inXhr.responseXML; }, textHandler: function(inXhr) { return inXhr.responseText; }, jsonHandler: function(inXhr) { var r = inXhr.responseText; try { return r && enyo.json.parse(r); } catch (x) { enyo.warn("Ajax request set to handleAs JSON but data was not in JSON format"); return r; } }, //* @protected //* Handler for ajax progress events. updateProgress: function(event) { // filter out "input" as it causes exceptions on some Firefox versions // due to unimplemented internal APIs var ev = {}; for (var k in event) { if (k !== 'input') { ev[k] = event[k]; } } this.sendProgress(event.loaded, 0, event.total, ev); }, statics: { objectToQuery: function(/*Object*/ map) { var enc = encodeURIComponent; var pairs = []; var backstop = {}; for (var name in map){ var value = map[name]; if (value != backstop[name]) { var assign = enc(name) + "="; if (enyo.isArray(value)) { for (var i=0; i < value.length; i++) { pairs.push(assign + enc(value[i])); } } else { pairs.push(assign + enc(value)); } } } return pairs.join("&"); } }, protectedStatics: { parseResponseHeaders: function(xhr) { var headers = {}; var headersStr = []; if (xhr.getAllResponseHeaders) { headersStr = xhr.getAllResponseHeaders().split(/\r?\n/); } for (var i = 0; i < headersStr.length; i++) { var headerStr = headersStr[i]; var index = headerStr.indexOf(': '); if (index > 0) { var key = headerStr.substring(0, index).toLowerCase(); var val = headerStr.substring(index + 2); headers[key] = val; } } return headers; } } });