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
JavaScript
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