2019-05-22 13:11:48 +01:00
( function ( global ) {
2016-08-07 09:17:49 +01:00
"use strict" ;
2019-05-22 13:11:48 +01:00
var Modules = global . GOVUK . Modules ;
2025-07-31 12:47:40 -04:00
// Template functions for rendering component states
let renderStates = {
'initial' : function ( data ) {
return `
$ { data . showNowAsDefault ? `
< div class = "radio-select__column margin-y-2" >
< div class = "usa-radio" >
< input class = "usa-radio__input" checked = "checked" id = "${data.name}-0" name = "${data.name}" type = "radio" value = "" >
< label class = "usa-radio__label" for = "${data.name}-0" > Now < / l a b e l >
< / d i v >
2020-07-16 10:49:21 +01:00
< / d i v >
2025-07-31 12:47:40 -04:00
` : ''}
2023-09-15 12:26:31 -04:00
< div class = "radio-select__column margin-y-2" >
2025-07-31 12:47:40 -04:00
$ { data . categories . map ( category =>
` <input type='button' class='usa-button usa-button--outline radio-select__button--category' aria-expanded="false" value=' ${ category } ' /> `
) . join ( '' ) }
2016-12-19 10:36:17 +00:00
< / d i v >
2025-07-31 12:47:40 -04:00
` ;
} ,
'choose' : function ( data ) {
return `
$ { data . showNowAsDefault ? `
< div class = "radio-select__column margin-y-2" >
< div class = "usa-radio" >
< input class = "usa-radio__input" checked = "checked" id = "${data.name}-0" name = "${data.name}" type = "radio" value = "" >
< label class = "usa-radio__label" for = "${data.name}-0" > Now < / l a b e l >
< / d i v >
2016-12-19 10:36:17 +00:00
< / d i v >
2025-07-31 12:47:40 -04:00
` : ''}
2023-09-15 12:26:31 -04:00
< div class = "radio-select__column margin-y-2" >
2025-07-31 12:47:40 -04:00
$ { data . choices . map ( choice => `
< div class = "usa-radio js-option" >
< input class = "usa-radio__input" type = "radio" value = "${choice.value}" id = "${choice.id}" name = "${data.name}" / >
< label class = "usa-radio__label" for = "${choice.id}" > $ { choice . label } < / l a b e l >
< / d i v >
` ).join('')}
< input type = 'button' class = 'usa-button usa-button--outline radio-select__button--done margin-top-4' aria - expanded = 'true' value = 'Back to select a new time' / >
2016-12-19 10:36:17 +00:00
< / d i v >
2025-07-31 12:47:40 -04:00
` ;
} ,
'chosen' : function ( data ) {
return `
$ { data . showNowAsDefault ? `
< div class = "radio-select__column margin-y-2" >
< div class = "usa-radio" >
< input class = "usa-radio__input" id = "${data.name}-0" name = "${data.name}" type = "radio" value = "" >
< label class = "usa-radio__label" for = "${data.name}-0" > Now < / l a b e l >
< / d i v >
2016-12-19 10:36:17 +00:00
< / d i v >
2025-07-31 12:47:40 -04:00
` : ''}
< div class = "radio-select__column margin-y-2" >
$ { data . choices . map ( choice => `
< div class = "usa-radio" >
< input class = "usa-radio__input" checked = "checked" type = "radio" value = "${choice.value}" id = "${choice.id}" name = "${data.name}" / >
< label class = "usa-radio__label" for = "${choice.id}" > $ { choice . label } < / l a b e l >
< / d i v >
` ).join('')}
< / d i v >
< div class = "radio-select__column margin-y-2" >
< input type = 'button' class = 'usa-button usa-button--outline radio-select__button--reset' aria - expanded = 'false' value = 'Choose a different time' / >
< / d i v >
` ;
}
2016-10-11 14:17:29 +01:00
} ;
2016-08-07 09:17:49 +01:00
2021-01-20 11:23:01 +00:00
let shiftFocus = function ( elementToFocus , component ) {
// The first option is always the default
if ( elementToFocus === 'default' ) {
2021-01-19 14:12:29 +00:00
$ ( '[type=radio]' , component ) . eq ( 0 ) . focus ( ) ;
}
2021-01-20 11:23:01 +00:00
if ( elementToFocus === 'option' ) {
2021-01-19 14:12:29 +00:00
$ ( '[type=radio]' , component ) . eq ( 1 ) . focus ( ) ;
}
2016-10-11 14:17:29 +01:00
} ;
2016-08-07 09:17:49 +01:00
Modules . RadioSelect = function ( ) {
this . start = function ( component ) {
let $component = $ ( component ) ;
2016-12-19 10:36:17 +00:00
let render = ( state , data ) => {
2025-07-31 12:47:40 -04:00
$component . html ( renderStates [ state ] ( data ) ) ;
2016-12-19 10:36:17 +00:00
} ;
2021-01-20 11:23:01 +00:00
// store array of all options in component
2016-10-11 14:17:29 +01:00
let choices = $ ( 'label' , $component ) . toArray ( ) . map ( function ( element ) {
let $element = $ ( element ) ;
return {
'id' : $element . attr ( 'for' ) ,
'label' : $ . trim ( $element . text ( ) ) ,
2016-12-19 10:36:17 +00:00
'value' : $element . prev ( 'input' ) . attr ( 'value' )
2016-10-11 14:17:29 +01:00
} ;
2016-08-07 09:17:49 +01:00
} ) ;
2016-10-11 14:17:29 +01:00
let categories = $component . data ( 'categories' ) . split ( ',' ) ;
let name = $component . find ( 'input' ) . eq ( 0 ) . attr ( 'name' ) ;
2019-07-01 11:48:09 +01:00
let mousedownOption = null ;
2020-07-16 10:49:21 +01:00
let showNowAsDefault = (
2020-07-16 19:27:33 +01:00
$component . data ( 'show-now-as-default' ) . toString ( ) === 'true' ?
2020-07-16 10:49:21 +01:00
{ 'name' : name } : false
) ;
2021-01-20 11:23:01 +00:00
// functions for changing the state of the component's HTML
2019-07-01 11:48:09 +01:00
const reset = ( ) => {
2019-07-08 10:42:54 +01:00
render ( 'initial' , {
'categories' : categories ,
2020-07-16 10:49:21 +01:00
'name' : name ,
'showNowAsDefault' : showNowAsDefault
2019-07-08 10:42:54 +01:00
} ) ;
2021-01-20 11:23:01 +00:00
shiftFocus ( 'default' , component ) ;
2019-07-08 10:42:54 +01:00
} ;
2019-07-01 11:48:09 +01:00
const selectOption = ( value ) => {
render ( 'chosen' , {
'choices' : choices . filter (
element => element . value == value
) ,
2020-07-16 10:49:21 +01:00
'name' : name ,
'showNowAsDefault' : showNowAsDefault
2019-07-01 11:48:09 +01:00
} ) ;
2021-01-20 11:23:01 +00:00
shiftFocus ( 'option' , component ) ;
2019-07-01 11:48:09 +01:00
} ;
2021-01-20 11:23:01 +00:00
// use mousedown + mouseup event sequence to confirm option selection
2019-07-01 11:48:09 +01:00
const trackMouseup = ( event ) => {
const parentNode = event . target . parentNode ;
if ( parentNode === mousedownOption ) {
const value = $ ( 'input' , parentNode ) . attr ( 'value' ) ;
selectOption ( value ) ;
// clear tracking
mousedownOption = null ;
$ ( document ) . off ( 'mouseup' , trackMouseup ) ;
}
} ;
2016-10-11 14:17:29 +01:00
2021-01-20 11:23:01 +00:00
// set events
2016-10-11 14:17:29 +01:00
$component
2020-02-06 14:49:07 +00:00
. on ( 'click' , '.radio-select__button--category' , function ( event ) {
2016-10-11 14:17:29 +01:00
event . preventDefault ( ) ;
2016-10-11 17:59:09 +01:00
let wordsInDay = $ ( this ) . attr ( 'value' ) . split ( ' ' ) ;
let day = wordsInDay [ wordsInDay . length - 1 ] . toLowerCase ( ) ;
2016-10-11 14:17:29 +01:00
render ( 'choose' , {
'choices' : choices . filter (
2016-10-11 17:59:09 +01:00
element => element . label . toLowerCase ( ) . indexOf ( day ) > - 1
2016-10-11 14:17:29 +01:00
) ,
2020-07-16 19:27:33 +01:00
'name' : name ,
'showNowAsDefault' : showNowAsDefault
2016-10-11 14:17:29 +01:00
} ) ;
2021-01-20 11:23:01 +00:00
shiftFocus ( 'option' , component ) ;
2016-10-11 14:17:29 +01:00
} )
2019-07-01 11:48:09 +01:00
. on ( 'mousedown' , '.js-option' , function ( event ) {
mousedownOption = this ;
2016-10-11 14:17:29 +01:00
2019-07-01 11:48:09 +01:00
// mouseup on the same option completes the click action
$ ( document ) . on ( 'mouseup' , trackMouseup ) ;
2016-10-11 14:17:29 +01:00
} )
2019-07-01 11:48:09 +01:00
// space and enter, clicked on a radio confirm that option was selected
2016-10-11 14:17:29 +01:00
. on ( 'keydown' , 'input[type=radio]' , function ( event ) {
2019-07-01 11:48:09 +01:00
// allow keypresses which aren’ t enter or space through
2016-10-11 14:17:29 +01:00
if ( event . which !== 13 && event . which !== 32 ) {
return true ;
}
event . preventDefault ( ) ;
let value = $ ( this ) . attr ( 'value' ) ;
2019-07-01 11:48:09 +01:00
selectOption ( value ) ;
2016-10-11 14:17:29 +01:00
} )
2020-02-06 14:49:07 +00:00
. on ( 'click' , '.radio-select__button--done' , function ( event ) {
2016-10-11 14:17:29 +01:00
event . preventDefault ( ) ;
2019-07-08 10:42:54 +01:00
let $selection = $ ( 'input[type=radio]:checked' , this . parentNode ) ;
if ( $selection . length ) {
render ( 'chosen' , {
'choices' : choices . filter (
element => element . value == $selection . eq ( 0 ) . attr ( 'value' )
) ,
2020-07-16 10:49:21 +01:00
'name' : name ,
'showNowAsDefault' : showNowAsDefault
2019-07-08 10:42:54 +01:00
} ) ;
2021-01-20 11:23:01 +00:00
shiftFocus ( 'option' , component ) ;
2019-07-08 10:42:54 +01:00
} else {
reset ( ) ;
2021-01-20 11:23:01 +00:00
shiftFocus ( 'default' , component ) ;
2019-07-08 10:42:54 +01:00
}
2016-10-11 14:17:29 +01:00
2019-07-08 10:42:54 +01:00
} )
2020-02-06 14:49:07 +00:00
. on ( 'click' , '.radio-select__button--reset' , function ( event ) {
2019-07-08 10:42:54 +01:00
event . preventDefault ( ) ;
reset ( ) ;
2021-01-20 11:23:01 +00:00
shiftFocus ( 'default' , component ) ;
2019-07-08 10:42:54 +01:00
2016-10-11 14:17:29 +01:00
} ) ;
2021-01-20 11:23:01 +00:00
// set HTML to initial state
2016-10-11 14:17:29 +01:00
render ( 'initial' , {
'categories' : categories ,
2020-07-16 10:49:21 +01:00
'name' : name ,
'showNowAsDefault' : showNowAsDefault
2016-08-07 09:17:49 +01:00
} ) ;
2016-10-11 18:11:20 +01:00
$component . css ( { 'height' : 'auto' } ) ;
2016-08-07 09:17:49 +01:00
} ;
} ;
2019-05-22 13:11:48 +01:00
} ) ( window ) ;