const ajax = (function() { "use strict"; class NetworkError extends Error {} class UnexpectedMimeError extends Error {} class InvalidJsonError extends Error {} const MIME_JSON = "application/json"; /** * Wrap a function so that it receives `this` as first argument. */ function thisToArg(f) { return function(...rest) { return f(this, ...rest); } } 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) { if (xhr.status == 0) { console.error(xhr); throw new NetworkError("Failed to connect to server"); } if (!xhr.responseText) { const json = null; } else { const contentType = xhr.getResponseHeader("Content-Type"); if (contentType != MIME_JSON) { throw new UnexpectedMimeError(`Server did not reply with JSON but with ${contentType}`); } try { const json = JSON.parse(xhr.responseText); } catch(e) { throw new InvalidJsonError(); } } return { ok: 200 <= xhr.status && xhr.status < 300, status: xhr.status, statusText: xhr.statusText, getHeader: xhr.getResponseHeader, json, xhr, }; } function getJson(url, options={}) { if (!options.headers) options.headers = {}; options.headers["Accept"] = MIME_JSON; return new Promise((resolve, reject) => { let xhr = xhrInitForPromise(resolve, reject, url, "GET", options.headers); xhr.send(); }).then(xhrParseJsonResponse); } function postJson(url, data={}, options={}) { if (!options.headers) options.headers = {}; options.headers["Content-Type"] = MIME_JSON; options.headers["Accept"] = MIME_JSON; return new Promise((resolve, reject) => { let xhr = xhrInitForPromise(resolve, reject, url, "POST", options.headers); xhr.send(JSON.stringify(data)); }).then(xhrParseJsonResponse); } return { NetworkError, UnexpectedMimeError, InvalidJsonError, getJson, postJson }; })();