/** * ---------------------------------------------- * Helper functions for BladeWindUI components * ---------------------------------------------- */ const currentModal = []; let elName; /** * Shortcut for document.querySelector. * @param {string} element - The element to find in the DOM. * @return {(Element|boolean)} The matching DOM element. * @see {@link https://bladewindui.com/extra/helper-functions#domel} */ const domEl = (element) => { return (document.querySelector(element) !== null) ? document.querySelector(element) : false; }; /** * Alias for domEl(element) */ const dom_el = (element) => { return domEl(element); }; /** * Shortcut for document.querySelectorAll. * @param {string} element - The element(s) to find in the DOM. * @param scope * @return {NodeListOf<*>|boolean} The collection of DOM elements. * @see {@link https://bladewindui.com/extra/helper-functions#domels} */ const domEls = (element, scope = null) => { if (scope) { if (typeof scope === 'string') { if (scope.indexOf('.') === -1 && scope.indexOf('#') === -1) { console.log(`${scope} needs to contain . or # to target it in the DOM`); } scope = document.querySelector(scope); } return scope.querySelectorAll(element); } return (document.querySelectorAll(element).length > 0) ? document.querySelectorAll(element) : false; }; /** * Alias for domEls(element) */ const dom_els = (element) => { return domEls(element); }; /** * Check to see if val is empty * @param {string} val - The string to test emptiness for * @return {boolean} True if string is empty */ const isEmpty = (val) => { let regex = /^\s*$/; return regex.test(val); }; /** * Hide an element. * @param {string} element - The css class (name) of the element to hide. * @param {boolean} elementIsDomObject - If true, will not be treated as a string but DOM element. * @return {void} * @see {@link https://bladewindui.com/extra/helper-functions#hide} */ const hide = (element, elementIsDomObject = false) => { if ((!elementIsDomObject && domEl(element) != null) || (elementIsDomObject && element != null)) { changeCss(element, 'hidden', 'add', elementIsDomObject); } }; /** * Display an element. * @param {Object|boolean} element - The css class (name) of the element to hide. * @param {boolean} elementIsDomObject - If true, will not be treated as a string but DOM element. * @return {void} * @see {@link https://bladewindui.com/extra/helper-functions#unhide} */ const unhide = (element, elementIsDomObject = false) => { if ((!elementIsDomObject && domEl(element) != null) || (elementIsDomObject && element != null)) { changeCss(element, 'hidden', 'remove', elementIsDomObject); } }; /** * Clear validation errors. Used together with validateForm(). * If the user provides a value for a form field, that was earlier marked as an error, clear it. * @param {Object} obj - The DOM element to target for clearing. * @return {void} */ const clearErrors = (obj) => { let el = obj.el; let elParent = obj.elParent; let elName = obj.elName; let showErrorInline = obj.showErrorInline; if (el.value !== '') { (elParent !== null) ? domEl(`.${elParent} .clickable`).classList.remove('!border-red-400') : el.classList.remove('!border-red-400'); (showErrorInline) ? hide(`.${elName}-inline-error`) : ''; } else { (elParent !== null) ? domEl(`.${elParent} .clickable`).classList.add('!border-red-400') : el.classList.add('!border-red-400'); (showErrorInline) ? unhide(`.${elName}-inline-error`) : ''; } }; /** * Modify the css for a DOM element. * @param {Element|boolean} element - The class name of ID of the DOM element to modify. * @param {string} css - Comma separated list of css classes to apply to . * @param {string} mode - Add|Remove. Determines if should be added or removed from . * @param {boolean} elementIsDomObject - If true, will not be treated as a string but DOM element. * @return {void} * @see {@link https://bladewindui.com/extra/helper-functions#changecss} * @example * changeCss('.email', 'border-2, border-red-500'); * changeCss('.email', 'border-2, border-red-500', 'remove'); * changeCss(domEl('.email'), 'border-2, border-red-500', 'remove', true); */ const changeCss = (element, css, mode = 'add', elementIsDomObject = false) => { // css can be comma separated // if !elementIsDomObject run it through domEl if (!elementIsDomObject) element = domEl(element); if (element) { if (css.indexOf(',') !== -1 || css.indexOf(' ') !== -1) { css = css.replace(/\s+/g, '').split(','); for (let classname of css) { (mode === 'add') ? element.classList.add(classname.trim()) : element.classList.remove(classname.trim()); } } else { if (element.classList !== undefined) { (mode === 'add') ? element.classList.add(css) : element.classList.remove(css); } } } }; /** * Validate a form and highlight each field that fails validation. * element does not need to be a
tag. Can be any element containing form fields. * @param form * @return {boolean} True if validation passes and False if validation fails. * @see {@link https://bladewindui.com/extra/helper-functions#validateform} */ const validateForm = (form) => { let hasError = 0; let BreakException = {}; let fieldToValidate = []; try { fieldToValidate = (typeof (form) === 'string') ? domEls(`${form} .required`) : form.querySelectorAll('.required'); fieldToValidate.forEach((el) => { changeCss(el, '!border-red-500', 'remove', true); if (isEmpty(el.value)) { let elName = el.getAttribute('name'); let elParent = el.getAttribute('data-parent'); let errorMessage = el.getAttribute('data-error-message'); let showErrorInline = el.getAttribute('data-error-inline'); let errorHeading = el.getAttribute('data-error-heading'); (elParent !== null) ? changeCss(`.${elParent} .clickable`, '!border-red-400') : changeCss(el, '!border-red-400', 'add', true); el.focus(); if (errorMessage) { (showErrorInline) ? unhide(`.${elName}-inline-error`) : showNotification(errorHeading, errorMessage, 'error'); } let listenerObj = { 'el': el, 'elParent': elParent, 'elName': elName, 'showErrorInline': showErrorInline }; el.addEventListener('keyup', clearErrors.bind(null, listenerObj), false); hasError++; throw BreakException; } }); } catch (e) { } return hasError === 0; }; /** * Allow only numeric input in a text input field. * @param {event} event - The event object. Key events. * @param {boolean} with_dots - Should dots be allowed in the input. Useful when entering decimals. * @return {void} * @see {@link https://bladewindui.com/extra/helper-functions#isnumberkey} * @example * onkeypress="return isNumberKey(event)" */ const isNumberKey = (event, with_dots = 1) => { let acceptedKeys = (with_dots === 1) ? /[\d\b\\.]/ : /\d\b/; if (!event.key.toString().match(acceptedKeys) && event.keyCode !== 8 && event.keyCode !== 9) { event.preventDefault(); } }; /** * Execute a user-defined function. * @param {string} func - The function to execute, with or without parameters. * @return {void} */ const callUserFunction = (func) => { if (func !== '' && func !== undefined) eval(func); }; /** * Serialize a form into key/value pairs for ajax submission. * @param {string} form - The form to serialize. * @return {object} The serialized object. * @see {@link https://bladewindui.com/extra/helper-functions#serialize} */ const serialize = (form) => { let data = new FormData(domEl(form)); let obj = {}; for (let [key, value] of data) { /*** ** in some cases the form field name and api parameter differ, and you want to ** display a more meaningful error message from Laravels $errors.. set an attr ** data-serialize-as on the form field. that value will be used instead of [key] ** example: input name="contact_name" data-serialize-as="contact_person" ** Laravel will display contact name field is required but contact_person : value ** will be sent to the API **/ let thisElement = document.getElementsByName(key); let serializeAs = thisElement[0].getAttribute('data-serialize-as'); obj[serializeAs ?? key] = value; } return obj; }; /** * Check if string contains a keyword. * @param {string} str - The string to check for keyword existence. * @param {string} keyword - The keyword to check for. * @return {boolean} True if string contains keyword. False if it does not. * @see {@link https://bladewindui.com/extra/helper-functions#stringcontains} */ const stringContains = (str, keyword) => { if (typeof str !== 'string') return false; return (str.indexOf(keyword) !== -1); }; var doNothing = () => { } /** * Modify the css for DOM elements of the same type. * @param {string} elements - The class name of ID of the DOM elements to modify. * @param {string} css - Comma separated list of css classes to apply to . * @param {string} mode - Add|Remove. Determines if should be added or removed from . * @return {void} * @see {@link https://bladewindui.com/extra/helper-functions#changecssfordomarray} */ const changeCssForDomArray = (elements, css, mode = 'add') => { if (domEls(elements).length > 0) { domEls(elements).forEach((el) => { changeCss(el, css, mode, true); }); } }; /** * Animate an element. * @param {string} element - The css class (name) of the element to animate. * @param {string} animation - The css animation class to be applied. * @return {void} * @see {@link https://bladewindui.com/extra/helper-functions#animatecss} */ const animateCSS = (element, animation) => new Promise((resolve, reject) => { const animationName = `animate__${animation}`; const node = domEl(element); if (node) { node.classList.remove('hidden'); node.classList.add('animate__animated', animationName); document.documentElement.style.setProperty('--animate-duration', '.5s'); function handleAnimationEnd(event) { node.classList.remove('animate__animated', animationName); event.stopPropagation(); resolve('Animation ended'); } node.addEventListener('animationend', handleAnimationEnd, {once: true}); } }); /** * Display a modal. * @param {string} element - The css class (name) of the modal. * @return {void} * @see {@link https://bladewindui.com/extra/helper-functions#showmodal} */ const showModal = (element) => { unhide(`.bw-${element}-modal`); document.body.classList.add('overflow-hidden'); domEl(`.bw-${element}-modal`).focus(); let index = (currentModal.length === 0) ? 0 : currentModal.length + 1; animateCSS(`.bw-${element}`, 'zoomIn').then(() => { currentModal[index] = element; }); }; /** * Trap focus within an open modal to prevent scrolling behind the modal. * @param {Event} event - The event object. * @return {void} */ const trapFocusInModal = (event) => { let modalName = currentModal[(currentModal.length - 1)]; if (modalName !== undefined) { const focusableElements = domEls(`.bw-${modalName}-modal input:not([type='hidden']):not([class*='hidden']), .bw-${modalName}-modal button:not([class*="hidden"]), .bw-${modalName}-modal a:not([class*="hidden"])`); const firstElement = focusableElements[0]; const lastElement = focusableElements[focusableElements.length - 1]; if (event.key === 'Tab') { if (event.shiftKey && document.activeElement === firstElement) { event.preventDefault(); lastElement.focus(); } else if (!event.shiftKey && document.activeElement === lastElement) { event.preventDefault(); firstElement.focus(); } } } }; /** * Hide a modal. * @param {string} element - The css class (name) of the modal. * @return {void} * @see {@link https://bladewindui.com/extra/helper-functions#hidemodal} */ const hideModal = (element) => { animateCSS(`.bw-${element}`, 'zoomOut').then(() => { hide(`.bw-${element}-modal`); currentModal.pop(); document.body.classList.remove('overflow-hidden'); domEl(`.bw-${element}-modal`).removeEventListener('keydown', trapFocusInModal); }); }; /** * Display the spinning icon on a button. * @param {string} element - The css class (name) of the button. * @return {void} * @see {@link https://bladewindui.com/extra/helper-functions#showbuttonspinner} */ const showButtonSpinner = (element) => { unhide(`${element} .bw-spinner`); }; /** * Hide the spinning icon on a button. * @param {string} element - The css class (name) of the button. * @return {void} * @see {@link https://bladewindui.com/extra/helper-functions#hidebuttonspinner} */ const hideButtonSpinner = (element) => { hide(`${element} .bw-spinner`); }; /** * Show the action buttons on a modal. * @param {string} element - The css class (name) of the modal. * @return {void} * @see {@link https://bladewindui.com/extra/helper-functions#showmodalactionbuttons} */ const showModalActionButtons = (element) => { unhide(`.bw-${element} .modal-footer`); }; /** * Hide the action buttons on a modal. * @param {string} element - The css class (name) of the modal. * @return {void} * @see {@link https://bladewindui.com/extra/helper-functions#hidemodalactionbuttons} */ const hideModalActionButtons = (element) => { hide(`.bw-${element} .modal-footer`); }; /** * Alias for unhide(). * @see {@link https://bladewindui.com/extra/helper-functions#show} */ const show = (element, elementIsDomObject = false) => { unhide(element, elementIsDomObject); }; /** * Add a key/value pair to client's storage. * @param {string} key - The key. * @param {string} val - The value corresponding to key. * @param {string} storageType - The storage key/val should be added to. sessionStorage | localStorage. * @return {void} * @see {@link https://bladewindui.com/extra/helper-functions#addtostorage} */ const addToStorage = (key, val, storageType = 'localStorage') => { if (window.localStorage || window.sessionStorage) { (storageType === 'localStorage') ? localStorage.setItem(key, val) : sessionStorage.setItem(key, val); } }; /** * Retrieve a value from client's storage based on its key. * @param {string} key - The key. * @param {string} storageType - The storage to retrieve value from. sessionStorage | localStorage. * @return {string} The value of * @see {@link https://bladewindui.com/extra/helper-functions#getfromstorage} */ const getFromStorage = (key, storageType = 'localStorage') => { if (window.localStorage || window.sessionStorage) { return (storageType === 'localStorage') ? localStorage.getItem(key) : sessionStorage.getItem(key); } }; /** * Delete a key/value pair from client's storage. * @param {string} key - The key. * @param {string} storageType - The storage to remove key/val from. sessionStorage | localStorage. * @return {void} * @see {@link https://bladewindui.com/extra/helper-functions#removefromstorage} */ const removeFromStorage = (key, storageType = 'localStorage') => { if (window.localStorage || window.sessionStorage) { (storageType === 'localStorage') ? localStorage.removeItem(key) : sessionStorage.removeItem(key); } }; /** * Navigate to a tab. * @param {string} element - The css class (name) of the tab to navigate to. * @param {string} colour - The colour of the tab. * @param {string} scope - The scope within which to find . More like a parent element. * @return {(void|boolean)} */ const goToTab = (element, colour, scope) => { let scope_ = scope.replace(/-/g, '_'); let tabContent = domEl('.bw-tc-' + element); if (tabContent === null) return false; changeCssForDomArray(`.${scope}-headings li.atab span`, `${colour}, is-active`, 'remove'); changeCssForDomArray(`.${scope}-headings li.atab span`, 'is-inactive'); changeCss(`.atab-${element} span`, 'is-inactive', 'remove'); changeCss(`.atab-${element} span`, `is-active, ${colour}`); domEls(`.${scope_}-tab-contents > div.atab-content`).forEach((element) => { hide(element, true); }); unhide(tabContent, true); }; /** * Get the offsetWidth of a prefix/suffix label * @param {string} element - The css class (name) of the prefix/suffix field. * @return {int} */ const getPrefixSuffixOffsetWidth = (element) => { let ps_element = domEl(element); const clone = ps_element.cloneNode(true); clone.style.visibility = 'hidden'; clone.style.position = 'absolute'; clone.style.display = 'block'; document.body.appendChild(clone); let offsetWidth = clone.offsetWidth; document.body.removeChild(clone); return offsetWidth; }; /** * Position a prefix in an input field. * @param {string} element - The css class (name) of the input field. * @param {string} mode - Event to trigger the positioning. * @return {void} */ const positionPrefix = (element, mode = 'blur') => { let transparency = domEl(`.dv-${element} .prefix`).getAttribute('data-transparency'); let offset = (transparency === '1') ? -5 : 7; let prefixWidth = ((getPrefixSuffixOffsetWidth(`.dv-${element} .prefix`)) + offset) * 1; let defaultLabelLeftPos = '0.875rem'; let inputField = domEl(`input.${element}`); let labelField = domEl(`.dv-${element} label`); if (mode === 'blur') { if (labelField) { labelField.style.left = (inputField.value === '') ? `${prefixWidth}px` : defaultLabelLeftPos; } domEl(`input.${element}`).style.paddingLeft = `${prefixWidth}px`; inputField.addEventListener('focus', (event) => { positionPrefix(element, event.type); // for backward compatibility where {once:true} is not supported inputField.removeEventListener('focus', positionPrefix); }, {once: true}); } else if (mode === 'focus') { if (labelField) labelField.style.left = defaultLabelLeftPos; inputField.addEventListener('blur', (event) => { positionPrefix(element, event.type); // for backward compatibility where {once:true} is not supported inputField.removeEventListener('blur', positionPrefix); }, {once: true}); } }; /** * Position a suffix in an input field. * @param {string} element - The css class (name) of the input field. * @param {string} mode - Event to trigger the positioning. * @return {void} */ const positionSuffix = (element) => { let transparency = domEl(`.dv-${element} .suffix`).getAttribute('data-transparency'); let offset = (transparency === '1') ? -5 : 7; let suffixWidth = ((getPrefixSuffixOffsetWidth(`.dv-${element} .suffix`)) + offset) * 1; domEl(`input.${element}`).style.paddingRight = `${suffixWidth}px`; }; /** * Show or hide password in a password input fiield. * @param {string} element - The css class (name) of the input field. * @param {string} mode - Show or hide. * @return {void} */ const togglePassword = (element, mode) => { let inputField = domEl(`input.${element}`); if (mode === 'show') { inputField.setAttribute('type', 'text'); unhide(`.dv-${element} .suffix svg.hide-pwd`); hide(`.dv-${element} .suffix svg.show-pwd`); } else { inputField.setAttribute('type', 'password') unhide(`.dv-${element} .suffix svg.show-pwd`); hide(`.dv-${element} .suffix svg.hide-pwd`); } }; /** * Partition an array into two separate arrays. * @param {array} arr - The array to be split. * @param {function} fn - The evaluation function to run on each element > should return true/false for each element * @return {[array, array]} */ const partition = (arr, fn) => { return arr.reduce( (acc, val, i, arr) => { acc[fn(val, i, arr) ? 0 : 1].push(val); return acc; }, [[], []] ); } /** * Filter a table based on keyword. * @param {string} keyword - The keyword to filter table by. * @param {string} table - The css class (name) of the table to filter. * @param {null} field - The field to search. * @param {array} tableData - The data to filter * @return {void} */ const filterTable = (keyword, table, field, tableData) => { if (tableData === null) { // not dynamic table, search row content domEls(`${table} tbody tr`).forEach((tr) => { (tr.innerText.toLowerCase().includes(keyword.toLowerCase())) ? unhide(tr, true) : hide(tr, true); }); return; } let currentPage = domEl(table).getAttribute('data-current-page'); const [showList, hideList] = partition(tableData, (row) => { if (field) { return row[field].toLowerCase().match(keyword.toLowerCase()); } else { return Object.values(row).toString().toLowerCase().match(keyword.toLowerCase()); } }); hideList.forEach((row) => { let thisRow = (currentPage !== null) ? `${table} tbody tr[data-id="${row.id}"][data-page="${currentPage}"]` : `${table} tbody tr[data-id="${row.id}"]`; hide(domEl(thisRow), true); }); showList.forEach((row) => { let thisRow = (currentPage !== null) ? `${table} tbody tr[data-id="${row.id}"][data-page="${currentPage}"]` : `${table} tbody tr[data-id="${row.id}"]`; const elem = domEl(thisRow); if (elem) { unhide(elem, true); } }); }; /** * Filter a table based on keyword, . * @param {string} keyword - The keyword to filter table by. * @param {string} table - The css class (name) of the table to filter. * @param {string} field - The field to search. * @param {int} delay - Number of milliseconds to debouce the search. * @return {function} - The debounced search function to be run */ let debounceTimerId; const filterTableDebounced = (keyword, table, field = null, delay = 0, minLength = 0, tableData = {}) => { let currentPage = domEl(table).getAttribute('data-current-page'); let rows = (currentPage !== null) ? `${table} tbody tr.hidden[data-page="${currentPage}"]` : `${table} tbody tr.hidden`; if (keyword.length >= minLength) { return (...args) => { clearTimeout(debounceTimerId); debounceTimerId = setTimeout(() => filterTable(keyword, table, field, tableData), delay); }; } else { return (...args) => { clearTimeout(debounceTimerId); debounceTimerId = setTimeout(() => { domEls(rows).forEach((tr) => { unhide(tr, true); }); }, delay); }; } }; /** * Remove trailing comma from string. * @param {string} element - The input field to remove trailing comma from. * @return {void} */ const stripComma = (element) => { if (element.value.startsWith(',')) { element.value = element.value.replace(/^,/, ''); } const event = new Event('change', { bubbles: true, cancelable: true }); element.dispatchEvent(event); }; /** * Select a tag. * @param {string} value - The value or uuid to pass when tag is selected. * @param {string} name - The name of the tag. * @return {void} */ const selectTag = (value, name) => { let input = domEl(`input[name="${name}"]`); let max_selection = input.getAttribute('data-max-selection'); let tag = domEl(`.bw-${name}-${value}`); let css = tag.getAttribute('class'); if (input.value.includes(value)) { // remove let keyword = `(,?)${value}`; input.value = input.value.replace(input.value.match(keyword)[0], ''); changeCss(tag, css.match(/bg-[\w]+-500/)[0], 'remove', true); changeCss(tag, (css.match(/bg-[\w]+-500/)[0]).replace('500', '200/80'), 'add', true); changeCss(tag, css.match(/text-[\w]+-50/)[0], 'remove', true); changeCss(tag, (css.match(/text-[\w]+-50/)[0]).replace('50', '600'), 'add', true); } else { // add let total_selected = (input.value === '') ? 0 : input.value.split(',').length; if (total_selected < max_selection) { input.value += `,${value}`; changeCss(tag, css.match(/bg-[\w]+-200\/80/)[0], 'remove', true); changeCss(tag, (css.match(/bg-[\w]+-200\/80/)[0]).replace('200/80', '500'), 'add', true); changeCss(tag, css.match(/text-[\w]+-600/)[0], 'remove', true); changeCss(tag, (css.match(/text-[\w]+-600/)[0]).replace('600', '50'), 'add', true); } else { showNotification(input.getAttribute('data-error-heading'), input.getAttribute('data-error-message'), 'error'); } } stripComma(input) }; /** * Highlight selected tags. * @param {string} values - Comma separated list of values corresponding to tags to highlight. * @param {string} name - The name of the tags. * @return {void} */ const highlightSelectedTags = (values, name) => { if (values !== '') { let valuesArray = values.split(','); for (let x = 0; x < valuesArray.length; x++) { selectTag(valuesArray[x].trim(), name); } } }; /** * Compare two dates and display an error if second date is less than first date. * This is used in the range Datepicker component to ensure dates make sense. * @param {string} element1 - The first date input field. * @param {string} element2 - The second date input field. * @param {string} message - Error message to display if validation fails. * @param {boolean} inline - Display error inline or in a notification component. * @return {boolean} True if date 2 is greater than date 1. * @see {@link https://bladewindui.com/extra/helper-functions#comparedates} */ const compareDates = (element1, element2, message, inline) => { let date1El = domEl(`.${element1}`); let date2El = domEl(`.${element2}`); setTimeout(() => { let startDate = new Date(date1El.value).getTime(); let endDate = new Date(date2El.value).getTime(); if (startDate !== '' && endDate !== '') { if (startDate > endDate) { changeCss(date2El, '!border-red-400', 'add', true); (inline !== 1) ? showNotification('', message, 'error') : domEl(`.error-${element1}${element2}`).innerHTML = message; return false; } else { changeCss(date2El, '!border-red-400', 'remove', true); return true; } } }, 100); }; /** * Validate for minimum and maximum values of an input field * @param {number} min - The minimum value. * @param {number} max - The maximum value. * @param {string} element - The input field to validate. * @param {boolean} enforce_limits - Ensure input does not exceed maximum or go below minimum * @return {void} */ const checkMinMax = (min, max, element, enforce_limits = false) => { let field = domEl(`.${element}`); let minimum = parseInt(min); let maximum = parseInt(max); let errorMessage = field.getAttribute('data-error-message'); let showErrorInline = field.getAttribute('data-error-inline'); let errorHeading = field.getAttribute('data-error-heading'); if (field.value !== '' && ((!isNaN(minimum) && field.value < minimum) || (!isNaN(maximum) && field.value > maximum))) { if (enforce_limits) { if (field.value < minimum) field.value = minimum; if (field.value > maximum) field.value = maximum; } else { changeCss(field, '!border-red-400', 'add', true); if (errorMessage) { (showErrorInline) ? unhide(`.${element}-inline-error`) : showNotification(errorHeading, errorMessage, 'error'); } } } else { if (errorMessage) hide(`.${element}-inline-error`); changeCss(field, '!border-red-400', 'remove', true); } }; /** * Display a clear button in an input field that has text. * @param {string} element - The css class (name) of the input field. * @return {void} */ const makeClearable = (element) => { let field = domEl(`.${element}`); let suffixElement = domEl(`.${element}-suffix svg`); let tableElement = element.replace('bw_search_', 'table.'); let clearingFunction = (domEl(tableElement)) ? field.getAttribute('oninput').replace('this.value', "''") : ''; if (!suffixElement.getAttribute('onclick')) { suffixElement.setAttribute('onclick', `domEl(\'.${element}\').value=''; hide(this, true); ${clearingFunction}`); } (field.value !== '') ? unhide(suffixElement, true) : hide(suffixElement, true); }; /** * Convert a selected file to base64. * @param {string} file - Url of selected file. * @param {string} element - The input field to write the base64 string to. * @return {void} */ const convertToBase64 = (file, element) => { const reader = new FileReader(); reader.onloadend = () => { const base64String = reader.result;//.replace('data:', '').replace(/^.+,/, ''); domEl(element).value = base64String; }; reader.readAsDataURL(file); }; /** * Check if selected file size falls within allowed file size. * @param {number} fileSize - The selected file size. * @param {number} maxSize - THe maximum file size. * @return {boolean} True if if less than */ const allowedFileSize = (fileSize, maxSize) => { return (fileSize <= maxSize * 1000000); }; /** * Set the value of a datepicker * @return {void} * @param {string} elName - name of the input field to update * @param {string} date - new value to set */ const setDatepickerValue = (elName, date) => { let input = domEl(`.${elName}`); if (!input) { console.error(`No datepicker found with the name ${elName}`); return; } // let alpineComponent = document.querySelector('[x-data]').__x.$data; if (!input._x_model) { console.error(`Alpine.js component not found for element ${elName}`); return; } input._x_model.set(date); };