Skip to content

Commit

Permalink
fix(click): Clicks firing twice, closes #573
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam Bradley committed Feb 10, 2014
1 parent e40e205 commit 2132d29
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 23 deletions.
49 changes: 29 additions & 20 deletions js/ext/angular/test/clickTests.html
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@
<i class="radio-icon ion-checkmark"></i>
</label>

<div class="item item-checkbox" style="padding-left: 58px !important">
<label class="checkbox">
<input type="checkbox" ng-model="htmlCheckboxData.checkedValue">
</label>
Checkbox {{ htmlCheckboxData.checkedValue }}</a>
</div>

</div>
</div>

Expand All @@ -130,6 +137,8 @@

.controller('MyCtrl', function($scope) {

$scope.htmlCheckboxData = {};

$scope.otherTests = function() {
if($scope.testBtnText == 'HTML') {
$scope.testBtnText = 'AngJS';
Expand All @@ -140,47 +149,47 @@
$scope.otherTests();

$scope.htmlToggleClick = function() {
console.log('htmlToggleClick', 'click');
console.debug('htmlToggleClick', 'click');
$scope.buttonValue = 'html' + Math.floor(Math.random() * 999);
};

$scope.stringClick = 'stringMethod()';
$scope.stringMethod = function() {
console.log('toggle {{ stringClick }]', 'click');
console.debug('toggle {{ stringClick }]', 'click');
$scope.buttonValue = 'tg' + Math.floor(Math.random() * 999);
};

$scope.itemClick = function() {
console.log('itemClick()', 'click');
console.debug('itemClick()', 'click');
$scope.buttonValue = 'itm' + Math.floor(Math.random() * 999);
};

$scope.menuItems = [
{
label: 'Item 1',
actionItem: function() {
console.log('item.actionItem()', 'click')
console.debug('item.actionItem()', 'click')
$scope.buttonValue = 'itm' + Math.floor(Math.random() * 999);
}
}
];

$scope.buttonClick = function() {
console.log('button ng-click', 'click')
console.debug('button ng-click', 'click')
$scope.buttonValue = 'btn' + Math.floor(Math.random() * 999);
};

$scope.divClick = function() {
console.log('div ng-click', 'click')
console.debug('div ng-click', 'click')
$scope.buttonValue = 'div' + Math.floor(Math.random() * 999);
};
$scope.radioModel = {}
$scope.radioChange = function() {
console.log('radio ng-change', 'change', $scope.radioModel.data);
console.debug('radio ng-change', 'change', $scope.radioModel.data);
};

$scope.radioClick = function(val) {
console.log('radio ng-click', 'click', val);
console.debug('radio ng-click', 'click', val);
$scope.buttonValue = 'rd' + Math.floor(Math.random() * 999);
};

Expand All @@ -192,23 +201,23 @@
}

document.getElementById('radio1').addEventListener('change', function(){
console.log('radio 1', 'change');
console.debug('radio 1', 'change');
});
document.getElementById('radio1').addEventListener('click', function(){
console.log('radio 1', 'click');
console.debug('radio 1', 'click');
});
document.getElementById('radio2').addEventListener('change', function(){
console.log('radio 2', 'change');
console.debug('radio 2', 'change');
});
document.getElementById('radio2').addEventListener('click', function(){
console.log('radio 2', 'click');
console.debug('radio 2', 'click');
});

document.addEventListener('touchstart', function(e){
console.log('touchstart');
console.debug('touchstart');
});
document.addEventListener('touchend', function(e){
console.log('touchend');
console.debug('touchend');
if(!e.changedTouches || !e.changedTouches.length) return;

var dot = document.createElement('div');
Expand All @@ -223,16 +232,16 @@
}, 3000);
});
document.addEventListener('mousedown', function(){
console.log('mousedown');
console.debug('mousedown');
});
document.addEventListener('mouseup', function(){
console.log('mouseup');
console.debug('mouseup');
});
// document.addEventListener('mousemove', function(event){
// console.log('mousemove', 'clientX: ' + event.clientX, 'clientY: ' + event.clientY);
// console.debug('mousemove', 'clientX: ' + event.clientX, 'clientY: ' + event.clientY);
// });
document.addEventListener('click', function(event){
console.log('click', 'clientX: ' + event.clientX, 'clientY: ' + event.clientY);
console.debug('click', 'clientX: ' + event.clientX, 'clientY: ' + event.clientY);
});
document.getElementById('clear').addEventListener('click', function(){
setTimeout(clearMsgs, 200);
Expand All @@ -258,10 +267,10 @@
for (var i = 0, j = arguments.length; i < j; i++){
args.push(arguments[i]);
}
console.log.apply(this, args);
console.debug.apply(this, args);
};

console.log = function() {
console.debug = function() {
//return;
if(stopped) return;

Expand Down
17 changes: 14 additions & 3 deletions js/utils/poly.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
// simulate a normal click by running the element's click method then focus on it
if(ele.disabled) return;

console.debug('tapElement', ele.tagName, ele.className);

var c = getCoordinates(e);

// using initMouseEvent instead of MouseEvent for our Android friends
Expand All @@ -50,7 +52,10 @@
}

// remember the coordinates of this tap so if it happens again we can ignore it
recordCoordinates(e);
// but only if the coordinates are not already being actively disabled
if( !isRecentTap(e) ) {
recordCoordinates(e);
}

// set the last tap time so if a click event quickly happens it knows to ignore it
ele.lastTap = Date.now();
Expand All @@ -65,12 +70,14 @@

if( isRecentTap(e) ) {
// if a tap in the same area just happened, don't continue
console.debug('tapPolyfill', 'isRecentTap', ele.tagName);
return;
}

if(e.target.lastClick && e.target.lastClick + CLICK_PREVENT_DURATION > Date.now()) {
if(ele.lastClick && ele.lastClick + CLICK_PREVENT_DURATION > Date.now()) {
// if a click recently happend on this element, don't continue
// (yes on some devices it's possible for a click to happen before a touchend)
console.debug('tapPolyfill', 'recent lastClick', ele.tagName);
return;
}

Expand Down Expand Up @@ -111,6 +118,7 @@
if(e.target.control.labelLastTap && e.target.control.labelLastTap + CLICK_PREVENT_DURATION > Date.now()) {
// Android will fire a click for the label, and a click for the input which it is associated to
// this stops the second ghost click from the label from continuing
console.debug('preventGhostClick', 'labelLastTap');
e.stopPropagation();
e.preventDefault();
return false;
Expand All @@ -122,19 +130,22 @@
// The input's click event will propagate so don't bother letting this label's click
// propagate cuz it causes double clicks. However, do NOT e.preventDefault(), because
// the label still needs to click the input
console.debug('preventGhostClick', 'label stopPropagation');
e.stopPropagation();
return;
}

if( isRecentTap(e) ) {
// a tap has already happened at these coordinates recently, ignore this event
console.debug('preventGhostClick', 'isRecentTap', e.target.tagName);
e.stopPropagation();
e.preventDefault();
return false;
}

if(e.target.lastTap && e.target.lastTap + CLICK_PREVENT_DURATION > Date.now()) {
// this element has already had the tap poly fill run on it recently, ignore this event
console.debug('preventGhostClick', 'e.target.lastTap', e.target.tagName);
e.stopPropagation();
e.preventDefault();
return false;
Expand Down Expand Up @@ -201,7 +212,7 @@
}

var tapCoordinates = {}; // used to remember coordinates to ignore if they happen again quickly
var CLICK_PREVENT_DURATION = 350; // amount of milliseconds to check for ghostclicks
var CLICK_PREVENT_DURATION = 450; // amount of milliseconds to check for ghostclicks

// set global click handler and check if the event should stop or not
document.addEventListener('click', preventGhostClick, true);
Expand Down

0 comments on commit 2132d29

Please sign in to comment.