|
5 | 5 | .controller('MdFabController', MdFabController); |
6 | 6 |
|
7 | 7 | function MdFabController($scope, $element, $animate, $mdUtil, $mdConstant, $timeout) { |
8 | | - var vm = this; |
| 8 | + var ctrl = this; |
9 | 9 | var initialAnimationAttempts = 0; |
10 | 10 |
|
11 | 11 | // NOTE: We use async eval(s) below to avoid conflicts with any existing digest loops |
12 | 12 |
|
13 | | - vm.open = function() { |
| 13 | + ctrl.open = function() { |
14 | 14 | $scope.$evalAsync("vm.isOpen = true"); |
15 | 15 | }; |
16 | 16 |
|
17 | | - vm.close = function() { |
| 17 | + ctrl.close = function() { |
18 | 18 | // Async eval to avoid conflicts with existing digest loops |
19 | 19 | $scope.$evalAsync("vm.isOpen = false"); |
20 | 20 |
|
|
23 | 23 | }; |
24 | 24 |
|
25 | 25 | // Toggle the open/close state when the trigger is clicked |
26 | | - vm.toggle = function() { |
| 26 | + ctrl.toggle = function() { |
27 | 27 | $scope.$evalAsync("vm.isOpen = !vm.isOpen"); |
28 | 28 | }; |
29 | 29 |
|
30 | 30 | /* |
31 | 31 | * AngularJS Lifecycle hook for newer AngularJS versions. |
32 | | - * Bindings are not guaranteed to have been assigned in the controller, but they are in the $onInit hook. |
| 32 | + * Bindings are not guaranteed to have been assigned in the controller, but they are in the |
| 33 | + * $onInit hook. |
33 | 34 | */ |
34 | | - vm.$onInit = function() { |
| 35 | + ctrl.$onInit = function() { |
35 | 36 | setupDefaults(); |
36 | 37 | setupListeners(); |
37 | 38 | setupWatchers(); |
|
47 | 48 |
|
48 | 49 | function setupDefaults() { |
49 | 50 | // Set the default direction to 'down' if none is specified |
50 | | - vm.direction = vm.direction || 'down'; |
| 51 | + ctrl.direction = ctrl.direction || 'down'; |
51 | 52 |
|
52 | 53 | // Set the default to be closed |
53 | | - vm.isOpen = vm.isOpen || false; |
| 54 | + ctrl.isOpen = ctrl.isOpen || false; |
54 | 55 |
|
55 | 56 | // Start the keyboard interaction at the first action |
56 | 57 | resetActionIndex(); |
|
82 | 83 | } |
83 | 84 |
|
84 | 85 | var closeTimeout; |
| 86 | + |
| 87 | + /** |
| 88 | + * @param {MouseEvent} event |
| 89 | + */ |
85 | 90 | function parseEvents(event) { |
86 | 91 | // If the event is a click, just handle it |
87 | 92 | if (event.type == 'click') { |
|
91 | 96 | // If we focusout, set a timeout to close the element |
92 | 97 | if (event.type == 'focusout' && !closeTimeout) { |
93 | 98 | closeTimeout = $timeout(function() { |
94 | | - vm.close(); |
| 99 | + ctrl.close(); |
95 | 100 | }, 100, false); |
96 | 101 | } |
97 | 102 |
|
|
103 | 108 | } |
104 | 109 |
|
105 | 110 | function resetActionIndex() { |
106 | | - vm.currentActionIndex = -1; |
| 111 | + ctrl.currentActionIndex = -1; |
107 | 112 | } |
108 | 113 |
|
109 | 114 | function setupWatchers() { |
|
179 | 184 | }); |
180 | 185 |
|
181 | 186 | // TODO: On desktop, we should be able to reset the indexes so you cannot tab through, but |
182 | | - // this breaks accessibility, especially on mobile, since you have no arrow keys to press |
183 | | - // resetActionTabIndexes(); |
| 187 | + // this breaks accessibility, especially on mobile, since you have no arrow keys to press |
| 188 | + // resetActionTabIndexes(); |
184 | 189 | } |
185 | 190 |
|
186 | 191 | function disableKeyboard() { |
|
194 | 199 | var closestActions = $mdUtil.getClosest(event.target, 'md-fab-actions'); |
195 | 200 |
|
196 | 201 | if (!closestTrigger && !closestActions) { |
197 | | - vm.close(); |
| 202 | + ctrl.close(); |
198 | 203 | } |
199 | 204 | } |
200 | 205 | } |
201 | 206 |
|
202 | 207 | function keyPressed(event) { |
203 | 208 | switch (event.which) { |
204 | | - case $mdConstant.KEY_CODE.ESCAPE: vm.close(); event.preventDefault(); return false; |
| 209 | + case $mdConstant.KEY_CODE.ESCAPE: ctrl.close(); event.preventDefault(); return false; |
205 | 210 | case $mdConstant.KEY_CODE.LEFT_ARROW: doKeyLeft(event); return false; |
206 | 211 | case $mdConstant.KEY_CODE.UP_ARROW: doKeyUp(event); return false; |
207 | 212 | case $mdConstant.KEY_CODE.RIGHT_ARROW: doKeyRight(event); return false; |
|
221 | 226 | var actions = resetActionTabIndexes(); |
222 | 227 |
|
223 | 228 | // Increment/decrement the counter with restrictions |
224 | | - vm.currentActionIndex = vm.currentActionIndex + direction; |
225 | | - vm.currentActionIndex = Math.min(actions.length - 1, vm.currentActionIndex); |
226 | | - vm.currentActionIndex = Math.max(0, vm.currentActionIndex); |
| 229 | + ctrl.currentActionIndex = ctrl.currentActionIndex + direction; |
| 230 | + ctrl.currentActionIndex = Math.min(actions.length - 1, ctrl.currentActionIndex); |
| 231 | + ctrl.currentActionIndex = Math.max(0, ctrl.currentActionIndex); |
227 | 232 |
|
228 | 233 | // Focus the element |
229 | | - var focusElement = angular.element(actions[vm.currentActionIndex]).children()[0]; |
| 234 | + var focusElement = angular.element(actions[ctrl.currentActionIndex]).children()[0]; |
230 | 235 | angular.element(focusElement).attr('tabindex', 0); |
231 | 236 | focusElement.focus(); |
232 | 237 |
|
|
248 | 253 | } |
249 | 254 |
|
250 | 255 | function doKeyLeft(event) { |
251 | | - if (vm.direction === 'left') { |
| 256 | + if (ctrl.direction === 'left') { |
252 | 257 | doActionNext(event); |
253 | 258 | } else { |
254 | 259 | doActionPrev(event); |
255 | 260 | } |
256 | 261 | } |
257 | 262 |
|
258 | 263 | function doKeyUp(event) { |
259 | | - if (vm.direction === 'down') { |
| 264 | + if (ctrl.direction === 'down') { |
260 | 265 | doActionPrev(event); |
261 | 266 | } else { |
262 | 267 | doActionNext(event); |
263 | 268 | } |
264 | 269 | } |
265 | 270 |
|
266 | 271 | function doKeyRight(event) { |
267 | | - if (vm.direction === 'left') { |
| 272 | + if (ctrl.direction === 'left') { |
268 | 273 | doActionPrev(event); |
269 | 274 | } else { |
270 | 275 | doActionNext(event); |
271 | 276 | } |
272 | 277 | } |
273 | 278 |
|
274 | 279 | function doKeyDown(event) { |
275 | | - if (vm.direction === 'up') { |
| 280 | + if (ctrl.direction === 'up') { |
276 | 281 | doActionPrev(event); |
277 | 282 | } else { |
278 | 283 | doActionNext(event); |
279 | 284 | } |
280 | 285 | } |
281 | 286 |
|
282 | | - function isTrigger(element) { |
| 287 | + /** |
| 288 | + * @param {Node} element |
| 289 | + * @returns {Node|null} |
| 290 | + */ |
| 291 | + function getClosestButton(element) { |
| 292 | + return $mdUtil.getClosest(element, 'button') || $mdUtil.getClosest(element, 'md-button'); |
| 293 | + } |
| 294 | + |
| 295 | + /** |
| 296 | + * @param {Node} element |
| 297 | + * @returns {Node|null} |
| 298 | + */ |
| 299 | + function getClosestTrigger(element) { |
283 | 300 | return $mdUtil.getClosest(element, 'md-fab-trigger'); |
284 | 301 | } |
285 | 302 |
|
286 | | - function isAction(element) { |
| 303 | + /** |
| 304 | + * @param {Node} element |
| 305 | + * @returns {Node|null} |
| 306 | + */ |
| 307 | + function getClosestAction(element) { |
287 | 308 | return $mdUtil.getClosest(element, 'md-fab-actions'); |
288 | 309 | } |
289 | 310 |
|
| 311 | + /** |
| 312 | + * @param {MouseEvent} event |
| 313 | + */ |
290 | 314 | function handleItemClick(event) { |
291 | | - if (isTrigger(event.target)) { |
292 | | - vm.toggle(); |
| 315 | + var closestButton = event.target ? getClosestButton(event.target) : null; |
| 316 | + |
| 317 | + // Check that the button in the trigger is not disabled |
| 318 | + if (closestButton && !closestButton.disabled) { |
| 319 | + if (getClosestTrigger(event.target)) { |
| 320 | + ctrl.toggle(); |
| 321 | + } |
293 | 322 | } |
294 | 323 |
|
295 | | - if (isAction(event.target)) { |
296 | | - vm.close(); |
| 324 | + if (getClosestAction(event.target)) { |
| 325 | + ctrl.close(); |
297 | 326 | } |
298 | 327 | } |
299 | 328 |
|
|
0 commit comments