Skip to content

Commit cb602b5

Browse files
committed
fix(tap): Prevent clicks from firing after scrolling, #579
1 parent 82b04ea commit cb602b5

File tree

4 files changed

+241
-50
lines changed

4 files changed

+241
-50
lines changed

Diff for: js/ext/angular/test/scroll2.html

+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
<html ng-app="navTest">
2+
<head>
3+
<meta charset="utf-8">
4+
<title>Scroll Click Tests</title>
5+
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
6+
<!--<link rel="stylesheet" href="../../../../dist/css/ionic.css">-->
7+
<script src="../../../../dist/js/ionic.bundle.js"></script>
8+
<style>
9+
#click-notify {
10+
position: absolute;
11+
top: 0;
12+
left: 0;
13+
z-index: 9997;
14+
display: none;
15+
padding: 8px;
16+
background: red;
17+
color: white;
18+
}
19+
#mousemove-notify {
20+
position: absolute;
21+
top: 40px;
22+
left: 0;
23+
z-index: 9998;
24+
display: none;
25+
padding: 8px;
26+
background: orange;
27+
}
28+
#touchmove-notify {
29+
position: absolute;
30+
top: 80px;
31+
left: 0;
32+
z-index: 9999;
33+
display: none;
34+
padding: 8px;
35+
background: yellow;
36+
}
37+
#touchcancel-notify {
38+
position: absolute;
39+
top: 120px;
40+
left: 0;
41+
z-index: 9999;
42+
display: none;
43+
padding: 8px;
44+
background: purple;
45+
color: white;
46+
}
47+
a {
48+
display: block;
49+
background: blue;
50+
margin: 40px 80px;
51+
padding: 40px;
52+
-webkit-tap-highlight-color: transparent;
53+
text-decoration: none;
54+
}
55+
.activated {
56+
background: yellow;
57+
}
58+
</style>
59+
</head>
60+
<body>
61+
62+
<div id="click-notify">CLICK!</div>
63+
<div id="mousemove-notify">Mouse Move!</div>
64+
<div id="touchmove-notify">Touch Move!</div>
65+
<div id="touchcancel-notify">Touch Cancel!</div>
66+
67+
<ion-view title="Home" hide-nav-bar="true">
68+
69+
<ion-content class="" scroll="false">
70+
71+
<a href='#' id="link">&nbsp;</a>
72+
73+
<div id="logs"></div>
74+
75+
</ion-content>
76+
77+
</ion-view>
78+
79+
<script>
80+
angular.module('navTest', ['ionic']);
81+
82+
var mouseTimerId;
83+
var mouseMoveCount = 0;
84+
function onMouseMove(e) {
85+
clearTimeout(mouseTimerId);
86+
mouseTimerId = setTimeout(function(){
87+
var el = document.getElementById('mousemove-notify');
88+
el.style.display = 'block';
89+
mouseMoveCount++;
90+
el.innerText = 'Mouse Move! ' + mouseMoveCount;
91+
clearTimeout(mouseTimerId);
92+
mouseTimerId = setTimeout(function(){
93+
el.style.display = 'none';
94+
}, 1000);
95+
}, 0);
96+
}
97+
98+
var touchTimerId;
99+
var touchMoveCount = 0;
100+
function onTouchMove(e) {
101+
clearTimeout(touchTimerId);
102+
touchTimerId = setTimeout(function(){
103+
var el = document.getElementById('touchmove-notify');
104+
el.style.display = 'block';
105+
touchMoveCount++;
106+
el.innerText = 'Touch Move! ' + touchMoveCount;
107+
clearTimeout(touchTimerId);
108+
touchTimerId = setTimeout(function(){
109+
el.style.display = 'none';
110+
}, 1000);
111+
}, 0);
112+
}
113+
114+
var touchCancelTimerId;
115+
var touchCancelMoveCount = 0;
116+
function onTouchCancel(e) {
117+
clearTimeout(touchCancelTimerId);
118+
touchCancelTimerId = setTimeout(function(){
119+
var el = document.getElementById('touchcancel-notify');
120+
el.style.display = 'block';
121+
touchCancelMoveCount++;
122+
el.innerText = 'Touch Cancel! ' + touchCancelMoveCount;
123+
clearTimeout(touchCancelTimerId);
124+
touchCancelTimerId = setTimeout(function(){
125+
el.style.display = 'none';
126+
}, 1000);
127+
}, 0);
128+
}
129+
130+
document.getElementById('link').addEventListener('click', onClick, false);
131+
132+
function onClick(e) {
133+
var el = document.getElementById('click-notify');
134+
el.style.display = 'block';
135+
el.innerText = 'Click!';
136+
137+
setTimeout(function(){
138+
document.getElementById('click-notify').style.display = 'none';
139+
}, 300);
140+
}
141+
142+
document.addEventListener('touchmove', onTouchMove, false);
143+
document.addEventListener('touchcancel', onTouchCancel, false);
144+
document.addEventListener('mousemove', onMouseMove, false);
145+
146+
147+
var index = 0;
148+
var timeId;
149+
var msgs = [];
150+
151+
console.debug = function() {
152+
index++;
153+
var msg = [];
154+
msg.push(index);
155+
for (var i = 0, j = arguments.length; i < j; i++){
156+
msg.push(arguments[i]);
157+
}
158+
msg.push(getTime());
159+
160+
msg = msg.join(', ');
161+
162+
if(arguments[0] === 'ERROR!') msg = '<span style="color:red;font-weight:bold">' + msg + '</span>';
163+
164+
if(arguments[0] === 'touchstart') msg = '<span style="color:blue">' + msg + '</span>';
165+
if(arguments[0] === 'touchend') msg = '<span style="color:darkblue">' + msg + '</span>';
166+
167+
if(arguments[0] === 'mousedown') msg = '<span style="color:red">' + msg + '</span>';
168+
if(arguments[0] === 'mouseup') msg = '<span style="color:maroon">' + msg + '</span>';
169+
170+
if(arguments[0] === 'click') msg = '<span style="color:purple">' + msg + '</span>';
171+
172+
if(arguments[1] === 'click') msg = '<span style="color:green;font-weight:bold">' + msg + '</span>';
173+
if(arguments[1] === 'change') msg = '<span style="color:orange;font-weight:bold">' + msg + '</span>';
174+
175+
msgs.unshift( msg );
176+
177+
if(msgs.length > 30) {
178+
msgs.splice(30);
179+
}
180+
181+
// do this so we try not to interfere with the device performance
182+
clearTimeout(timeId);
183+
timeId = setTimeout(function(){
184+
document.getElementById('logs').innerHTML = msgs.join('<br>');
185+
}, 150);
186+
187+
};
188+
189+
function getTime() {
190+
var d = new Date();
191+
return d.getSeconds() + '.' + d.getMilliseconds();
192+
}
193+
194+
</script>
195+
</body>
196+
</html>
197+

