@astro-utils/forms
Version:
Server component for Astro (call server functions from client side with validation and state management)
124 lines (123 loc) • 4.22 kB
JavaScript
import getContext from '@astro-utils/context';
export default class FormsReact {
constructor(_astro) {
this._astro = _astro;
this.scriptToRun = '';
this.overrideResponse = null;
}
/**
* Reload the state (BindForm) without client redirect. If that a POST request, buttons will not be invoked again.
* Call BindForm.on.reloadState() to reload the state of every form relevant to this reload.
*/
reloadState() {
const { settings } = getContext(this._astro, '@astro-utils/forms');
settings.reloadState = true;
}
/**
* Redirects the user to the given URL after the given timeout. (using `setTimeout`)
* @param location
* @param timeoutSec - timeout in seconds
*/
redirectTimeoutSeconds(location, timeoutSec = 2) {
this.scriptToRun += `
setTimeout(function() {
window.location.href = new URL("${this._escapeParentheses(location)}", window.location.href).href;
}, ${timeoutSec * 1000});
`.trim();
}
/**
* Redirect the user to the given URL.
* @param location
* @param status - redirect status code
*/
redirect(location, status) {
this.overrideResponse = new Response(null, {
status: status || 302,
headers: {
Location: location,
},
});
}
/**
* Update the search parameters of the current URL and return `Response` object.
*/
updateSearchParams() {
const url = new URL(this._astro.request.url, 'http://example.com');
const search = url.searchParams;
const self = this;
return {
search,
redirect(status, removeEmptyParams = true) {
const copySearch = new URLSearchParams(search);
if (removeEmptyParams) {
for (const [key, value] of copySearch.entries()) {
if (value === '' || value == null) {
copySearch.delete(key);
}
}
}
const searchString = copySearch.toString();
let pathWithSearch = url.pathname.split('/').pop();
if (searchString) {
pathWithSearch += '?' + searchString;
}
self.overrideResponse = new Response(null, {
status: status || 302,
headers: {
Location: pathWithSearch,
},
});
}
};
}
/**
* Update **one** search parameter of the current URL and return `Response` object.
* @param key - search parameter key
* @param value - search parameter value (if `null` the parameter will be removed)
* @param status - redirect status code
*/
updateOneSearchParam(key, value, status) {
const { search, redirect } = this.updateSearchParams();
if (value == null) {
search.delete(key);
}
else {
search.set(key, value);
}
redirect(status);
}
/**
* Prompt alert message to the user with the `window.alert` function.
* @param message
*/
alert(message) {
this.callFunction('alert', message);
}
/**
* Print a message to the client console with the `console` class.
*/
console(type, ...messages) {
if (!(type in console)) {
throw new Error(`Invalid console type: ${type}`);
}
this.callFunction(`console.${type}`, ...messages);
}
/**
* Print a message to the client console with the `console.log` function.
*/
consoleLog(...messages) {
this.console('log', ...messages);
}
/**
* Call a client side function with the given arguments.
* @warning - this is **not** a safe function, make sure to validate the arguments before calling this function.
*/
callFunction(func, ...args) {
this.scriptToRun += `
${func}(...${JSON.stringify(args)});
`.trim();
}
_escapeParentheses(str) {
return str.replace(/"/g, '\\"');
}
}