devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
339 lines (269 loc) • 9.53 kB
JavaScript
var Deferred = require("./deferred").Deferred;
var domAdapter = require("../../core/dom_adapter");
var httpRequest = require("../../core/http_request");
var windowUtils = require("../../core/utils/window");
var window = windowUtils.getWindow();
var extendFromObject = require("./extend").extendFromObject;
var isDefined = require("./type").isDefined;
var Promise = require("../polyfills/promise");
var injector = require("./dependency_injector");
var SUCCESS = "success",
ERROR = "error",
TIMEOUT = "timeout",
NO_CONTENT = "nocontent",
PARSER_ERROR = "parsererror";
var isStatusSuccess = function isStatusSuccess(status) {
return 200 <= status && status < 300;
};
var hasContent = function hasContent(status) {
return status !== 204;
};
var paramsConvert = function paramsConvert(params) {
var result = [];
for (var name in params) {
var value = params[name];
if (value === undefined) {
continue;
}
if (value === null) {
value = "";
}
result.push(encodeURIComponent(name) + "=" + encodeURIComponent(value));
}
return result.join("&");
};
var createScript = function createScript(options) {
var script = domAdapter.createElement("script");
for (var name in options) {
script[name] = options[name];
}
return script;
};
var removeScript = function removeScript(scriptNode) {
scriptNode.parentNode.removeChild(scriptNode);
};
var appendToHead = function appendToHead(element) {
return domAdapter.getHead().appendChild(element);
};
var evalScript = function evalScript(code) {
var script = createScript({ text: code });
appendToHead(script);
removeScript(script);
};
var evalCrossDomainScript = function evalCrossDomainScript(url) {
var script = createScript({ src: url });
return new Promise(function (resolve, reject) {
var events = {
"load": resolve,
"error": reject
};
var loadHandler = function loadHandler(e) {
events[e.type]();
removeScript(script);
};
for (var event in events) {
domAdapter.listen(script, event, loadHandler);
}
appendToHead(script);
});
};
var getAcceptHeader = function getAcceptHeader(options) {
var dataType = options.dataType || "*",
scriptAccept = "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript",
accepts = {
"*": "*/*",
text: "text/plain",
html: "text/html",
xml: "application/xml, text/xml",
json: "application/json, text/javascript",
jsonp: scriptAccept,
script: scriptAccept
};
extendFromObject(accepts, options.accepts, true);
return accepts[dataType] ? accepts[dataType] + (dataType !== "*" ? ", */*; q=0.01" : "") : accepts["*"];
};
var getContentTypeHeader = function getContentTypeHeader(options) {
var defaultContentType;
if (options.data && !options.upload && getMethod(options) !== "GET") {
defaultContentType = "application/x-www-form-urlencoded;charset=utf-8";
}
return options.contentType || defaultContentType;
};
var getDataFromResponse = function getDataFromResponse(xhr) {
return xhr.responseType && xhr.responseType !== "text" || typeof xhr.responseText !== "string" ? xhr.response : xhr.responseText;
};
var postProcess = function postProcess(deferred, xhr, dataType) {
var data = getDataFromResponse(xhr);
switch (dataType) {
case "jsonp":
evalScript(data);
break;
case "script":
evalScript(data);
deferred.resolve(data, SUCCESS, xhr);
break;
case "json":
try {
deferred.resolve(JSON.parse(data), SUCCESS, xhr);
} catch (e) {
deferred.reject(xhr, PARSER_ERROR, e);
}
break;
default:
deferred.resolve(data, SUCCESS, xhr);
}
};
var isCrossDomain = function isCrossDomain(url) {
if (!windowUtils.hasWindow()) {
return true;
}
var crossDomain = false,
originAnchor = domAdapter.createElement("a"),
urlAnchor = domAdapter.createElement("a");
originAnchor.href = window.location.href;
try {
urlAnchor.href = url;
urlAnchor.href = urlAnchor.href;
crossDomain = originAnchor.protocol + "//" + originAnchor.host !== urlAnchor.protocol + "//" + urlAnchor.host;
} catch (e) {
crossDomain = true;
}
return crossDomain;
};
var setHttpTimeout = function setHttpTimeout(timeout, xhr) {
return timeout && setTimeout(function () {
xhr.customStatus = TIMEOUT;
xhr.abort();
}, timeout);
};
var getJsonpOptions = function getJsonpOptions(options) {
if (options.dataType === "jsonp") {
var random = Math.random().toString().replace(/\D/g, ""),
callbackName = options.jsonpCallback || "dxCallback" + Date.now() + "_" + random,
callbackParameter = options.jsonp || "callback";
options.data = options.data || {};
options.data[callbackParameter] = callbackName;
return callbackName;
}
};
var getRequestOptions = function getRequestOptions(options, headers) {
var params = options.data,
url = options.url || window.location.href;
if (!options.cache) {
params = params || {};
params["_"] = Date.now();
}
if (params && !options.upload) {
if (typeof params !== "string") {
params = paramsConvert(params);
}
if (getMethod(options) === "GET") {
url += (url.indexOf("?") > -1 ? "&" : "?") + params;
params = null;
} else if (headers["Content-Type"] && headers["Content-Type"].indexOf("application/x-www-form-urlencoded") > -1) {
params = params.replace(/%20/g, "+");
}
}
return {
url: url,
parameters: params
};
};
var getMethod = function getMethod(options) {
return (options.method || "GET").toUpperCase();
};
var getRequestHeaders = function getRequestHeaders(options) {
var headers = options.headers || {};
headers["Content-Type"] = headers["Content-Type"] || getContentTypeHeader(options);
headers["Accept"] = headers["Accept"] || getAcceptHeader(options);
if (!options.crossDomain && !headers["X-Requested-With"]) {
headers["X-Requested-With"] = "XMLHttpRequest";
}
return headers;
};
var sendRequest = function sendRequest(options) {
var xhr = httpRequest.getXhr(),
d = new Deferred(),
result = d.promise(),
async = isDefined(options.async) ? options.async : true,
dataType = options.dataType,
timeout = options.timeout || 0,
timeoutId;
options.crossDomain = isCrossDomain(options.url);
var needScriptEvaluation = dataType === "jsonp" || dataType === "script";
if (options.cache === undefined) {
options.cache = !needScriptEvaluation;
}
var callbackName = getJsonpOptions(options),
headers = getRequestHeaders(options),
requestOptions = getRequestOptions(options, headers),
url = requestOptions.url,
parameters = requestOptions.parameters;
if (callbackName) {
window[callbackName] = function (data) {
d.resolve(data, SUCCESS, xhr);
};
}
if (options.crossDomain && needScriptEvaluation) {
var reject = function reject() {
d.reject(xhr, ERROR);
},
resolve = function resolve() {
if (dataType === "jsonp") return;
d.resolve(null, SUCCESS, xhr);
};
evalCrossDomainScript(url).then(resolve, reject);
return result;
}
if (options.crossDomain && !("withCredentials" in xhr)) {
d.reject(xhr, ERROR);
return result;
}
xhr.open(getMethod(options), url, async, options.username, options.password);
if (async) {
xhr.timeout = timeout;
timeoutId = setHttpTimeout(timeout, xhr, d);
}
xhr["onreadystatechange"] = function (e) {
if (xhr.readyState === 4) {
clearTimeout(timeoutId);
if (isStatusSuccess(xhr.status)) {
if (hasContent(xhr.status)) {
postProcess(d, xhr, dataType);
} else {
d.resolve(null, NO_CONTENT, xhr);
}
} else {
d.reject(xhr, xhr.customStatus || ERROR);
}
}
};
if (options.upload) {
xhr.upload["onprogress"] = options.upload["onprogress"];
xhr.upload["onloadstart"] = options.upload["onloadstart"];
xhr.upload["onabort"] = options.upload["onabort"];
}
if (options.xhrFields) {
for (var field in options.xhrFields) {
xhr[field] = options.xhrFields[field];
}
}
if (options.responseType === "arraybuffer") {
xhr.responseType = options.responseType;
}
for (var name in headers) {
if (headers.hasOwnProperty(name) && isDefined(headers[name])) {
xhr.setRequestHeader(name, headers[name]);
}
}
if (options.beforeSend) {
options.beforeSend(xhr);
}
xhr.send(parameters);
result.abort = function () {
xhr.abort();
};
return result;
};
module.exports = injector({ sendRequest: sendRequest });
;