Diff for: js/ext/angular/test/service/ionicTap.unit.js

+18-35
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,13 @@ describe('Ionic Tap', function() {
55
ionic.tap.reset();
66
});
77

8-
it('Should not focus on an input if it has scrolled', function() {
9-
var targetEle = {
10-
dispatchEvent: function() {},
11-
focus: function() { this.isFocused = true; }
12-
};
13-
14-
ionic.tap.setStart({clientX: 100, clientY: 100});
15-
16-
targetEle.tagName = 'INPUT';
17-
var e = {
18-
clientX: 100, clientY: 200,
19-
preventDefault: function() {}
20-
};
21-
ionic.tap.simulateClick(targetEle, e);
22-
expect(targetEle.isFocused).toBeUndefined();
23-
});
24-
258
it('Should focus on an input if it hasnt scrolled', function() {
269
var targetEle = {
2710
dispatchEvent: function() {},
2811
focus: function() { this.isFocused = true; }
2912
};
3013

31-
ionic.tap.setStart({clientX: 100, clientY: 100});
14+
ionic.tap.setTouchStart({clientX: 100, clientY: 100});
3215

3316
targetEle.tagName = 'INPUT';
3417
var e = {
@@ -46,7 +29,7 @@ describe('Ionic Tap', function() {
4629
focus: function() {}
4730
};
4831

49-
ionic.tap.setStart({ clientX: 100, clientY: 100 });
32+
ionic.tap.setTouchStart({ clientX: 100, clientY: 100 });
5033
var e = {
5134
clientX: 100, clientY: 100,
5235
preventDefault: function() { this.preventedDefault = true }
@@ -68,46 +51,46 @@ describe('Ionic Tap', function() {
6851
e.preventedDefault = false;
6952
});
7053

71-
it('Should setStart and hasScrolled true if >= touch tolerance', function() {
72-
ionic.tap.setStart({ clientX: 100, clientY: 100 });
54+
it('Should setTouchStart and hasTouchScrolled true if >= touch tolerance', function() {
55+
ionic.tap.setTouchStart({ clientX: 100, clientY: 100 });
7356

74-
var s = ionic.tap.hasScrolled({ clientX: 111, clientY: 100 });
57+
var s = ionic.tap.hasTouchScrolled({ clientX: 111, clientY: 100 });
7558
expect(s).toEqual(true);
7659

77-
s = ionic.tap.hasScrolled({ clientX: 89, clientY: 100 });
60+
s = ionic.tap.hasTouchScrolled({ clientX: 89, clientY: 100 });
7861
expect(s).toEqual(true);
7962

80-
s = ionic.tap.hasScrolled({ clientX: 100, clientY: 107 });
63+
s = ionic.tap.hasTouchScrolled({ clientX: 100, clientY: 107 });
8164
expect(s).toEqual(true);
8265

83-
s = ionic.tap.hasScrolled({ clientX: 100, clientY: 93 });
66+
s = ionic.tap.hasTouchScrolled({ clientX: 100, clientY: 93 });
8467
expect(s).toEqual(true);
8568

86-
s = ionic.tap.hasScrolled({ clientX: 100, clientY: 200 });
69+
s = ionic.tap.hasTouchScrolled({ clientX: 100, clientY: 200 });
8770
expect(s).toEqual(true);
8871
});
8972

90-
it('Should setStart and hasScrolled false if less than touch tolerance', function() {
91-
ionic.tap.setStart({ clientX: 100, clientY: 100 });
73+
it('Should setTouchStart and hasTouchScrolled false if less than touch tolerance', function() {
74+
ionic.tap.setTouchStart({ clientX: 100, clientY: 100 });
9275

93-
var s = ionic.tap.hasScrolled({ clientX: 100, clientY: 100 });
76+
var s = ionic.tap.hasTouchScrolled({ clientX: 100, clientY: 100 });
9477
expect(s).toEqual(false);
9578

96-
s = ionic.tap.hasScrolled({ clientX: 104, clientY: 100 });
79+
s = ionic.tap.hasTouchScrolled({ clientX: 104, clientY: 100 });
9780
expect(s).toEqual(false);
9881

99-
s = ionic.tap.hasScrolled({ clientX: 96, clientY: 100 });
82+
s = ionic.tap.hasTouchScrolled({ clientX: 96, clientY: 100 });
10083
expect(s).toEqual(false);
10184

102-
s = ionic.tap.hasScrolled({ clientX: 100, clientY: 102 });
85+
s = ionic.tap.hasTouchScrolled({ clientX: 100, clientY: 102 });
10386
expect(s).toEqual(false);
10487

105-
s = ionic.tap.hasScrolled({ clientX: 100, clientY: 98 });
88+
s = ionic.tap.hasTouchScrolled({ clientX: 100, clientY: 98 });
10689
expect(s).toEqual(false);
10790
});
10891

109-
it('Should not be hasScrolled if 0 coordinates', function() {
110-
var s = ionic.tap.hasScrolled({ clientX: 0, clientY: 0 });
92+
it('Should not be hasTouchScrolled if 0 coordinates', function() {
93+
var s = ionic.tap.hasTouchScrolled({ clientX: 0, clientY: 0 });
11194
expect(s).toEqual(false);
11295
});
11396

Diff for: js/utils/activator.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@
4444
document.body.removeEventListener('mousedown', ionic.activator.start);
4545
touchMoveClearTimer = setTimeout(function(){
4646
document.body.addEventListener('touchmove', onTouchMove, false);
47-
}, 85);
48-
setTimeout(activateElements, 85);
47+
}, 80);
48+
setTimeout(activateElements, 80);
4949
} else {
5050
document.body.addEventListener('mousemove', clear, false);
5151
ionic.requestAnimationFrame(activateElements);
@@ -79,7 +79,7 @@
7979
}
8080

8181
function onTouchMove(e) {
82-
if( ionic.tap.hasScrolled(e) ) {
82+
if( ionic.tap.hasTouchScrolled(e) ) {
8383
clear();
8484
}
8585
}

0 commit comments

Comments
 (0)