UNPKG

@aemforms/af-custom-functions

Version:

Provides a collection of custom functions designed to aid creation of adaptive form

284 lines (265 loc) 10.5 kB
/** * Validates if the given URL is correct. * @param {string} url - The URL to validate. * @returns {boolean} - True if the URL is valid, false otherwise. */ function validateURL(url) { try { const validatedUrl = new URL(url, window.location.href); return (validatedUrl.protocol === 'http:' || validatedUrl.protocol === 'https:'); } catch (err) { return false; } } /** * Converts a JSON string to an object. * @param {string} str - The JSON string to convert to an object. * @returns {object} - The parsed JSON object. Returns an empty object if an exception occurs. * @memberof module:FormView~customFunctions */ function toObject(str) { if (typeof str === 'string') { try { return JSON.parse(str); } catch (e) { return {}; } } return str; } /** * Navigates to the specified URL. * @param {string} destinationURL - The URL to navigate to. If not specified, a new blank window will be opened. * @param {string} destinationType - The type of destination. Supports the following values: "_newwindow", "_blank", "_parent", "_self", "_top", or the name of the window. * @returns {Window} - The newly opened window. */ function navigateTo(destinationURL, destinationType) { let param = null, windowParam = window, arg = null; switch (destinationType){ case "_newwindow": param = "_blank"; arg = "width=1000,height=800"; break; } if (!param) { if (destinationType) { param = destinationType; } else { param = "_blank"; } } if (validateURL(destinationURL)){ windowParam.open(destinationURL, param, arg); } } /** * Default error handler for the invoke service API. * @param {object} response - The response body of the invoke service API. * @param {object} headers - The response headers of the invoke service API. * @param {scope} globals - An object containing read-only form instance, read-only target field instance and methods for form modifications. * @returns {void} */ function defaultErrorHandler(response, headers, globals) { if(response && response.validationErrors) { response.validationErrors?.forEach(function (violation) { if (violation.details) { if (violation.fieldName) { globals.functions.markFieldAsInvalid(violation.fieldName, violation.details.join("\n"), {useQualifiedName: true}); } else if (violation.dataRef) { globals.functions.markFieldAsInvalid(violation.dataRef, violation.details.join("\n"), {useDataRef: true}); } } }); } } /** * Handles the success response after a form submission. * * @param {scope} globals - An object containing read-only form instance, read-only target field instance and methods for form modifications. * @returns {void} */ function defaultSubmitSuccessHandler(globals) { const event = globals.event; const submitSuccessResponse = event?.payload?.body; const form = globals.form; if (submitSuccessResponse) { if (submitSuccessResponse.redirectUrl) { window.location.href = encodeURI(submitSuccessResponse.redirectUrl); } else if (submitSuccessResponse.thankYouMessage) { let formContainerElement = document.getElementById(`${form.$id}`); let thankYouMessage = document.createElement("div"); thankYouMessage.setAttribute("class", "tyMessage"); thankYouMessage.setAttribute("tabindex", "-1"); thankYouMessage.setAttribute("role","alertdialog"); thankYouMessage.innerHTML = submitSuccessResponse.thankYouMessage; formContainerElement.replaceWith(thankYouMessage); thankYouMessage.focus(); } } } /** * Handles the error response after a form submission. * * @param {string} defaultSubmitErrorMessage - The default error message. * @param {scope} globals - An object containing read-only form instance, read-only target field instance and methods for form modifications. * @returns {void} */ function defaultSubmitErrorHandler(defaultSubmitErrorMessage, globals) { // view layer should send localized error message here window.alert(defaultSubmitErrorMessage); } /** * Fetches the captcha token for the form. * * This function uses the Google reCAPTCHA Enterprise/turnstile service to fetch the captcha token. * * @async * @param {object} globals - An object containing read-only form instance, read-only target field instance and methods for form modifications. * @returns {string} - The captcha token. */ async function fetchCaptchaToken(globals) { return new Promise((resolve, reject) => { // successCallback and errorCallback can be reused for different captcha implementations const successCallback = function(token) { resolve(token); }; const errorCallback = function(error) { reject(error); }; try{ const captcha = globals.form.$captcha; if (captcha.$captchaProvider === "turnstile") { const turnstileContainer = document.getElementsByClassName("cmp-adaptiveform-turnstile__widget")[0]; const turnstileParameters = { 'sitekey': captcha.$captchaSiteKey, 'callback': successCallback, 'error-callback': errorCallback } if(turnstile != undefined) { const widgetId = turnstile.render(turnstileContainer, turnstileParameters); if (widgetId) { turnstile.execute(widgetId); } else { reject({error: "Failed to render turnstile captcha"}); } } else { reject({error: "Turnstile captcha not loaded"}); } } else { const siteKey = captcha?.$properties['fd:captcha']?.config?.siteKey; const captchaElementName = captcha.$name.replaceAll('-', '_'); let captchaPath = captcha?.$properties['fd:path']; const index = captchaPath.indexOf('/jcr:content'); let formName = ''; if (index > 0) { captchaPath = captchaPath.substring(0, index); formName = captchaPath.substring(captchaPath.lastIndexOf("/") + 1).replaceAll('-', '_'); } let actionName = `submit_${formName}_${captchaElementName}`; grecaptcha.enterprise.ready(() => { grecaptcha.enterprise.execute(siteKey, {action: actionName}) .then((token) => resolve(token)) .catch((error) => reject(error)); }); } } catch (error) { reject(error); } }); } /** * Converts a date to the number of days since the Unix epoch (1970-01-01). * * If the input date is a number, it is assumed to represent the number of days since the epoch, * including both integer and decimal parts. In this case, only the integer part is returned as the number of days. * * @param {string|Date|number} date - The date to convert. * Can be: * - An ISO string (yyyy-mm-dd) * - A Date object * - A number representing the days since the epoch, where the integer part is the number of days and the decimal part is the fraction of the day * * @returns {number} - The number of days since the Unix epoch */ function dateToDaysSinceEpoch(date) { let dateObj; if (typeof date === 'string') { dateObj = new Date(date); } else if (typeof date === 'number') { return Math.floor(date); } else if (date instanceof Date) { dateObj = date; } else { throw new Error('Invalid date input'); } // Validate that date is valid after parsing if (isNaN(dateObj.getTime())) { throw new Error('Invalid date input'); } return Math.floor(dateObj.getTime() / (1000 * 60 * 60 * 24)); } /** * Prefixes the URL with the context path. * @param {string} url - The URL to externalize. * @returns {string} - The externalized URL. */ function externalize(url) { // Check if Granite.HTTP.externalize is available, otherwise return the original URL if (window?.Granite?.HTTP && typeof window.Granite.HTTP.externalize === "function") { return window.Granite.HTTP.externalize(url); } else { return url; } } /** * Downloads the Document of Record (DoR) for the form. * * @param {string=} fileName - The name of the file to be downloaded. Defaults to "Downloaded_DoR.pdf" if not specified. * @param {scope} globals - An object containing read-only form instance, read-only target field instance, and methods for form modifications. * @returns {void} */ function downloadDoR(fileName, globals) { const lang = globals.form.$lang; const query = new URLSearchParams({ locale: lang }).toString(); let dorApiUrl = externalize('/adobe/forms/af/dor/' + globals.form.$id + '?' + query); const formData = new FormData(); var jsonString = JSON.stringify(globals.functions.exportData()); formData.append('data', jsonString); const id = globals.form.$id; var xhr = new XMLHttpRequest(); xhr.open('POST', dorApiUrl, true); xhr.responseType = "arraybuffer"; xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { const blob = new Blob([xhr.response], { type: 'application/pdf' }); const blobUrl = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = blobUrl; a.download = fileName || "Downloaded_DoR.pdf"; document.body.appendChild(a); a.click(); URL.revokeObjectURL(blobUrl); document.body.removeChild(a); } else { console.error("Error while generating pdf"); } } }; xhr.send(formData); } export { validateURL, navigateTo, toObject, defaultErrorHandler, defaultSubmitSuccessHandler, defaultSubmitErrorHandler, fetchCaptchaToken, dateToDaysSinceEpoch, externalize, downloadDoR };