import { Utils } from '../../src/utils'; export class Forms { /** * Checks if the label has validation and apply * the correct class and styles * @param textfield */ static validateField(textfield: HTMLInputElement) { if (!textfield) { console.error('No text field element found'); return; } const hasLength = textfield.getAttribute('data-length') !== null; const lenAttr = parseInt(textfield.getAttribute('data-length')); const len = textfield.value.length; if ( len === 0 && textfield.validity.badInput === false && !textfield.required && textfield.classList.contains('validate') ) { textfield.classList.remove('invalid'); } else if (textfield.classList.contains('validate')) { // Check for character counter attributes if ( (textfield.validity.valid && hasLength && len <= lenAttr) || (textfield.validity.valid && !hasLength) ) { textfield.classList.remove('invalid'); } else { textfield.classList.add('invalid'); } } } /** * Resizes the given TextArea after updating the * value content dynamically. * @param e EventTarget */ static textareaAutoResize(e: EventTarget) { const textarea = e as HTMLTextAreaElement; // if (!textarea) { // console.error('No textarea element found'); // return; // } // Textarea Auto Resize let hiddenDiv: HTMLDivElement = document.querySelector('.hiddendiv'); if (!hiddenDiv) { hiddenDiv = document.createElement('div'); hiddenDiv.classList.add('hiddendiv', 'common'); document.body.append(hiddenDiv); } const style = getComputedStyle(textarea); // Set font properties of hiddenDiv const fontFamily = style.fontFamily; //textarea.css('font-family'); const fontSize = style.fontSize; //textarea.css('font-size'); const lineHeight = style.lineHeight; //textarea.css('line-height'); // Firefox can't handle padding shorthand. const paddingTop = style.paddingTop; //getComputedStyle(textarea).css('padding-top'); const paddingRight = style.paddingRight; //textarea.css('padding-right'); const paddingBottom = style.paddingBottom; //textarea.css('padding-bottom'); const paddingLeft = style.paddingLeft; //textarea.css('padding-left'); if (fontSize) hiddenDiv.style.fontSize = fontSize; //('font-size', fontSize); if (fontFamily) hiddenDiv.style.fontFamily = fontFamily; //css('font-family', fontFamily); if (lineHeight) hiddenDiv.style.lineHeight = lineHeight; //css('line-height', lineHeight); if (paddingTop) hiddenDiv.style.paddingTop = paddingTop; //ss('padding-top', paddingTop); if (paddingRight) hiddenDiv.style.paddingRight = paddingRight; //css('padding-right', paddingRight); if (paddingBottom) hiddenDiv.style.paddingBottom = paddingBottom; //css('padding-bottom', paddingBottom); if (paddingLeft) hiddenDiv.style.paddingLeft = paddingLeft; //css('padding-left', paddingLeft); // Set original-height, if none if (!textarea.hasAttribute('original-height')) textarea.setAttribute('original-height', textarea.getBoundingClientRect().height.toString()); if (textarea.getAttribute('wrap') === 'off') { hiddenDiv.style.overflowWrap = 'normal'; // ('overflow-wrap', 'normal') hiddenDiv.style.whiteSpace = 'pre'; //.css('white-space', 'pre'); } hiddenDiv.innerText = textarea.value + '\n'; hiddenDiv.innerHTML = hiddenDiv.innerHTML.replace(/\n/g, '
'); // When textarea is hidden, width goes crazy. // Approximate with half of window size if (textarea.offsetWidth > 0 && textarea.offsetHeight > 0) { hiddenDiv.style.width = textarea.getBoundingClientRect().width + 'px'; // ('width', textarea.width() + 'px'); } else { hiddenDiv.style.width = window.innerWidth / 2 + 'px'; //css('width', window.innerWidth / 2 + 'px'); } // Resize if the new height is greater than the // original height of the textarea const originalHeight = parseInt(textarea.getAttribute('original-height')); const prevLength = parseInt(textarea.getAttribute('previous-length')); if (isNaN(originalHeight)) return; if (originalHeight <= hiddenDiv.clientHeight) { textarea.style.height = hiddenDiv.clientHeight + 'px'; //css('height', hiddenDiv.innerHeight() + 'px'); } else if (textarea.value.length < prevLength) { // In case the new height is less than original height, it // means the textarea has less text than before // So we set the height to the original one textarea.style.height = originalHeight + 'px'; } textarea.setAttribute('previous-length', (textarea.value || '').length.toString()); } static Init() { if (typeof document !== 'undefined') document?.addEventListener('DOMContentLoaded', () => { document.addEventListener('change', (e: KeyboardEvent) => { const target = e.target; if (target instanceof HTMLInputElement) { if (target.value.length !== 0 || target.getAttribute('placeholder') !== null) { for (const child of target.parentNode.children) { if (child.tagName == 'label') { child.classList.add('active'); } } } Forms.validateField(target); } }); document.addEventListener('keyup', (e: KeyboardEvent) => { const target = e.target; // Radio and Checkbox focus class if (target instanceof HTMLInputElement && ['radio', 'checkbox'].includes(target.type)) { // TAB, check if tabbing to radio or checkbox. if (Utils.keys.TAB.includes(e.key)) { target.classList.add('tabbed'); target.addEventListener('blur', () => target.classList.remove('tabbed'), { once: true }); } } }); document .querySelectorAll('.materialize-textarea') .forEach((textArea: HTMLTextAreaElement) => { Forms.InitTextarea(textArea); }); // File Input Path document .querySelectorAll('.file-field input[type="file"]') .forEach((fileInput: HTMLInputElement) => { Forms.InitFileInputPath(fileInput); }); }); } static InitTextarea(textarea: HTMLTextAreaElement) { // Save Data in Element textarea.setAttribute('original-height', textarea.getBoundingClientRect().height.toString()); textarea.setAttribute('previous-length', (textarea.value || '').length.toString()); Forms.textareaAutoResize(textarea); textarea.addEventListener('keyup', (e) => Forms.textareaAutoResize(e.target)); textarea.addEventListener('keydown', (e) => Forms.textareaAutoResize(e.target)); } static InitFileInputPath(fileInput: HTMLInputElement) { fileInput.addEventListener('change', () => { const fileField = fileInput.closest('.file-field'); const pathInput = fileField.querySelector('input.file-path'); const files = fileInput.files; const filenames = []; for (let i = 0; i < files.length; i++) { filenames.push(files[i].name); } pathInput.value = filenames.join(', '); pathInput.dispatchEvent( new Event('change', { bubbles: true, cancelable: true, composed: true }) ); }); } }