arch-repo-manager/srv/static/js/ajaxhelper.js

140 lines
4.3 KiB
JavaScript

const apiPrefix = 'api/v0';
let authError = false;
/// \brief Makes an AJAX query with basic error handling.
function queryRoute(method, path, callback)
{
const ajaxRequest = new XMLHttpRequest();
ajaxRequest.onreadystatechange = function() {
if (this.readyState === 4) {
const status = this.status;
authError = status === 403;
switch (status) {
case 401:
return queryRoute(method, path, callback);
case 403:
return window.alert('Authentication failed. Try again.');
default:
try {
return callback(this, status === 200);
} catch (e) {
window.alert('Unable to process server response: ' + e);
throw e;
}
}
}
};
const args = [method, apiPrefix + path, true];
if (authError) {
args.push('try', 'again');
}
ajaxRequest.open(...args);
ajaxRequest.send();
return ajaxRequest;
}
/// \brief Makes an AJAX query for the specified form.
function startFormQuery(formId, handler)
{
return startFormQueryEx(formId, handler).ajaxRequest;
}
/// \brief Makes an AJAX query for the specified form.
function startFormQueryEx(formId, handler)
{
const form = document.getElementById(formId);
const params = makeFormQueryParameter(form);
return {
ajaxRequest: queryRoute(form.method, form.getAttribute('action') + params, handler),
form: form,
params, params,
};
}
/// \brief Returns the query parameter for the specified \a form element.
function makeFormQueryParameter(form)
{
const params = [];
const formElements = form.elements;
for (let i = 0, count = formElements.length; i != count; ++i) {
const formElement = formElements[i];
if (formElement.disabled || formElement.style.display === 'none') {
continue; // if we disable a form element or hide it via CSS we also don't want to submit its data
}
const type = formElement.type;
if ((type === 'checkbox' || type === 'radio') && !formElement.checked) {
continue;
}
const name = formElement.name;
if (name === undefined || name.length < 1) {
continue;
}
else if (name === 'package-names') {
const packageNames = formElement.value.split(/[,\s]+/);
packageNames.forEach(function (packageName) {
if (packageName.length <= 0) {
return;
}
params.push(['package', encodeURIComponent(packageName)].join("="));
});
continue;
}
const values = [];
const options = formElement.options;
if (options !== undefined) {
for (let i = 0, end = options.length; i != end; ++i) {
const option = options[i];
if (option.selected && option.dataset.ignore) {
continue;
}
const value = option.value;
if (option.selected && value !== undefined && value !== 'none' && value !== 'None') {
values.push(value);
}
}
} else if (formElement.value !== undefined) {
values.push(formElement.value);
}
values.forEach(function(value) {
params.push([encodeURIComponent(name), encodeURIComponent(value)].join("="));
});
}
if (params.length < 1) {
return "";
}
return "?" + params.join("&");
}
function makeIdParams(ids)
{
if (!Array.isArray(ids)) {
ids = [ids];
}
return ids.map(id => 'id=' + encodeURIComponent(id)).join('&');
}
/// \brief Shows an alert for the specified AJAX request.
function showAjaxError(xhr, action)
{
let errorMessage;
try {
errorMessage = JSON.parse(xhr.responseText).error;
} catch (e) {
errorMessage = xhr.responseText;
}
if (!errorMessage) {
errorMessage = 'unknown error';
}
window.alert('Unable to ' + action + ': ' + errorMessage);
}
/// \brief Returns whether the specified AJAX request failed and shows an alert it it did.
function checkForAjaxError(xhr, action)
{
if (xhr.status === 200) {
return false;
}
showAjaxError(xhr, action);
return true;
}