diff --git a/src/ngAria/aria.js b/src/ngAria/aria.js index 904d9a0e5959..73e9e0733f9f 100644 --- a/src/ngAria/aria.js +++ b/src/ngAria/aria.js @@ -387,7 +387,10 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) { if ($aria.config('bindKeydown') && !attr.ngKeydown && !attr.ngKeypress && !attr.ngKeyup) { elem.on('keydown', function(event) { var keyCode = event.which || event.keyCode; - if (keyCode === 32 || keyCode === 13) { + + if (keyCode === 13 || keyCode === 32) { + // Prevent the default browser behavior (e.g. scrolling when pressing spacebar). + event.preventDefault(); scope.$apply(callback); } diff --git a/test/ngAria/ariaSpec.js b/test/ngAria/ariaSpec.js index 1970b01438b0..11130b17430e 100644 --- a/test/ngAria/ariaSpec.js +++ b/test/ngAria/ariaSpec.js @@ -922,116 +922,101 @@ describe('$aria', function() { }); describe('accessible actions', function() { - beforeEach(injectScopeAndCompiler); - - var clickFn; - - it('should trigger a click from the keyboard', function() { - scope.someAction = function() {}; + var clickEvents; - var elements = $compile('
' + - '
' + - '' + - '
')(scope); - - scope.$digest(); + beforeEach(injectScopeAndCompiler); + beforeEach(function() { + clickEvents = []; + scope.onClick = jasmine.createSpy('onClick').and.callFake(function(evt) { + var nodeName = evt ? evt.target.nodeName.toLowerCase() : ''; + var prevented = !!(evt && evt.isDefaultPrevented()); + clickEvents.push(nodeName + '(' + prevented + ')'); + }); + }); - clickFn = spyOn(scope, 'someAction'); + it('should trigger a click from the keyboard (and prevent default action)', function() { + compileElement( + '
' + + '
' + + '' + + '
'); - var divElement = elements.find('div'); - var liElement = elements.find('li'); + var divElement = element.find('div'); + var liElement = element.find('li'); + divElement.triggerHandler({type: 'keydown', keyCode: 13}); + liElement.triggerHandler({type: 'keydown', keyCode: 13}); divElement.triggerHandler({type: 'keydown', keyCode: 32}); liElement.triggerHandler({type: 'keydown', keyCode: 32}); - expect(clickFn).toHaveBeenCalledWith('div'); - expect(clickFn).toHaveBeenCalledWith('li'); + expect(clickEvents).toEqual(['div(true)', 'li(true)', 'div(true)', 'li(true)']); }); - it('should trigger a click in browsers that provide event.which instead of event.keyCode', function() { - scope.someAction = function() {}; + it('should trigger a click in browsers that provide `event.which` instead of `event.keyCode`', + function() { + compileElement( + '
' + + '
' + + '' + + '
'); + + var divElement = element.find('div'); + var liElement = element.find('li'); - var elements = $compile('
' + - '
' + - '' + - '
')(scope); + divElement.triggerHandler({type: 'keydown', which: 13}); + liElement.triggerHandler({type: 'keydown', which: 13}); + divElement.triggerHandler({type: 'keydown', which: 32}); + liElement.triggerHandler({type: 'keydown', which: 32}); - scope.$digest(); + expect(clickEvents).toEqual(['div(true)', 'li(true)', 'div(true)', 'li(true)']); + } + ); - clickFn = spyOn(scope, 'someAction'); + they('should not bind to key events if there is existing `ng-$prop`', + ['keydown', 'keypress', 'keyup'], function(eventName) { + scope.onKeyEvent = jasmine.createSpy('onKeyEvent'); + compileElement('
'); - var divElement = elements.find('div'); - var liElement = elements.find('li'); + element.triggerHandler({type: eventName, keyCode: 13}); + element.triggerHandler({type: eventName, keyCode: 32}); - divElement.triggerHandler({type: 'keydown', which: 32}); - liElement.triggerHandler({type: 'keydown', which: 32}); + expect(scope.onClick).not.toHaveBeenCalled(); + expect(scope.onKeyEvent).toHaveBeenCalledTimes(2); + } + ); - expect(clickFn).toHaveBeenCalledWith('div'); - expect(clickFn).toHaveBeenCalledWith('li'); - }); + it('should update bindings when keydown is handled', function() { + scope.count = 0; + compileElement('
Count: {{ count }}
'); - it('should not bind to key events if there is existing ng-keydown', function() { - scope.onClick = jasmine.createSpy('onClick'); - scope.onKeydown = jasmine.createSpy('onKeydown'); + expect(element.text()).toBe('Count: 0'); - var tmpl = '
'; - compileElement(tmpl); + element.triggerHandler({type: 'keydown', keyCode: 13}); + expect(element.text()).toBe('Count: 1'); element.triggerHandler({type: 'keydown', keyCode: 32}); - - expect(scope.onKeydown).toHaveBeenCalled(); - expect(scope.onClick).not.toHaveBeenCalled(); + expect(element.text()).toBe('Count: 2'); }); - it('should not bind to key events if there is existing ng-keypress', function() { - scope.onClick = jasmine.createSpy('onClick'); - scope.onKeypress = jasmine.createSpy('onKeypress'); - - var tmpl = '
'; - compileElement(tmpl); + it('should pass `$event` to `ng-click` handler as local', function() { + compileElement('
{{ event.type }}{{ event.keyCode }}
'); + expect(element.text()).toBe(''); - element.triggerHandler({type: 'keypress', keyCode: 32}); + element.triggerHandler({type: 'keydown', keyCode: 13}); + expect(element.text()).toBe('keydown13'); - expect(scope.onKeypress).toHaveBeenCalled(); - expect(scope.onClick).not.toHaveBeenCalled(); + element.triggerHandler({type: 'keydown', keyCode: 32}); + expect(element.text()).toBe('keydown32'); }); - it('should not bind to key events if there is existing ng-keyup', function() { - scope.onClick = jasmine.createSpy('onClick'); - scope.onKeyup = jasmine.createSpy('onKeyup'); - - var tmpl = '
'; - compileElement(tmpl); + it('should not bind keydown to natively interactive elements', function() { + compileElement(''); - element.triggerHandler({type: 'keyup', keyCode: 32}); + element.triggerHandler({type: 'keydown', keyCode: 13}); + element.triggerHandler({type: 'keydown', keyCode: 32}); - expect(scope.onKeyup).toHaveBeenCalled(); expect(scope.onClick).not.toHaveBeenCalled(); }); - - it('should update bindings when keydown is handled', function() { - compileElement('
{{text}}
'); - expect(element.text()).toBe(''); - spyOn(scope.$root, '$digest').and.callThrough(); - element.triggerHandler({ type: 'keydown', keyCode: 13 }); - expect(element.text()).toBe('clicked!'); - expect(scope.$root.$digest).toHaveBeenCalledOnce(); - }); - - it('should pass $event to ng-click handler as local', function() { - compileElement('
{{event.type}}' + - '{{event.keyCode}}
'); - expect(element.text()).toBe(''); - element.triggerHandler({ type: 'keydown', keyCode: 13 }); - expect(element.text()).toBe('keydown13'); - }); - - it('should not bind keydown to natively interactive elements', function() { - compileElement(''); - expect(element.text()).toBe(''); - element.triggerHandler({ type: 'keydown', keyCode: 13 }); - expect(element.text()).toBe(''); - }); }); describe('actions when bindRoleForClick is set to false', function() {