feathermost/ajax.js

109 lines
2.9 KiB
JavaScript
Raw Normal View History

2020-03-25 17:05:25 +01:00
const ajax = (function() { "use strict";
2020-03-26 16:01:09 +01:00
class AjaxError extends Error {
constructor (message, xhr, ...rest) {
2020-03-26 16:01:09 +01:00
super(message, ...rest);
this.xhr = xhr;
2020-03-26 16:01:09 +01:00
}
}
class NetworkError extends AjaxError {}
class NotOkError extends AjaxError {}
class UnexpectedMimeError extends AjaxError {}
class InvalidJsonError extends AjaxError {}
2020-03-25 17:05:25 +01:00
const MIME_JSON = "application/json";
function xhrInitForPromise(resolve, reject, url, method, headers) {
const t_resolve = thisToArg(resolve),
t_reject = thisToArg(reject);
let xhr = new XMLHttpRequest();
xhr.addEventListener("load", t_resolve);
xhr.addEventListener("error", t_resolve);
xhr.addEventListener("abort", t_reject);
xhr.addEventListener("timeout", t_reject);
xhr.open(method, url);
for (let header of Object.getOwnPropertyNames(headers)) {
xhr.setRequestHeader(header, headers[header]);
}
return xhr;
}
function xhrParseJsonResponse(xhr) {
2020-03-26 16:01:09 +01:00
xhr.responseJson = null;
xhr.ok = false;
2020-03-25 17:05:25 +01:00
2020-03-26 16:01:09 +01:00
if (xhr.responseText) {
2020-03-25 17:05:25 +01:00
const contentType = xhr.getResponseHeader("Content-Type");
if (contentType != MIME_JSON) {
2020-03-26 16:01:09 +01:00
throw new UnexpectedMimeError(`Server did not reply with JSON but with ${contentType}`, xhr);
2020-03-25 17:05:25 +01:00
}
try {
2020-03-26 16:01:09 +01:00
xhr.responseJson = JSON.parse(xhr.responseText);
2020-03-25 17:05:25 +01:00
} catch(e) {
2020-03-26 16:01:09 +01:00
throw new InvalidJsonError("Server replied with JSON that we couldn't parse", xhr);
}
}
xhr.ok = 200 <= xhr.status && xhr.status < 300;
if (!xhr.ok) {
console.error(xhr);
if (xhr.status === 0) {
throw new NetworkError("Failed to connect to server. Developer console may have more information", xhr);
} else {
throw new NotOkError(`${xhr.status} ${xhr.statusText}`, xhr);
2020-03-25 17:05:25 +01:00
}
}
2020-03-26 16:01:09 +01:00
return xhr;
2020-03-25 17:05:25 +01:00
}
2020-03-29 00:40:47 +01:00
function withParams(url, queryParams) {
let sep = "?";
for (let paramName of Object.getOwnPropertyNames(queryParams)) {
const paramValue = queryParams[paramName];
if (!paramValue) continue;
url += `${sep}${encodeURIComponent(paramName)}`;
if (paramValue !== true) {
url += `=${encodeURIComponent(paramValue)}`;
}
sep = "&";
}
}
2020-03-25 17:05:25 +01:00
function getJson(url, options={}) {
2020-03-29 00:40:47 +01:00
if (!options.queryParams) options.queryParams = {};
2020-03-25 17:05:25 +01:00
if (!options.headers) options.headers = {};
options.headers["Accept"] = MIME_JSON;
2020-03-29 00:40:47 +01:00
const urlWithParams = withParams(url, options.queryParams);
2020-03-25 17:05:25 +01:00
return new Promise((resolve, reject) => {
let xhr = xhrInitForPromise(resolve, reject, url, "GET", options.headers);
xhr.send();
}).then(xhrParseJsonResponse);
}
2020-03-26 16:01:09 +01:00
function postJson(url, data=undefined, options={}) {
2020-03-25 17:05:25 +01:00
if (!options.headers) options.headers = {};
options.headers["Content-Type"] = MIME_JSON;
options.headers["Accept"] = MIME_JSON;
2020-03-25 17:05:25 +01:00
return new Promise((resolve, reject) => {
let xhr = xhrInitForPromise(resolve, reject, url, "POST", options.headers);
2020-03-26 16:01:09 +01:00
if (data === undefined) {
xhr.send();
} else {
xhr.send(JSON.stringify(data));
}
2020-03-25 17:05:25 +01:00
}).then(xhrParseJsonResponse);
}
return {
2020-03-26 16:01:09 +01:00
NetworkError, NotOkError, UnexpectedMimeError, InvalidJsonError,
2020-03-25 17:05:25 +01:00
getJson, postJson
};
})();