|
11 | 11 | // NOTE: We use async eval(s) below to avoid conflicts with any existing digest loops |
12 | 12 |
|
13 | 13 | ctrl.open = function() { |
14 | | - $scope.$evalAsync("vm.isOpen = true"); |
| 14 | + $scope.$evalAsync("ctrl.isOpen = true"); |
15 | 15 | }; |
16 | 16 |
|
17 | 17 | ctrl.close = function() { |
18 | 18 | // Async eval to avoid conflicts with existing digest loops |
19 | | - $scope.$evalAsync("vm.isOpen = false"); |
| 19 | + $scope.$evalAsync("ctrl.isOpen = false"); |
20 | 20 |
|
21 | 21 | // Focus the trigger when the element closes so users can still tab to the next item |
22 | 22 | $element.find('md-fab-trigger')[0].focus(); |
23 | 23 | }; |
24 | 24 |
|
25 | 25 | // Toggle the open/close state when the trigger is clicked |
26 | 26 | ctrl.toggle = function() { |
27 | | - $scope.$evalAsync("vm.isOpen = !vm.isOpen"); |
| 27 | + $scope.$evalAsync("ctrl.isOpen = !ctrl.isOpen"); |
28 | 28 | }; |
29 | 29 |
|
30 | 30 | /* |
|
113 | 113 |
|
114 | 114 | function setupWatchers() { |
115 | 115 | // Watch for changes to the direction and update classes/attributes |
116 | | - $scope.$watch('vm.direction', function(newDir, oldDir) { |
| 116 | + $scope.$watch('ctrl.direction', function(newDir, oldDir) { |
117 | 117 | // Add the appropriate classes so we can target the direction in the CSS |
118 | 118 | $animate.removeClass($element, 'md-' + oldDir); |
119 | 119 | $animate.addClass($element, 'md-' + newDir); |
|
125 | 125 | var trigger, actions; |
126 | 126 |
|
127 | 127 | // Watch for changes to md-open |
128 | | - $scope.$watch('vm.isOpen', function(isOpen) { |
| 128 | + $scope.$watch('ctrl.isOpen', function(isOpen) { |
129 | 129 | // Reset the action index since it may have changed |
130 | 130 | resetActionIndex(); |
131 | 131 |
|
|
182 | 182 | $mdUtil.nextTick(function() { |
183 | 183 | angular.element(document).on('click touchend', checkForOutsideClick); |
184 | 184 | }); |
185 | | - |
186 | | - // TODO: On desktop, we should be able to reset the indexes so you cannot tab through, but |
187 | | - // this breaks accessibility, especially on mobile, since you have no arrow keys to press |
188 | | - // resetActionTabIndexes(); |
189 | 185 | } |
190 | 186 |
|
191 | 187 | function disableKeyboard() { |
|
204 | 200 | } |
205 | 201 | } |
206 | 202 |
|
| 203 | + /** |
| 204 | + * @param {KeyboardEvent} event |
| 205 | + * @returns {boolean} |
| 206 | + */ |
207 | 207 | function keyPressed(event) { |
208 | 208 | switch (event.which) { |
209 | 209 | case $mdConstant.KEY_CODE.ESCAPE: ctrl.close(); event.preventDefault(); return false; |
210 | 210 | case $mdConstant.KEY_CODE.LEFT_ARROW: doKeyLeft(event); return false; |
211 | 211 | case $mdConstant.KEY_CODE.UP_ARROW: doKeyUp(event); return false; |
212 | 212 | case $mdConstant.KEY_CODE.RIGHT_ARROW: doKeyRight(event); return false; |
213 | 213 | case $mdConstant.KEY_CODE.DOWN_ARROW: doKeyDown(event); return false; |
| 214 | + case $mdConstant.KEY_CODE.TAB: doShift(event); return false; |
214 | 215 | } |
215 | 216 | } |
216 | 217 |
|
|
223 | 224 | } |
224 | 225 |
|
225 | 226 | function focusAction(event, direction) { |
226 | | - var actions = resetActionTabIndexes(); |
| 227 | + var actions = getActionsElement()[0].querySelectorAll('.md-fab-action-item'); |
| 228 | + var previousActionIndex = ctrl.currentActionIndex; |
227 | 229 |
|
228 | 230 | // Increment/decrement the counter with restrictions |
229 | 231 | ctrl.currentActionIndex = ctrl.currentActionIndex + direction; |
230 | 232 | ctrl.currentActionIndex = Math.min(actions.length - 1, ctrl.currentActionIndex); |
231 | 233 | ctrl.currentActionIndex = Math.max(0, ctrl.currentActionIndex); |
232 | 234 |
|
233 | | - // Focus the element |
234 | | - var focusElement = angular.element(actions[ctrl.currentActionIndex]).children()[0]; |
235 | | - angular.element(focusElement).attr('tabindex', 0); |
236 | | - focusElement.focus(); |
237 | | - |
238 | | - // Make sure the event doesn't bubble and cause something else |
239 | | - event.preventDefault(); |
240 | | - event.stopImmediatePropagation(); |
241 | | - } |
242 | | - |
243 | | - function resetActionTabIndexes() { |
244 | | - // Grab all of the actions |
245 | | - var actions = getActionsElement()[0].querySelectorAll('.md-fab-action-item'); |
246 | | - |
247 | | - // Disable all other actions for tabbing |
248 | | - angular.forEach(actions, function(action) { |
249 | | - angular.element(angular.element(action).children()[0]).attr('tabindex', -1); |
250 | | - }); |
| 235 | + // Let Tab and Shift+Tab escape if we're trying to move past the start/end. |
| 236 | + if (event.which !== $mdConstant.KEY_CODE.TAB || |
| 237 | + previousActionIndex !== ctrl.currentActionIndex) { |
| 238 | + // Focus the element |
| 239 | + var focusElement = angular.element(actions[ctrl.currentActionIndex]).children()[0]; |
| 240 | + focusElement.focus(); |
251 | 241 |
|
252 | | - return actions; |
| 242 | + // Make sure the event doesn't bubble and cause something else |
| 243 | + event.preventDefault(); |
| 244 | + event.stopImmediatePropagation(); |
| 245 | + } |
253 | 246 | } |
254 | 247 |
|
255 | 248 | function doKeyLeft(event) { |
|
284 | 277 | } |
285 | 278 | } |
286 | 279 |
|
| 280 | + function doShift(event) { |
| 281 | + if (event.shiftKey) { |
| 282 | + doActionPrev(event); |
| 283 | + } else { |
| 284 | + doActionNext(event); |
| 285 | + } |
| 286 | + } |
| 287 | + |
287 | 288 | /** |
288 | 289 | * @param {Node} element |
289 | 290 | * @returns {Node|null} |
|
309 | 310 | } |
310 | 311 |
|
311 | 312 | /** |
312 | | - * @param {MouseEvent} event |
| 313 | + * @param {MouseEvent|FocusEvent} event |
313 | 314 | */ |
314 | 315 | function handleItemClick(event) { |
315 | 316 | var closestButton = event.target ? getClosestButton(event.target) : null; |
|
0 commit comments