UNPKG

digitalmarketplace-frontend

Version:

Digital Marketplace Frontend contains assets and components used in Digital Marketplace projects

187 lines (185 loc) 9.01 kB
class ListInput { static moduleName = 'dm-list-input'; static itemContainerClass = 'dm-list-input__item-container'; static hiddenItemClass = 'dm-list-input__item--hidden'; static visibleItemClass = 'dm-list-input__item--visible'; static itemInputClass = 'dm-list-input__item-input'; static itemErrorClass = 'dm-list-input__item--error'; static itemErrorMsgClass = 'dm-list-input-error-message'; static itemCounterClass = 'dm-list-input__counter'; static inputErrorClass = 'govuk-input--error'; static removeButtonClass = 'dm-list-input__item-remove'; static hiddenRemoveButtonClass = 'dm-list-input__item-remove--hidden'; static formGroupErrorClass = 'govuk-form-group--error'; static hiddenAddButtonClass = 'dm-list-input__item-add--hidden'; static addButtonRemainingClass = 'dm-list-input__js-remaining-counter'; $module; $allVisibleItems; $addAnotherButton; $allItems; constructor($module) { this.$module = $module; this.$allVisibleItems = this.findVisibleItems(); this.$addAnotherButton = this.$module.find('.dm-list-input__item-add'); this.$allItems = this.$module.find('.dm-list-input__item'); } init() { this.hideEmptyItems(); this.updateAllCounters(); this.addRemoveClickEvent(); this.toggleAddAnotherButton(); this.addAddClickEvent(); } findVisibleItems() { return this.$module.find('.dm-list-input__item--visible'); } // Hide all items that do not have a value (except for the first one, or the first two if no items have a value) hideEmptyItems() { let numberOfVisibleEmptyItems = 0; let numberOfFilledInItems = 0; this.$allItems.each((_index, item) => { const $item = $(item); const $input = $item.find('.' + ListInput.itemInputClass); const $removeButton = $item.find('.' + ListInput.removeButtonClass); if (!$input.attr('value')) { if (numberOfVisibleEmptyItems === 0) { $removeButton.removeClass(ListInput.hiddenRemoveButtonClass); } else if (numberOfVisibleEmptyItems === 1 && numberOfFilledInItems === 0) { $removeButton.removeClass(ListInput.hiddenRemoveButtonClass); } else { $item.addClass(ListInput.hiddenItemClass); $item.removeClass(ListInput.visibleItemClass); $removeButton.addClass(ListInput.hiddenRemoveButtonClass); $input.attr('disabled', 'true'); } numberOfVisibleEmptyItems += 1; } else { $item.removeClass(ListInput.hiddenItemClass); $item.addClass(ListInput.visibleItemClass); $removeButton.removeClass(ListInput.hiddenRemoveButtonClass); numberOfFilledInItems += 1; } }); this.$allVisibleItems = this.findVisibleItems(); } // Adds an event listener to module to listen for any // click events fired by the items "Remove" button addRemoveClickEvent() { this.$allItems.each((_index, item) => { const $item = $(item); const $input = $item.find('.' + ListInput.itemInputClass); const $removeButton = $item.find('.' + ListInput.removeButtonClass); $removeButton.on('click', () => { $input.val(''); $input.removeAttr('value'); $input.attr('disabled', 'true'); $removeButton.addClass(ListInput.hiddenRemoveButtonClass); $item.addClass(ListInput.hiddenItemClass); $item.removeClass(ListInput.visibleItemClass); this.$allVisibleItems = this.findVisibleItems(); if ($item.hasClass(ListInput.itemErrorClass)) { $item.removeClass(ListInput.itemErrorClass); const $errorFormGroup = $item.find('.' + ListInput.formGroupErrorClass); $errorFormGroup.removeClass(ListInput.formGroupErrorClass); $errorFormGroup.remove('.' + ListInput.itemErrorMsgClass); const $errorInput = $errorFormGroup.find('.' + ListInput.inputErrorClass); const inputId = $errorInput.attr('id'); const inputDescribedBy = $errorInput.attr('aria-describedby'); $errorInput.attr('aria-describedby', inputDescribedBy.replace(inputId + '-error', '')); $errorInput.removeClass(ListInput.inputErrorClass); } // Hide Remove buttons if there is only one item left if (this.$allVisibleItems.length === 1) { const $removeButtons = this.$module.find('.' + ListInput.removeButtonClass); $removeButtons.each((_index, button) => { $(button).addClass(ListInput.hiddenRemoveButtonClass); }); $(this.$allVisibleItems.get(0)).find('input').trigger('focus'); } else { // Set focus to the next input const $nextVisibleItem = ListInput.getSibling('next', $item, '.' + ListInput.visibleItemClass); if ($nextVisibleItem) { $nextVisibleItem.find('input').trigger('focus'); } else { const $previousVisibleItem = ListInput.getSibling('previous', $item, '.' + ListInput.visibleItemClass); $previousVisibleItem.find('input').trigger('focus'); } } this.updateAllCounters(); this.toggleAddAnotherButton(); }); }); } // Used to update each item's label and remove button hidden text updateCounters() { this.$allVisibleItems.each((index, item) => { $(item).find('.' + ListInput.itemCounterClass).each((_index, counter) => { $(counter).text(index + 1); }); }); } // Used to update "Add another" buttons "Remaining" counter // and sets focus to the new additional input updateRemainingCounter() { const $visibleItems = this.$allVisibleItems; const totalItems = this.$allItems.length; this.$module.find('.' + ListInput.addButtonRemainingClass).text(totalItems - $visibleItems.length); } addAddClickEvent() { this.$addAnotherButton.on('click', () => { const $firstHiddenItem = this.$module.find('.' + ListInput.hiddenItemClass).first(); const $firstHiddenInput = $firstHiddenItem.find('.' + ListInput.itemInputClass); if ($firstHiddenItem.length) { $firstHiddenInput.removeAttr('disabled'); this.$module.find('.' + ListInput.itemContainerClass).append($firstHiddenItem); $firstHiddenItem.removeClass(ListInput.hiddenItemClass); $firstHiddenItem.addClass(ListInput.visibleItemClass); this.$allVisibleItems = this.findVisibleItems(); this.updateAllCounters(); $firstHiddenItem.find('.' + ListInput.removeButtonClass).removeClass(ListInput.hiddenRemoveButtonClass); $firstHiddenInput.trigger('focus'); this.toggleAddAnotherButton(); // Show Remove buttons if there is more one item if (this.$allVisibleItems.length > 1) { this.$module.find('.' + ListInput.removeButtonClass).each((_index, button) => { $(button).removeClass(ListInput.hiddenRemoveButtonClass); }); } } }); } toggleAddAnotherButton() { const $firstHiddenItem = this.$module.find('.' + ListInput.hiddenItemClass); if ($firstHiddenItem.length) { this.$addAnotherButton.removeClass(ListInput.hiddenAddButtonClass); } else { this.$addAnotherButton.addClass(ListInput.hiddenAddButtonClass); } } updateAllCounters() { this.updateCounters(); this.updateRemainingCounter(); } static getSibling(direction, elem, selector) { // Get the next sibling element let sibling = (direction === 'next') ? elem.next() : elem.prev(); // If there's no selector, return the first sibling if (!selector) return sibling; // If the sibling matches our selector, use it // If not, jump to the next sibling and continue the loop while (sibling.length) { if (sibling.is(selector)) return sibling; sibling = (direction === 'next') ? sibling.next() : sibling.prev(); } } } export { ListInput }; //# sourceMappingURL=list-input.mjs.map