Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Commit

Permalink
fix(ngClick): subract processing time of the click action
Browse files Browse the repository at this point in the history
subract the time it takes for the browser to process the click action for preventing the ghost click. long running processes or slower devices where a lot of rendering is happening would get the ghost click every time.
  • Loading branch information
Tr4v1s authored and travis committed Dec 11, 2015
1 parent 25e8c59 commit 879309f
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 1 deletion.
12 changes: 11 additions & 1 deletion src/ngTouch/directive/ngClick.js
Expand Up @@ -57,6 +57,7 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',

var ACTIVE_CLASS_NAME = 'ng-click-active';
var lastPreventedTime;
var processingTime;
var touchCoordinates;
var lastLabelClickCoordinates;

Expand Down Expand Up @@ -121,7 +122,7 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
// Global click handler that prevents the click if it's in a bustable zone and preventGhostClick
// was called recently.
function onClick(event) {
if (Date.now() - lastPreventedTime > PREVENT_DURATION) {
if (Date.now() - lastPreventedTime - processingTime > PREVENT_DURATION) {
return; // Too old.
}

Expand Down Expand Up @@ -197,6 +198,14 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
checkAllowableRegions(touchCoordinates, x, y);
}

function calculateProcessingTime() {
//use the now - last prevented time on a timeout
processingTime = 0;
$timeout(function() {
processingTime = Date.now() - lastPreventedTime;
}, 0);
}

// Actual linking function.
return function(scope, element, attr) {
var clickHandler = $parse(attr.ngClick),
Expand Down Expand Up @@ -251,6 +260,7 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
if (tapping && diff < TAP_DURATION && dist < MOVE_TOLERANCE) {
// Call preventGhostClick so the clickbuster will catch the corresponding click.
preventGhostClick(x, y);
calculateProcessingTime();

// Blur the focused element (the button, probably) before firing the callback.
// This doesn't work perfectly on Android Chrome, but seems to work elsewhere.
Expand Down
79 changes: 79 additions & 0 deletions test/ngTouch/directive/ngClickSpec.js
Expand Up @@ -233,6 +233,85 @@ describe('ngClick (touch)', function() {
}));


it('should cancel the following click event with long running processes', inject(function($rootScope, $compile, $rootElement, $timeout) {
//we need the real date now function for really getting the time... to really test the timeout...
Date.now = orig_now;
var count = 0;
var done = false;

$rootScope.slowCount = function() {
var start = Date.now();
var now = Date.now();
//must wait longer than the PREVENT_DURATION
while (now - start < 3000) {
now = Date.now();
}
count++;
};

element = $compile('<div ng-click="slowCount()"></div>')($rootScope);
$rootElement.append(element);

$rootScope.$digest();

expect(count).toBe(0);

// Fire touchstart at 10ms, touchend at 50ms, the click at 300ms.
runs(function() {
setTimeout(function() {
browserTrigger(element, 'touchstart', {
keys: [],
x: 10,
y: 10
});
try {
$timeout.verifyNoPendingTasks();
} catch (e) {
$timeout.flush();
}
}, 10);

setTimeout(function() {
browserTrigger(element, 'touchend', {
keys: [],
x: 10,
y: 10
});
try {
$timeout.verifyNoPendingTasks();
} catch (e) {
$timeout.flush();
}

expect(count).toBe(1);
}, 50);

setTimeout(function() {
browserTrigger(element, 'click', {
keys: [],
x: 10,
y: 10
});
try {
$timeout.verifyNoPendingTasks();
} catch (e) {
$timeout.flush();
}
done = true;
}, 300);

});

waitsFor(function() {
return done;
}, "click event to fire", 500);

runs(function() {
expect(count).toEqual(1);
});
}));


it('should cancel the following click event even when the element has changed', inject(
function($rootScope, $compile, $rootElement) {
$rootElement.append(
Expand Down

0 comments on commit 879309f

Please sign in to comment.