| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of touch; | 5 part of touch; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * Click buster implementation, which is a behavior that prevents native clicks | 8 * Click buster implementation, which is a behavior that prevents native clicks |
| 9 * from firing at undesirable times. There are two scenarios where we may want | 9 * from firing at undesirable times. There are two scenarios where we may want |
| 10 * to 'bust' a click. | 10 * to 'bust' a click. |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 /* | 62 /* |
| 63 if (coord.x < 1 && coord.y < 1) { | 63 if (coord.x < 1 && coord.y < 1) { |
| 64 // TODO(jacobr): implement a configurable logging framework. | 64 // TODO(jacobr): implement a configurable logging framework. |
| 65 // _logger.warning( | 65 // _logger.warning( |
| 66 // "Not busting click on label elem at(${coord.x}, ${coord.y})"); | 66 // "Not busting click on label elem at(${coord.x}, ${coord.y})"); |
| 67 return; | 67 return; |
| 68 } | 68 } |
| 69 */ | 69 */ |
| 70 DoubleLinkedQueueEntry<num> entry = _coordinates.firstEntry(); | 70 DoubleLinkedQueueEntry<num> entry = _coordinates.firstEntry(); |
| 71 while (entry != null) { | 71 while (entry != null) { |
| 72 if (_hitTest(entry.element, | 72 if (_hitTest( |
| 73 entry.nextEntry().element, | 73 entry.element, entry.nextEntry().element, coord.x, coord.y)) { |
| 74 coord.x, | |
| 75 coord.y)) { | |
| 76 entry.nextEntry().remove(); | 74 entry.nextEntry().remove(); |
| 77 entry.remove(); | 75 entry.remove(); |
| 78 return; | 76 return; |
| 79 } else { | 77 } else { |
| 80 entry = entry.nextEntry().nextEntry(); | 78 entry = entry.nextEntry().nextEntry(); |
| 81 } | 79 } |
| 82 } | 80 } |
| 83 | 81 |
| 84 // TODO(jacobr): implement a configurable logging framework. | 82 // TODO(jacobr): implement a configurable logging framework. |
| 85 // _logger.warning("busting click at ${coord.x}, ${coord.y}"); | 83 // _logger.warning("busting click at ${coord.x}, ${coord.y}"); |
| 86 e.stopPropagation(); | 84 e.stopPropagation(); |
| 87 e.preventDefault(); | 85 e.preventDefault(); |
| 88 } | 86 } |
| 89 | 87 |
| 90 /** | 88 /** |
| 91 * This handler will temporarily allow a click to occur near the touch event's | 89 * This handler will temporarily allow a click to occur near the touch event's |
| 92 * coordinates. | 90 * coordinates. |
| 93 */ | 91 */ |
| 94 static void _onTouchStart(Event e) { | 92 static void _onTouchStart(Event e) { |
| 95 TouchEvent te = e; | 93 TouchEvent te = e; |
| 96 final coord = new Coordinate.fromClient(te.touches[0]); | 94 final coord = new Coordinate.fromClient(te.touches[0]); |
| 97 _coordinates.add(coord.x); | 95 _coordinates.add(coord.x); |
| 98 _coordinates.add(coord.y); | 96 _coordinates.add(coord.y); |
| 99 new Timer( | 97 new Timer(const Duration(milliseconds: _TIME_THRESHOLD), () { |
| 100 const Duration(milliseconds: _TIME_THRESHOLD), | 98 _removeCoordinate(coord.x, coord.y); |
| 101 () { _removeCoordinate(coord.x, coord.y); }); | 99 }); |
| 102 _toggleTapHighlights(true); | 100 _toggleTapHighlights(true); |
| 103 } | 101 } |
| 104 | 102 |
| 105 /** | 103 /** |
| 106 * Hit test for whether a coordinate is within the distance threshold of an | 104 * Hit test for whether a coordinate is within the distance threshold of an |
| 107 * event. | 105 * event. |
| 108 */ | 106 */ |
| 109 static bool _hitTest(num x, num y, num eventX, num eventY) { | 107 static bool _hitTest(num x, num y, num eventX, num eventY) { |
| 110 return (eventX - x).abs() < _DISTANCE_THRESHOLD && | 108 return (eventX - x).abs() < _DISTANCE_THRESHOLD && |
| 111 (eventY - y).abs() < _DISTANCE_THRESHOLD; | 109 (eventY - y).abs() < _DISTANCE_THRESHOLD; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 // from propagating since there is no "allowable zone". | 171 // from propagating since there is no "allowable zone". |
| 174 // | 172 // |
| 175 // 3) User performs a should-not-be-busted click. | 173 // 3) User performs a should-not-be-busted click. |
| 176 // - touchstart event triggers the attached handler and creates a | 174 // - touchstart event triggers the attached handler and creates a |
| 177 // temporary "allowable zone". | 175 // temporary "allowable zone". |
| 178 // - The click handler captures the user's click event and allows it to | 176 // - The click handler captures the user's click event and allows it to |
| 179 // propagate since the click falls in the "allowable zone". | 177 // propagate since the click falls in the "allowable zone". |
| 180 if (_coordinates == null) { | 178 if (_coordinates == null) { |
| 181 // Listen to clicks on capture phase so they can be busted before anything | 179 // Listen to clicks on capture phase so they can be busted before anything |
| 182 // else gets a chance to handle them. | 180 // else gets a chance to handle them. |
| 183 Element.clickEvent.forTarget(document, useCapture: true).listen( | 181 Element.clickEvent.forTarget(document, useCapture: true).listen((e) { |
| 184 (e) { _onClick(e); }); | 182 _onClick(e); |
| 185 Element.focusEvent.forTarget(document, useCapture: true).listen( | 183 }); |
| 186 (e) { _lastPreventedTime = 0; }); | 184 Element.focusEvent.forTarget(document, useCapture: true).listen((e) { |
| 185 _lastPreventedTime = 0; |
| 186 }); |
| 187 | 187 |
| 188 // Listen to touchstart on capture phase since it must be called prior to | 188 // Listen to touchstart on capture phase since it must be called prior to |
| 189 // every click or else we will accidentally prevent the click even if we | 189 // every click or else we will accidentally prevent the click even if we |
| 190 // don't call preventGhostClick. | 190 // don't call preventGhostClick. |
| 191 Function startFn = (e) { _onTouchStart(e); }; | 191 Function startFn = (e) { |
| 192 _onTouchStart(e); |
| 193 }; |
| 192 if (!Device.supportsTouch) { | 194 if (!Device.supportsTouch) { |
| 193 startFn = mouseToTouchCallback(startFn); | 195 startFn = mouseToTouchCallback(startFn); |
| 194 } | 196 } |
| 195 var stream; | 197 var stream; |
| 196 if (Device.supportsTouch) { | 198 if (Device.supportsTouch) { |
| 197 stream = Element.touchStartEvent.forTarget(document, useCapture:true); | 199 stream = Element.touchStartEvent.forTarget(document, useCapture: true); |
| 198 } else { | 200 } else { |
| 199 stream = Element.mouseDownEvent.forTarget(document, useCapture:true); | 201 stream = Element.mouseDownEvent.forTarget(document, useCapture: true); |
| 200 } | 202 } |
| 201 EventUtil.observe(document, | 203 EventUtil.observe(document, stream, startFn, true); |
| 202 stream, | |
| 203 startFn, true); | |
| 204 _coordinates = new DoubleLinkedQueue<num>(); | 204 _coordinates = new DoubleLinkedQueue<num>(); |
| 205 } | 205 } |
| 206 | 206 |
| 207 // Turn tap highlights off until we know the ghost click has fired. | 207 // Turn tap highlights off until we know the ghost click has fired. |
| 208 _toggleTapHighlights(false); | 208 _toggleTapHighlights(false); |
| 209 | 209 |
| 210 // Above all other rules, we won't bust any clicks if there wasn't some call | 210 // Above all other rules, we won't bust any clicks if there wasn't some call |
| 211 // to preventGhostClick in the last time threshold. | 211 // to preventGhostClick in the last time threshold. |
| 212 _lastPreventedTime = TimeUtil.now(); | 212 _lastPreventedTime = TimeUtil.now(); |
| 213 DoubleLinkedQueueEntry<num> entry = _coordinates.firstEntry(); | 213 DoubleLinkedQueueEntry<num> entry = _coordinates.firstEntry(); |
| 214 while (entry != null) { | 214 while (entry != null) { |
| 215 if (_hitTest(entry.element, entry.nextEntry().element, x, y)) { | 215 if (_hitTest(entry.element, entry.nextEntry().element, x, y)) { |
| 216 entry.nextEntry().remove(); | 216 entry.nextEntry().remove(); |
| 217 entry.remove(); | 217 entry.remove(); |
| 218 return; | 218 return; |
| 219 } else { | 219 } else { |
| 220 entry = entry.nextEntry().nextEntry(); | 220 entry = entry.nextEntry().nextEntry(); |
| 221 } | 221 } |
| 222 } | 222 } |
| 223 } | 223 } |
| 224 } | 224 } |
| OLD | NEW |