ccs-digitalmarketplace-govuk-frontend
Version:
Digital Marketplace GOV.UK Frontend contains the code you need to start building a user interface for Digital Marketplace.
151 lines (121 loc) • 4.4 kB
JavaScript
const QuestionType = {
CONTROLLER: 0,
CONTROLLER_AND_TARGET: 1,
TARGET: 2
}
class QuestionInput {
constructor (question, $input) {
this.question = question
this.$input = $input
const targets = this.$input.attr('data-target')
this.targets = targets ? targets.split(' ') : []
}
setEventListener () {
this.$input.on('click', () => {
this.question.updateTargetQuestionsVisibility()
})
}
isChecked () {
return this.$input.is(':checked')
}
}
class Question {
constructor (questionWatcher, $question, questionType) {
this.questionWatcher = questionWatcher
this.$question = $question
this.id = this.$question.attr('id')
this.questionType = questionType
if (this.questionType === QuestionType.CONTROLLER) {
this.enableControllerQuestionMethods()
} else {
this.enableTargetQuestionMethods()
}
}
enableControllerQuestionMethods () {
this.questionInputs = this.$question.find('input').get().map((inputElement) => new QuestionInput(this, $(inputElement)))
this.possibleTargetIds = new Set(this.questionInputs.map((questionInput) => questionInput.targets).flat())
}
enableTargetQuestionMethods () {
this.targetOf = []
}
isVisible () {
return !this.$question.hasClass('govuk-visually-hidden')
}
currentTargetIds () {
let targets
if (this.isVisible() && this.questionInputs) {
targets = this.questionInputs.filter((questionInput) => questionInput.isChecked()).map((questionInput) => questionInput.targets).flat()
} else {
targets = []
}
return new Set(targets)
}
updateTargetQuestionsVisibility () {
this.questionWatcher.updateTargetQuestionsVisibility(this.possibleTargetIds)
}
appendTargetOf (questionId) {
this.targetOf.push(questionId)
}
toggleVisibility (isShown) {
this.$question.toggleClass('govuk-visually-hidden', !isShown)
this.$question.attr('aria-hidden', (!isShown).toString())
}
}
class QuestionWatcher {
constructor () {
this.questions = {}
$('[data-module="dm-question-with-follow-up"]').each((_index, question) => {
this.push(new Question(this, $(question), QuestionType.CONTROLLER))
})
for (const [questionId, question] of Object.entries(this.questions)) {
for (const questionTargetId of question.possibleTargetIds) {
if (questionTargetId in this.questions) {
if (this.questions[questionTargetId].questionType === QuestionType.CONTROLLER) {
this.questions[questionTargetId].questionType = QuestionType.CONTROLLER_AND_TARGET
this.questions[questionTargetId].enableTargetQuestionMethods()
}
} else {
this.push(new Question(this, $(`#${questionTargetId}`), QuestionType.TARGET))
}
this.questions[questionTargetId].appendTargetOf(questionId)
}
}
}
init () {
for (const question of Object.values(this.questions)) {
if (question.questionType < QuestionType.TARGET) {
for (const questionInput of question.questionInputs) {
questionInput.setEventListener()
}
if (question.questionType === QuestionType.CONTROLLER) {
this.updateTargetQuestionsVisibility(question.possibleTargetIds)
}
}
}
}
push (question) {
this.questions[question.id] = question
}
updateTargetQuestionsVisibility (possibleTargetIds, isShown) {
for (const possibleTargetId of possibleTargetIds) {
const targetQuestion = this.questions[possibleTargetId]
let questionIsShown
if (isShown === undefined) {
const controllerQuestions = targetQuestion.targetOf.map((questionId) => this.questions[questionId])
const targetsToShow = new Set(controllerQuestions.map((controllerQuestion) => Array.from(controllerQuestion.currentTargetIds())).flat())
questionIsShown = targetsToShow.has(possibleTargetId)
} else {
questionIsShown = isShown
}
targetQuestion.toggleVisibility(questionIsShown)
if (targetQuestion.questionType === QuestionType.CONTROLLER_AND_TARGET) {
if (questionIsShown) {
this.updateTargetQuestionsVisibility(targetQuestion.possibleTargetIds)
} else {
this.updateTargetQuestionsVisibility(targetQuestion.possibleTargetIds, false)
}
}
}
}
}
export default QuestionWatcher