mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
145 lines
4.8 KiB
JavaScript
145 lines
4.8 KiB
JavaScript
/**
|
|
* Acquires all data from the given form and POSTs it as JSON to the target URL.
|
|
* In case of failure this function will throw an error.
|
|
* In case of success a parsed JSON body of the response will be returned,
|
|
* unless the body contains a `location` field,
|
|
* in that case the page will be redirected to that location.
|
|
*
|
|
* @param formId - ID of the form.
|
|
* @param target - Target URL to POST to. Defaults to the current URL.
|
|
* @returns {Promise<unknown>} - The response JSON.
|
|
*/
|
|
async function postJsonForm(formId, target = '') {
|
|
const form = document.getElementById(formId);
|
|
const formData = new FormData(form);
|
|
const res = await fetch(target, {
|
|
method: 'POST',
|
|
credentials: 'include',
|
|
headers: { 'accept': 'application/json', 'content-type': 'application/json' },
|
|
body: JSON.stringify(Object.fromEntries(formData)),
|
|
});
|
|
if (res.status >= 400) {
|
|
const error = await res.json();
|
|
throw new Error(`${error.statusCode} - ${error.name}: ${error.message}`)
|
|
} else if (res.status === 200 || res.status === 201) {
|
|
const body = await res.json();
|
|
if (body.location) {
|
|
location.href = body.location;
|
|
} else {
|
|
return body;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Redirects the page to the given target with the key/value pairs of the JSON body as query parameters.
|
|
* Controls will be deleted from the JSON to prevent very large URLs.
|
|
* `false` values will be deleted to prevent incorrect serializations to "false".
|
|
* @param json - JSON to convert.
|
|
* @param target - URL to redirect to.
|
|
*/
|
|
function redirectJsonResponse(json, target) {
|
|
// These would cause the URL to get very large, can be acquired later if needed
|
|
delete json.controls;
|
|
|
|
// Remove false parameters since these would be converted to "false" strings
|
|
for (const [key, val] of Object.entries(json)) {
|
|
if (typeof val === 'boolean' && !val) {
|
|
delete json[key];
|
|
}
|
|
}
|
|
|
|
const searchParams = new URLSearchParams(Object.entries(json));
|
|
location.href = `${target}?${searchParams.toString()}`;
|
|
}
|
|
|
|
/**
|
|
* Adds a listener to the given form to catch the form submission and do an API call instead.
|
|
* In case of an error, the inner text of the given error block will be updated with the message.
|
|
* In case of success the callback function will be called.
|
|
*
|
|
* @param formId - ID of the form.
|
|
* @param errorId - ID of the error block.
|
|
* @param apiTarget - Target URL to send the POST request to. Defaults to the current URL.
|
|
* @param callback - Callback function that will be called with the response JSON.
|
|
*/
|
|
async function addPostListener(formId, errorId, apiTarget, callback) {
|
|
const form = document.getElementById(formId);
|
|
const errorBlock = document.getElementById(errorId);
|
|
|
|
form.addEventListener('submit', async(event) => {
|
|
event.preventDefault();
|
|
|
|
try {
|
|
const json = await postJsonForm(formId, apiTarget);
|
|
if (json) {
|
|
callback(json);
|
|
}
|
|
} catch (error) {
|
|
errorBlock.innerText = error.message;
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Updates links on a page based on the controls received from the API.
|
|
* @param url - API URL that will return the controls
|
|
* @param controlMap - Key/value map with keys being element IDs and values being the control field names.
|
|
*/
|
|
async function addControlLinks(url, controlMap) {
|
|
const json = await fetchJson(url);
|
|
for (let [ id, control ] of Object.entries(controlMap)) {
|
|
updateElement(id, json.controls[control], { href: true });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Shows or hides the given element.
|
|
* @param id - ID of the element.
|
|
* @param visible - If it should be visible.
|
|
*/
|
|
function setVisibility(id, visible) {
|
|
const element = document.getElementById(id);
|
|
element.classList[visible ? 'remove' : 'add']('hidden');
|
|
// Disable children of hidden elements,
|
|
// such that the browser does not expect input for them
|
|
for (const child of getDescendants(element)) {
|
|
if ('disabled' in child)
|
|
child.disabled = !visible;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Obtains all children, grandchildren, etc. of the given element.
|
|
* @param element - Element to get all descendants from.
|
|
*/
|
|
function getDescendants(element) {
|
|
return [...element.querySelectorAll("*")];
|
|
}
|
|
|
|
/**
|
|
* Updates the inner text and href field of an element.
|
|
* @param id - ID of the element.
|
|
* @param text - Text to put in the field(s).
|
|
* @param options - Indicates which fields should be updated.
|
|
* Keys should be `innerText` and/or `href`, values should be booleans.
|
|
*/
|
|
function updateElement(id, text, options) {
|
|
const element = document.getElementById(id);
|
|
if (options.innerText) {
|
|
element.innerText = text;
|
|
}
|
|
if (options.href) {
|
|
element.href = text;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetches JSON from the url and converts it to an object.
|
|
* @param url - URL to fetch JSON from.
|
|
*/
|
|
async function fetchJson(url) {
|
|
const res = await fetch(url, { headers: { accept: 'application/json' } });
|
|
return res.json();
|
|
}
|