@@ -9,6 +9,11 @@ angular.module('material.components.radioButton', [
99 . directive ( 'mdRadioGroup' , mdRadioGroupDirective )
1010 . directive ( 'mdRadioButton' , mdRadioButtonDirective ) ;
1111
12+ /**
13+ * @type {Readonly<{NEXT: number, CURRENT: number, PREVIOUS: number}> }
14+ */
15+ var incrementSelection = Object . freeze ( { PREVIOUS : - 1 , CURRENT : 0 , NEXT : 1 } ) ;
16+
1217/**
1318 * @ngdoc directive
1419 * @module material.components.radioButton
@@ -106,33 +111,38 @@ function mdRadioGroupDirective($mdUtil, $mdConstant, $mdTheming, $timeout) {
106111 }
107112
108113 /**
109- * @param {KeyboardEvent } ev
114+ * @param {KeyboardEvent } keyboardEvent
110115 */
111- function keydownListener ( ev ) {
112- var keyCode = ev . which || ev . keyCode ;
116+ function keydownListener ( keyboardEvent ) {
117+ var keyCode = keyboardEvent . which || keyboardEvent . keyCode ;
113118
114119 // Only listen to events that we originated ourselves
115120 // so that we don't trigger on things like arrow keys in inputs.
116121 if ( keyCode !== $mdConstant . KEY_CODE . ENTER &&
117- ev . currentTarget !== ev . target ) {
122+ keyboardEvent . currentTarget !== keyboardEvent . target ) {
118123 return ;
119124 }
120125
121126 switch ( keyCode ) {
122127 case $mdConstant . KEY_CODE . LEFT_ARROW :
123128 case $mdConstant . KEY_CODE . UP_ARROW :
124- ev . preventDefault ( ) ;
129+ keyboardEvent . preventDefault ( ) ;
125130 radioGroupController . selectPrevious ( ) ;
126131 setFocus ( ) ;
127132 break ;
128133
129134 case $mdConstant . KEY_CODE . RIGHT_ARROW :
130135 case $mdConstant . KEY_CODE . DOWN_ARROW :
131- ev . preventDefault ( ) ;
136+ keyboardEvent . preventDefault ( ) ;
132137 radioGroupController . selectNext ( ) ;
133138 setFocus ( ) ;
134139 break ;
135140
141+ case $mdConstant . KEY_CODE . SPACE :
142+ keyboardEvent . preventDefault ( ) ;
143+ radioGroupController . selectCurrent ( ) ;
144+ break ;
145+
136146 case $mdConstant . KEY_CODE . ENTER :
137147 var form = angular . element ( $mdUtil . getClosest ( element [ 0 ] , 'form' ) ) ;
138148 if ( form . length > 0 ) {
@@ -180,11 +190,14 @@ function mdRadioGroupDirective($mdUtil, $mdConstant, $mdTheming, $timeout) {
180190 getViewValue : function ( ) {
181191 return this . _ngModelCtrl . $viewValue ;
182192 } ,
193+ selectCurrent : function ( ) {
194+ return changeSelectedButton ( this . $element , incrementSelection . CURRENT ) ;
195+ } ,
183196 selectNext : function ( ) {
184- return changeSelectedButton ( this . $element , 1 ) ;
197+ return changeSelectedButton ( this . $element , incrementSelection . NEXT ) ;
185198 } ,
186199 selectPrevious : function ( ) {
187- return changeSelectedButton ( this . $element , - 1 ) ;
200+ return changeSelectedButton ( this . $element , incrementSelection . PREVIOUS ) ;
188201 } ,
189202 setActiveDescendant : function ( radioId ) {
190203 this . $element . attr ( 'aria-activedescendant' , radioId ) ;
@@ -196,9 +209,9 @@ function mdRadioGroupDirective($mdUtil, $mdConstant, $mdTheming, $timeout) {
196209 }
197210
198211 /**
199- * Coerce all child radio buttons into an array, then wrap then in an iterator
212+ * Coerce all child radio buttons into an array, then wrap them in an iterator.
200213 * @param parent {!JQLite}
201- * @return {{add: function(*=, *=): *, next: Function , last: function(): * , previous: Function , count: function(): (Array.length|*| number), hasNext: function(*=): ( Array.length|*|number|boolean), inRange: function(*): (Array.length|*|number| boolean), remove: function(*=): void , contains: function(*=): boolean, itemAt: function(*=): * , findBy: function(*, *): Array , hasPrevious: function(*=): ( Array.length|*|number|boolean), items: function(): (Array|* ), indexOf: function(*=): * , first: function(): *}|Object|*|AsyncIterableIterator<OctokitTypes.OctokitResponse<PaginationResults< any>>> }
214+ * @return {{add: add, next: (function()) , last: ( function(): any|null) , previous: (function()) , count: ( function(): number), hasNext: ( function(*=): Array.length|*|number|boolean), inRange: ( function(*): boolean), remove: remove , contains: ( function(*=): *| boolean) , itemAt: ( function(*=): any|null) , findBy: ( function(*, *): *[]) , hasPrevious: ( function(*=): Array.length|*|number|boolean), items: ( function(): *[] ), indexOf: ( function(*=): number) , first: ( function(): any|null)} }
202215 */
203216 function getRadioButtons ( parent ) {
204217 return $mdUtil . iterator ( parent [ 0 ] . querySelectorAll ( 'md-radio-button' ) , true ) ;
@@ -207,12 +220,14 @@ function mdRadioGroupDirective($mdUtil, $mdConstant, $mdTheming, $timeout) {
207220 /**
208221 * Change the radio group's selected button by a given increment.
209222 * If no button is selected, select the first button.
210- * @param {JQLite } parent
211- * @param {-1|1 } increment select previous button if the value is negative; the next button
212- * otherwise.
223+ * @param {JQLite } parent the md-radio-group
224+ * @param {incrementSelection } increment enum that determines whether the next or
225+ * previous button is clicked. For current, only the first button is selected, otherwise the
226+ * current selection is maintained (by doing nothing).
213227 */
214228 function changeSelectedButton ( parent , increment ) {
215229 var buttons = getRadioButtons ( parent ) ;
230+ var target ;
216231
217232 if ( buttons . count ( ) ) {
218233 var validate = function ( button ) {
@@ -221,11 +236,19 @@ function mdRadioGroupDirective($mdUtil, $mdConstant, $mdTheming, $timeout) {
221236 } ;
222237
223238 var selected = parent [ 0 ] . querySelector ( 'md-radio-button.md-checked' ) ;
224- var target = buttons [ increment < 0 ? 'previous' : 'next' ] ( selected , validate ) ||
225- buttons . first ( ) ;
239+ if ( ! selected ) {
240+ target = buttons . first ( ) ;
241+ } else if ( increment === incrementSelection . PREVIOUS ||
242+ increment === incrementSelection . NEXT ) {
243+ target = buttons [
244+ increment === incrementSelection . PREVIOUS ? 'previous' : 'next'
245+ ] ( selected , validate ) ;
246+ }
226247
227- // Activate radioButton's click listener (triggerHandler won't create a real click event)
228- angular . element ( target ) . triggerHandler ( 'click' ) ;
248+ if ( target ) {
249+ // Activate radioButton's click listener (triggerHandler won't create a real click event)
250+ angular . element ( target ) . triggerHandler ( 'click' ) ;
251+ }
229252 }
230253 }
231254}
0 commit comments