From 52a55ec61895951999cb0d74e706725b965e9c9f Mon Sep 17 00:00:00 2001 From: Braden Shepherdson Date: Fri, 12 Apr 2013 14:03:36 -0400 Subject: feat(ngTap): Add a CSS class while the element is held down. --- src/ngMobile/directive/ngClick.js | 33 ++++++++++++++++++++++++++++----- test/ngMobile/directive/ngClickSpec.js | 20 +++++++++++++++++++- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/ngMobile/directive/ngClick.js b/src/ngMobile/directive/ngClick.js index b3e3007d..a6f6ed19 100644 --- a/src/ngMobile/directive/ngClick.js +++ b/src/ngMobile/directive/ngClick.js @@ -2,11 +2,19 @@ /** * @ngdoc directive - * @name ngMobile.directive:ngTap + * @name ngMobile.directive:ngClick * * @description - * Specify custom behavior when element is tapped on a touchscreen device. - * A tap is a brief, down-and-up touch without much motion. + * A more powerful replacement for the default ngClick designed to be used on touchscreen + * devices. Most mobile browsers wait about 300ms after a tap-and-release before sending + * the click event. This version handles them immediately, and then prevents the + * following click event from propagating. + * + * This directive can fall back to using an ordinary click event, and so works on desktop + * browsers as well as mobile. + * + * This directive also sets the CSS class `ng-click-active` while the element is being held + * down (by a mouse click or touch) so you can restyle the depressed element if you wish. * * @element ANY * @param {expression} ngClick {@link guide/expression Expression} to evaluate @@ -15,7 +23,7 @@ * @example - count: {{ count }} @@ -37,6 +45,8 @@ ngMobile.directive('ngClick', ['$parse', '$timeout', '$rootElement', var MOVE_TOLERANCE = 12; // 12px seems to work in most mobile browsers. var PREVENT_DURATION = 2500; // 2.5 seconds maximum from preventGhostClick call to click var CLICKBUSTER_THRESHOLD = 25; // 25 pixels in any dimension is the limit for busting clicks. + + var ACTIVE_CLASS_NAME = 'ng-click-active'; var lastPreventedTime; var touchCoordinates; @@ -172,6 +182,7 @@ ngMobile.directive('ngClick', ['$parse', '$timeout', '$rootElement', function resetState() { tapping = false; + element.removeClass(ACTIVE_CLASS_NAME); } element.bind('touchstart', function(event) { @@ -182,6 +193,8 @@ ngMobile.directive('ngClick', ['$parse', '$timeout', '$rootElement', tapElement = tapElement.parentNode; } + element.addClass(ACTIVE_CLASS_NAME); + startTime = Date.now(); var touches = event.touches && event.touches.length ? event.touches : [event]; @@ -224,7 +237,8 @@ ngMobile.directive('ngClick', ['$parse', '$timeout', '$rootElement', clickHandler(scope, {$event: event}); }); } - tapping = false; + + resetState(); }); // Hack for iOS Safari's benefit. It goes searching for onclick handlers and is liable to click @@ -239,6 +253,15 @@ ngMobile.directive('ngClick', ['$parse', '$timeout', '$rootElement', clickHandler(scope, {$event: event}); }); }); + + element.bind('mousedown', function(event) { + element.addClass(ACTIVE_CLASS_NAME); + }); + + element.bind('mousemove mouseup', function(event) { + element.removeClass(ACTIVE_CLASS_NAME); + }); + }; }]); diff --git a/test/ngMobile/directive/ngClickSpec.js b/test/ngMobile/directive/ngClickSpec.js index 2f42662d..dd7ffed0 100644 --- a/test/ngMobile/directive/ngClickSpec.js +++ b/test/ngMobile/directive/ngClickSpec.js @@ -82,7 +82,7 @@ describe('ngClick (mobile)', function() { it('should not click if a touchmove comes before touchend', inject(function($rootScope, $compile, $rootElement) { - element = $compile('
')($rootScope); + element = $compile('
')($rootScope); $rootElement.append(element); $rootScope.$digest(); @@ -95,6 +95,22 @@ describe('ngClick (mobile)', function() { expect($rootScope.tapped).toBeUndefined(); })); + it('should add the CSS class while the element is held down, and then remove it', inject(function($rootScope, $compile, $rootElement) { + element = $compile('
')($rootScope); + $rootElement.append(element); + $rootScope.$digest(); + expect($rootScope.tapped).toBeUndefined(); + + var CSS_CLASS = 'ng-click-active'; + + expect(element.hasClass(CSS_CLASS)).toBe(false); + browserTrigger(element, 'touchstart', 10, 10); + expect(element.hasClass(CSS_CLASS)).toBe(true); + browserTrigger(element, 'touchend', 10, 10); + expect(element.hasClass(CSS_CLASS)).toBe(false); + expect($rootScope.tapped).toBe(true); + })); + describe('the clickbuster', function() { var element1, element2; @@ -292,4 +308,6 @@ describe('ngClick (mobile)', function() { expect($rootScope.event).toBeDefined(); })); }); + + }); -- cgit v1.2.3