|
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