devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
299 lines (297 loc) • 9.77 kB
JavaScript
/**
* DevExtreme (esm/core/utils/ajax.js)
* Version: 21.1.4
* Build date: Mon Jun 21 2021
*
* Copyright (c) 2012 - 2021 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
import {
Deferred
} from "./deferred";
import domAdapter from "../../core/dom_adapter";
import httpRequest from "../../core/http_request";
import {
getWindow,
hasWindow
} from "../../core/utils/window";
var window = getWindow();
import {
extendFromObject
} from "./extend";
import {
isDefined
} from "./type";
import Promise from "../polyfills/promise";
import injector from "./dependency_injector";
var SUCCESS = "success";
var ERROR = "error";
var TIMEOUT = "timeout";
var NO_CONTENT = "nocontent";
var PARSER_ERROR = "parsererror";
var isStatusSuccess = function(status) {
return 200 <= status && status < 300
};
var hasContent = function(status) {
return 204 !== status
};
var paramsConvert = function(params) {
var result = [];
for (var name in params) {
var value = params[name];
if (void 0 === value) {
continue
}
if (null === value) {
value = ""
}
if ("function" === typeof value) {
value = value()
}
result.push(encodeURIComponent(name) + "=" + encodeURIComponent(value))
}
return result.join("&")
};
var createScript = function(options) {
var script = domAdapter.createElement("script");
for (var name in options) {
script[name] = options[name]
}
return script
};
var removeScript = function(scriptNode) {
scriptNode.parentNode.removeChild(scriptNode)
};
var appendToHead = function(element) {
return domAdapter.getHead().appendChild(element)
};
var evalScript = function(code) {
var script = createScript({
text: code
});
appendToHead(script);
removeScript(script)
};
var evalCrossDomainScript = function(url) {
var script = createScript({
src: url
});
return new Promise((function(resolve, reject) {
var events = {
load: resolve,
error: reject
};
var loadHandler = function(e) {
events[e.type]();
removeScript(script)
};
for (var event in events) {
domAdapter.listen(script, event, loadHandler)
}
appendToHead(script)
}))
};
var getAcceptHeader = function(options) {
var dataType = options.dataType || "*";
var scriptAccept = "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript";
var 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(options) {
var defaultContentType;
if (options.data && !options.upload && "GET" !== getMethod(options)) {
defaultContentType = "application/x-www-form-urlencoded;charset=utf-8"
}
return options.contentType || defaultContentType
};
var getDataFromResponse = function(xhr) {
return xhr.responseType && "text" !== xhr.responseType || "string" !== typeof xhr.responseText ? xhr.response : xhr.responseText
};
var postProcess = function(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(url) {
if (!hasWindow()) {
return true
}
var crossDomain = false;
var originAnchor = domAdapter.createElement("a");
var 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(timeout, xhr) {
return timeout && setTimeout((function() {
xhr.customStatus = TIMEOUT;
xhr.abort()
}), timeout)
};
var getJsonpOptions = function(options) {
if ("jsonp" === options.dataType) {
var random = Math.random().toString().replace(/\D/g, "");
var callbackName = options.jsonpCallback || "dxCallback" + Date.now() + "_" + random;
var callbackParameter = options.jsonp || "callback";
options.data = options.data || {};
options.data[callbackParameter] = callbackName;
return callbackName
}
};
var getRequestOptions = function(options, headers) {
var params = options.data;
var paramsAlreadyString = "string" === typeof params;
var url = options.url || window.location.href;
if (!paramsAlreadyString && !options.cache) {
params = params || {};
params._ = Date.now()
}
if (params && !options.upload) {
if (!paramsAlreadyString) {
params = paramsConvert(params)
}
if ("GET" === getMethod(options)) {
if ("" !== params) {
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
}
};
function getMethod(options) {
return (options.method || "GET").toUpperCase()
}
var getRequestHeaders = function(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(options) {
var xhr = httpRequest.getXhr();
var d = new Deferred;
var result = d.promise();
var async = isDefined(options.async) ? options.async : true;
var dataType = options.dataType;
var timeout = options.timeout || 0;
var timeoutId;
options.crossDomain = isCrossDomain(options.url);
var needScriptEvaluation = "jsonp" === dataType || "script" === dataType;
if (void 0 === options.cache) {
options.cache = !needScriptEvaluation
}
var callbackName = getJsonpOptions(options);
var headers = getRequestHeaders(options);
var requestOptions = getRequestOptions(options, headers);
var url = requestOptions.url;
var parameters = requestOptions.parameters;
if (callbackName) {
window[callbackName] = function(data) {
d.resolve(data, SUCCESS, xhr)
}
}
if (options.crossDomain && needScriptEvaluation) {
evalCrossDomainScript(url).then((function() {
if ("jsonp" === dataType) {
return
}
d.resolve(null, SUCCESS, xhr)
}), (function() {
d.reject(xhr, ERROR)
}));
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 (4 === xhr.readyState) {
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 ("arraybuffer" === options.responseType) {
xhr.responseType = options.responseType
}
for (var name in headers) {
if (Object.prototype.hasOwnProperty.call(headers, 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
};
export default injector({
sendRequest: sendRequest
});