UNPKG

ccs-digitalmarketplace-govuk-frontend

Version:

Digital Marketplace GOV.UK Frontend contains the code you need to start building a user interface for Digital Marketplace.

256 lines (203 loc) 8.11 kB
const MAX_NUMBER_OF_ROWS = 3 class ComplianceCommunicationAttachmentListRowInput { constructor ($row, column) { const $column = $row.find(`.govuk-grid-column-one-half:nth-of-type(${column})`) this.$input = $column.find('input') this.$label = $column.find('.govuk-label') this.$hint = $column.find('.govuk-hint') } updateIndex (newIndex) { const newName = this.$input.attr('name').replace(/\d+/, newIndex) const newId = `input-${newName}` this.$label.attr('for', newId) this.$hint.attr('id', `${newId}-hint`) this.$input.attr('id', newId) this.$input.attr('name', newName) this.$input.attr('aria-describedby', `${newId}-hint`) } makeInteractable () { this.$input.removeAttr('tabindex') } } class ComplianceCommunicationAttachmentListRequiredInput { constructor ($row) { this.$requiredSection = $row.find('.dm-compliance-communication__attachments-item-required') this.$input = this.$requiredSection.find('.govuk-checkboxes__item > input') this.$label = this.$requiredSection.find('.govuk-checkboxes__item > .govuk-label') } isChecked () { return this.$input.is(':checked') } updateIndex (newIndex) { const newName = this.$input.attr('name').replace(/\d+/, newIndex) const newId = `input-${newName}` this.$label.attr('for', newId) this.$input.attr('id', newId) this.$input.attr('name', newName) } checkRow () { this.$requiredSection.toggleClass('govuk-visually-hidden', true) this.$input.prop('checked', true) this.$input.attr('tabindex', -1) this.$input.attr('tabindex', -1) } } class ComplianceCommunicationAttachmentListRowRemoveButton { constructor (attachmentListRow, $row) { this.attachmentListRow = attachmentListRow this.$button = $row.find('.dm-compliance-communication__attachments-item-remove') this.$removeButtonCounter = this.$button.find('.dm-compliance-communication__attachments-item-remove-counter') } init () { this.toggleVisibility(true) this.$button.on('click', () => { this.attachmentListRow.removeRow() }) } toggleVisibility (isShown) { this.$button.toggleClass('govuk-visually-hidden', !isShown) if (isShown) { this.$button.removeAttr('tabindex') } else { this.$button.attr('tabindex', -1) } } updateIndex (newIndex) { this.$removeButtonCounter.text(newIndex + 1) } } class ComplianceCommunicationAttachmentListRow { constructor (attachmentList, index, $row) { this.$row = $row this.attachmentList = attachmentList this.index = index this.$legendCounter = this.$row.find('.dm-compliance-communication__attachments-item-legend-counter') this.attachmentListRowFileInput = new ComplianceCommunicationAttachmentListRowInput($row, 1) this.attachmentListRowRequiredInput = new ComplianceCommunicationAttachmentListRequiredInput($row, 'dm-compliance-communication__attachments-item-required') this.attachmentListRowRemoveButton = new ComplianceCommunicationAttachmentListRowRemoveButton(this, $row) } init () { this.attachmentListRowRemoveButton.init() this.attachmentListRowFileInput.makeInteractable() this.attachmentListRowRequiredInput.checkRow() } updateIndex (newIndex) { this.index = newIndex this.attachmentListRowFileInput.updateIndex(newIndex) this.attachmentListRowRequiredInput.updateIndex(newIndex) this.attachmentListRowRemoveButton.updateIndex(newIndex) this.$legendCounter.text(newIndex + 1) } removeRow () { this.attachmentList.removeRow(this.index) this.deleteRow() } deleteRow () { this.$row.remove() } toggleRemoveButtonVisibility (isShown) { this.attachmentListRowRemoveButton.toggleVisibility(isShown) } isRowChecked () { return this.attachmentListRowRequiredInput.isChecked() } } class ComplianceCommunicationAttachmentListAddButton { constructor (attachmentList, $button) { this.attachmentList = attachmentList this.$button = $button this.$buttonCounter = $button.find('.dm-compliance-communication__attachments__js-remaining-counter') } init (numberOfRows) { this.$button.on('click', () => { this.attachmentList.addRow() }) this.updateButtonText(MAX_NUMBER_OF_ROWS - numberOfRows) } updateButtonText (numberRemaining) { this.$buttonCounter.text(numberRemaining) } toggleVisibility (isShown) { this.$button.toggleClass('govuk-visually-hidden', !isShown) if (isShown) { this.$button.removeAttr('tabindex') } else { this.$button.attr('tabindex', -1) } } } class ComplianceCommunicationAttachmentList { constructor (attachmentList) { this.$attachmentList = $(attachmentList) this.$attachmentListItems = this.$attachmentList.find('.dm-compliance-communication__attachments-items') this.attachmentListRows = this.$attachmentListItems.find('.dm-compliance-communication__attachments-item').get().map((row, index) => new ComplianceCommunicationAttachmentListRow(this, index, $(row))) this.attachmentListTemplateRow = new ComplianceCommunicationAttachmentListRow(this, 99, this.$attachmentList.find('.dm-compliance-communication__attachments-item-template > .dm-compliance-communication__attachments-item')) this.attachmentListAddButton = new ComplianceCommunicationAttachmentListAddButton(this, this.$attachmentList.find('.dm-compliance-communication__attachments-add')) } init () { const rowsChecked = this.attachmentListRows.map((attachmentListRow) => attachmentListRow.isRowChecked()) let indexToDeleteFrom if (rowsChecked.every((rowChecked) => !rowChecked)) { indexToDeleteFrom = 0 } else { indexToDeleteFrom = rowsChecked.indexOf(false) } if (indexToDeleteFrom >= 0) { this.attachmentListRows.slice(indexToDeleteFrom).forEach((attachmentListRow) => attachmentListRow.deleteRow()) this.attachmentListRows.splice(indexToDeleteFrom) } this.attachmentListAddButton.init(this.attachmentListRows.length) this.attachmentListRows.forEach((attachmentListRow) => attachmentListRow.init()) this.updateIfMinRows() this.updateAttachmentButton() } removeRow (indexToRemove) { this.attachmentListRows.splice(indexToRemove, 1) this.attachmentListRows.slice(indexToRemove).forEach((attachmentListRow, index) => { attachmentListRow.updateIndex(indexToRemove + index) }) this.updateIfMinRows() this.updateAttachmentButton() if (indexToRemove > 0) { this.focusOnRow(indexToRemove) } else { this.attachmentListAddButton.$button.focus() } } addRow () { const numberOfRows = this.attachmentListRows.length if (numberOfRows < MAX_NUMBER_OF_ROWS) { const $newRow = this.attachmentListTemplateRow.$row.clone() const attachmentListRow = new ComplianceCommunicationAttachmentListRow(this, numberOfRows, $newRow) attachmentListRow.updateIndex(numberOfRows) this.attachmentListRows.push(attachmentListRow) this.$attachmentListItems.append($newRow) this.attachmentListRows[numberOfRows].init() this.updateIfMinRows() this.updateAttachmentButton() this.focusOnRow(numberOfRows) } } updateIfMinRows () { if (this.attachmentListRows.length !== 0) { this.attachmentListRows[0].toggleRemoveButtonVisibility(true) } } updateAttachmentButton () { if (this.attachmentListRows.length === MAX_NUMBER_OF_ROWS) { this.attachmentListAddButton.toggleVisibility(false) } else { this.attachmentListAddButton.toggleVisibility(true) this.attachmentListAddButton.updateButtonText(MAX_NUMBER_OF_ROWS - this.attachmentListRows.length) } } focusOnRow (targetIndexToFocus) { const numberOfRows = this.attachmentListRows.length let indexToFocus = targetIndexToFocus if (targetIndexToFocus >= numberOfRows) { indexToFocus = numberOfRows - 1 } this.attachmentListRows[indexToFocus].attachmentListRowFileInput.$input.focus() } } export default ComplianceCommunicationAttachmentList