|
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