|
4 | 4 | angular.module('material.components.fabShared', ['material.core'])
|
5 | 5 | .controller('FabController', FabController);
|
6 | 6 |
|
7 |
| - function FabController($scope, $element, $animate, $mdUtil, $mdConstant) { |
| 7 | + function FabController($scope, $element, $animate, $mdUtil, $mdConstant, $timeout) { |
8 | 8 | var vm = this;
|
9 | 9 |
|
10 | 10 | // NOTE: We use async evals below to avoid conflicts with any existing digest loops
|
|
42 | 42 | resetActionIndex();
|
43 | 43 | }
|
44 | 44 |
|
45 |
| - var events = []; |
46 |
| - |
47 | 45 | function setupListeners() {
|
48 | 46 | var eventTypes = [
|
49 |
| - 'mousedown', 'mouseup', 'click', 'touchstart', 'touchend', 'focusin', 'focusout' |
| 47 | + '$md.pressdown', |
| 48 | + |
| 49 | + 'click', // Fired via keyboard ENTER |
| 50 | + |
| 51 | + 'focusin', 'focusout' |
50 | 52 | ];
|
51 | 53 |
|
52 | 54 | // Add our listeners
|
|
59 | 61 | angular.forEach(eventTypes, function(eventType) {
|
60 | 62 | $element.off(eventType, parseEvents);
|
61 | 63 | });
|
| 64 | + |
62 | 65 | // remove any attached keyboard handlers in case element is removed while
|
63 | 66 | // speed dial is open
|
64 | 67 | disableKeyboard();
|
65 | 68 | });
|
66 | 69 | }
|
67 | 70 |
|
68 |
| - function resetEvents() { |
69 |
| - events = []; |
70 |
| - } |
71 |
| - |
72 |
| - function equalsEvents(toCheck) { |
73 |
| - var isEqual, strippedCheck, moreToCheck; |
74 |
| - |
75 |
| - // Quick check to make sure we don't get stuck in an infinite loop |
76 |
| - var numTests = 0; |
77 |
| - |
78 |
| - do { |
79 |
| - // Strip out the question mark |
80 |
| - strippedCheck = toCheck.map(function(event) { |
81 |
| - return event.replace('?', '') |
82 |
| - }); |
83 |
| - |
84 |
| - // Check if they are equal |
85 |
| - isEqual = angular.equals(events, strippedCheck); |
86 |
| - |
87 |
| - // If not, check to see if removing an optional event makes them equal |
88 |
| - if (!isEqual) { |
89 |
| - toCheck = removeOptionalEvent(toCheck); |
90 |
| - moreToCheck = (toCheck.length >= events.length && toCheck.length !== strippedCheck.length); |
91 |
| - } |
92 |
| - } |
93 |
| - while (numTests < 10 && !isEqual && moreToCheck); |
94 |
| - |
95 |
| - return isEqual; |
96 |
| - } |
97 |
| - |
98 |
| - function removeOptionalEvent(events) { |
99 |
| - var foundOptional = false; |
100 |
| - |
101 |
| - return events.filter(function(event) { |
102 |
| - // If we have not found an optional one, keep searching |
103 |
| - if (!foundOptional && event.indexOf('?') !== -1) { |
104 |
| - foundOptional = true; |
105 |
| - |
106 |
| - // If we find an optional one, remove only that one and keep going |
107 |
| - return false; |
108 |
| - } |
109 |
| - |
110 |
| - return true; |
111 |
| - }); |
112 |
| - } |
113 |
| - |
114 |
| - function parseEvents(latestEvent) { |
115 |
| - events.push(latestEvent.type); |
116 |
| - |
117 |
| - // Handle desktop click |
118 |
| - if (equalsEvents(['mousedown', 'focusout?', 'focusin?', 'mouseup', 'click'])) { |
119 |
| - handleItemClick(latestEvent); |
120 |
| - resetEvents(); |
| 71 | + var recentEvent; |
| 72 | + function parseEvents(event) { |
| 73 | + // If we've had a recent press/click event, or material is sending us an additional event, |
| 74 | + // ignore it |
| 75 | + if (recentEvent && (isClick(recentEvent) || recentEvent.$material)) { |
121 | 76 | return;
|
122 | 77 | }
|
123 | 78 |
|
124 |
| - // Handle mobile click/tap (and keyboard enter) |
125 |
| - if (equalsEvents(['touchstart?', 'touchend?', 'click'])) { |
126 |
| - handleItemClick(latestEvent); |
127 |
| - resetEvents(); |
128 |
| - return; |
129 |
| - } |
| 79 | + // Otherwise, handle our events |
| 80 | + if (isClick(event)) { |
| 81 | + handleItemClick(event); |
130 | 82 |
|
131 |
| - // Handle tab keys (focusin) |
132 |
| - if (equalsEvents(['focusin'])) { |
| 83 | + // Store our recent click event |
| 84 | + recentEvent = event; |
| 85 | + } else if (event.type == 'focusin') { |
133 | 86 | vm.open();
|
134 |
| - resetEvents(); |
135 |
| - return; |
136 |
| - } |
137 |
| - |
138 |
| - // Handle tab keys (focusout) |
139 |
| - if (equalsEvents(['focusout'])) { |
| 87 | + } else if (event.type == 'focusout') { |
140 | 88 | vm.close();
|
141 |
| - resetEvents(); |
142 |
| - return; |
143 | 89 | }
|
144 | 90 |
|
145 |
| - eventUnhandled(); |
| 91 | + // Clear the recent event after all others have fired so we stop ignoring |
| 92 | + $timeout(function() { |
| 93 | + recentEvent = null; |
| 94 | + }, 100, false); |
146 | 95 | }
|
147 | 96 |
|
148 |
| - /* |
149 |
| - * No event was handled, so setup a timeout to clear the events |
150 |
| - * |
151 |
| - * TODO: Use $mdUtil.debounce()? |
152 |
| - */ |
153 |
| - var resetEventsTimeout; |
154 |
| - |
155 |
| - function eventUnhandled() { |
156 |
| - if (resetEventsTimeout) { |
157 |
| - window.clearTimeout(resetEventsTimeout); |
158 |
| - } |
159 |
| - |
160 |
| - resetEventsTimeout = window.setTimeout(function() { |
161 |
| - resetEvents(); |
162 |
| - }, 250); |
| 97 | + function isClick(event) { |
| 98 | + return event.type == '$md.pressdown' || event.type == 'click'; |
163 | 99 | }
|
164 | 100 |
|
165 | 101 | function resetActionIndex() {
|
|
219 | 155 |
|
220 | 156 | function enableKeyboard() {
|
221 | 157 | angular.element(document).on('keydown', keyPressed);
|
| 158 | + |
| 159 | + // TODO: On desktop, we should be able to reset the indexes so you cannot tab through |
| 160 | + //resetActionTabIndexes(); |
222 | 161 | }
|
223 | 162 |
|
224 | 163 | function disableKeyboard() {
|
|
245 | 184 | }
|
246 | 185 |
|
247 | 186 | function focusAction(event, direction) {
|
248 |
| - // Grab all of the actions |
249 |
| - var actions = getActionsElement()[0].querySelectorAll('.md-fab-action-item'); |
250 |
| - |
251 |
| - // Disable all other actions for tabbing |
252 |
| - angular.forEach(actions, function(action) { |
253 |
| - angular.element(angular.element(action).children()[0]).attr('tabindex', -1); |
254 |
| - }); |
| 187 | + var actions = resetActionTabIndexes(); |
255 | 188 |
|
256 | 189 | // Increment/decrement the counter with restrictions
|
257 | 190 | vm.currentActionIndex = vm.currentActionIndex + direction;
|
|
268 | 201 | event.stopImmediatePropagation();
|
269 | 202 | }
|
270 | 203 |
|
| 204 | + function resetActionTabIndexes() { |
| 205 | + // Grab all of the actions |
| 206 | + var actions = getActionsElement()[0].querySelectorAll('.md-fab-action-item'); |
| 207 | + |
| 208 | + // Disable all other actions for tabbing |
| 209 | + angular.forEach(actions, function(action) { |
| 210 | + angular.element(angular.element(action).children()[0]).attr('tabindex', -1); |
| 211 | + }); |
| 212 | + |
| 213 | + return actions; |
| 214 | + } |
| 215 | + |
271 | 216 | function doKeyLeft(event) {
|
272 | 217 | if (vm.direction === 'left') {
|
273 | 218 | doActionNext(event);
|
|
0 commit comments