import { assertNotNull } from './utils/assert'; import { $, $$, disableEl, enableEl, removeEl } from './utils/dom'; import { delegate, leftClick } from './utils/events'; export interface InputDuplicatorOptions { addButtonSelector: string; fieldSelector: string; maxInputCountSelector: string; removeButtonSelector: string; } export function inputDuplicatorCreator({ addButtonSelector, fieldSelector, maxInputCountSelector, removeButtonSelector, }: InputDuplicatorOptions) { const addButton = $<HTMLButtonElement>(addButtonSelector); if (!addButton) { return; } const form = assertNotNull(addButton.closest('form')); const fieldRemover = (event: MouseEvent, target: HTMLElement) => { event.preventDefault(); // Prevent removing the final field element to not "brick" the form const existingFields = $$(fieldSelector, form); if (existingFields.length <= 1) { return; } removeEl(assertNotNull(target.closest<HTMLElement>(fieldSelector))); enableEl(addButton); }; delegate(form, 'click', { [removeButtonSelector]: leftClick(fieldRemover), }); const maxOptionCountElement = assertNotNull($(maxInputCountSelector, form)); const maxOptionCount = parseInt(maxOptionCountElement.innerHTML, 10); addButton.addEventListener('click', e => { e.preventDefault(); const existingFields = $$<HTMLElement>(fieldSelector, form); let existingFieldsLength = existingFields.length; if (existingFieldsLength < maxOptionCount) { // The last element matched by the `fieldSelector` will be the last field, make a copy const prevField = existingFields[existingFieldsLength - 1]; const prevFieldCopy = prevField.cloneNode(true) as HTMLElement; $$<HTMLInputElement>('input', prevFieldCopy).forEach(prevFieldCopyInput => { // Reset new input's value prevFieldCopyInput.value = ''; prevFieldCopyInput.removeAttribute('value'); // Increment sequential attributes of the input prevFieldCopyInput.setAttribute('name', prevFieldCopyInput.name.replace(/\d+/g, `${existingFieldsLength}`)); prevFieldCopyInput.setAttribute('id', prevFieldCopyInput.id.replace(/\d+/g, `${existingFieldsLength}`)); }); prevField.insertAdjacentElement('afterend', prevFieldCopy); existingFieldsLength++; } // Remove the button if we reached the max number of options if (existingFieldsLength >= maxOptionCount) { disableEl(addButton); } }); }