Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

Commit

Permalink
fix(dropdown): fix keyboard-nav
Browse files Browse the repository at this point in the history
- Fix keyboard-nav for when not using append-to or append-to-body

Fixes #6102
Closes #6154
  • Loading branch information
Matt Lewis authored and wesleycho committed Aug 11, 2016
1 parent 0023d1b commit 6bad759
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 37 deletions.
17 changes: 8 additions & 9 deletions src/dropdown/dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,7 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
if (openScope === dropdownScope) {
openScope = null;
$document.off('click', closeDropdown);
var dropdownMenu = dropdownScope.getDropdownElement();
if (dropdownMenu) {
dropdownMenu.off('keydown', this.keybindFilter);
}
$document.off('keydown', this.keybindFilter);
}
};

Expand Down Expand Up @@ -60,11 +57,15 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
};

this.keybindFilter = function(evt) {
var dropdownElement = openScope.getDropdownElement();
var toggleElement = openScope.getToggleElement();
var dropdownElementTargeted = dropdownElement && dropdownElement[0].contains(evt.target);
var toggleElementTargeted = toggleElement && toggleElement[0].contains(evt.target);
if (evt.which === 27) {
evt.stopPropagation();
openScope.focusToggleElement();
closeDropdown();
} else if (openScope.isKeynavEnabled() && [38, 40].indexOf(evt.which) !== -1 && openScope.isOpen) {
} else if (openScope.isKeynavEnabled() && [38, 40].indexOf(evt.which) !== -1 && openScope.isOpen && (dropdownElementTargeted || toggleElementTargeted)) {
evt.preventDefault();
evt.stopPropagation();
openScope.focusDropdownEntry(evt.which);
Expand Down Expand Up @@ -256,13 +257,11 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
var newEl = dropdownElement;
self.dropdownMenu.replaceWith(newEl);
self.dropdownMenu = newEl;
self.dropdownMenu.on('keydown', uibDropdownService.keybindFilter);
$document.on('keydown', uibDropdownService.keybindFilter);
});
});
} else {
if (self.dropdownMenu) {
self.dropdownMenu.on('keydown', uibDropdownService.keybindFilter);
}
$document.on('keydown', uibDropdownService.keybindFilter);
}

scope.focusToggleElement();
Expand Down
52 changes: 24 additions & 28 deletions src/dropdown/test/dropdown.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -550,70 +550,67 @@ describe('uib-dropdown', function() {
function dropdown() {
return $compile('<li uib-dropdown keyboard-nav><a href uib-dropdown-toggle></a><ul uib-dropdown-menu><li><a href>Hello</a></li><li><a href>Hello Again</a></li></ul></li>')($rootScope);
}
function getFocusedElement() {
return angular.element(document.activeElement);
}
beforeEach(function() {
element = dropdown();
});

it('should focus first list element when down arrow pressed', function() {
var dropdownMenu = element.find('[uib-dropdown-menu]');
$document.find('body').append(element);
clickDropdownToggle();
triggerKeyDown(dropdownMenu, 40);
triggerKeyDown(getFocusedElement(), 40);

expect(element).toHaveClass(dropdownConfig.openClass);
var optionEl = element.find('ul').eq(0).find('a').eq(0);
expect(optionEl).toHaveFocus();
});

it('should not focus first list element when down arrow pressed if closed', function() {
var dropdownMenu = element.find('[uib-dropdown-menu]');
$document.find('body').append(element);
triggerKeyDown(dropdownMenu, 40);
triggerKeyDown(getFocusedElement(), 40);

expect(element).not.toHaveClass(dropdownConfig.openClass);
var focusEl = element.find('ul').eq(0).find('a').eq(0);
expect(focusEl).not.toHaveFocus();
});

it('should focus second list element when down arrow pressed twice', function() {
var dropdownMenu = element.find('[uib-dropdown-menu]');
$document.find('body').append(element);
clickDropdownToggle();
triggerKeyDown(dropdownMenu, 40);
triggerKeyDown(dropdownMenu, 40);
triggerKeyDown(getFocusedElement(), 40);
triggerKeyDown(getFocusedElement(), 40);

expect(element).toHaveClass(dropdownConfig.openClass);
var focusEl = element.find('ul').eq(0).find('a').eq(1);
expect(focusEl).toHaveFocus();
});

it('should not focus first list element when up arrow pressed after dropdown toggled', function() {
var dropdownMenu = element.find('[uib-dropdown-menu]');
$document.find('body').append(element);
clickDropdownToggle();
expect(element).toHaveClass(dropdownConfig.openClass);

triggerKeyDown(dropdownMenu, 38);
triggerKeyDown(getFocusedElement(), 38);
var focusEl = element.find('ul').eq(0).find('a').eq(0);
expect(focusEl).not.toHaveFocus();
});

it('should focus last list element when up arrow pressed after dropdown toggled', function() {
var dropdownMenu = element.find('[uib-dropdown-menu]');
$document.find('body').append(element);
clickDropdownToggle();
triggerKeyDown(dropdownMenu, 38);
triggerKeyDown(getFocusedElement(), 38);

expect(element).toHaveClass(dropdownConfig.openClass);
var focusEl = element.find('ul').eq(0).find('a').eq(1);
expect(focusEl).toHaveFocus();
});

it('should not change focus when other keys are pressed', function() {
var dropdownMenu = element.find('[uib-dropdown-menu]');
$document.find('body').append(element);
clickDropdownToggle();
triggerKeyDown(dropdownMenu, 37);
triggerKeyDown(getFocusedElement(), 37);

expect(element).toHaveClass(dropdownConfig.openClass);
var focusEl = element.find('ul').eq(0).find('a');
Expand All @@ -622,25 +619,23 @@ describe('uib-dropdown', function() {
});

it('should focus first list element when down arrow pressed 2x and up pressed 1x', function() {
var dropdownMenu = element.find('[uib-dropdown-menu]');
$document.find('body').append(element);
clickDropdownToggle();
triggerKeyDown(dropdownMenu, 40);
triggerKeyDown(dropdownMenu, 40);
triggerKeyDown(getFocusedElement(), 40);
triggerKeyDown(getFocusedElement(), 40);

triggerKeyDown(dropdownMenu, 38);
triggerKeyDown(getFocusedElement(), 38);

expect(element).toHaveClass(dropdownConfig.openClass);
var focusEl = element.find('ul').eq(0).find('a').eq(0);
expect(focusEl).toHaveFocus();
});

it('should stay focused on final list element if down pressed at list end', function() {
var dropdownMenu = element.find('[uib-dropdown-menu]');
$document.find('body').append(element);
clickDropdownToggle();
triggerKeyDown(dropdownMenu, 40);
triggerKeyDown(dropdownMenu, 40);
triggerKeyDown(getFocusedElement(), 40);
triggerKeyDown(getFocusedElement(), 40);

expect(element).toHaveClass(dropdownConfig.openClass);
var focusEl = element.find('ul').eq(0).find('a').eq(1);
Expand All @@ -652,47 +647,48 @@ describe('uib-dropdown', function() {

it('should close if esc is pressed while focused', function() {
element = dropdown('disabled');
var dropdownMenu = element.find('[uib-dropdown-menu]');
$document.find('body').append(element);
clickDropdownToggle();

triggerKeyDown(dropdownMenu, 40);
triggerKeyDown(getFocusedElement(), 40);

expect(element).toHaveClass(dropdownConfig.openClass);
var focusEl = element.find('ul').eq(0).find('a').eq(0);
expect(focusEl).toHaveFocus();

triggerKeyDown(dropdownMenu, 27);
triggerKeyDown(getFocusedElement(), 27);
expect(element).not.toHaveClass(dropdownConfig.openClass);
});

describe('with dropdown-append-to-body', function() {
function dropdown() {
return $compile('<li uib-dropdown dropdown-append-to-body keyboard-nav><a href uib-dropdown-toggle></a><ul uib-dropdown-menu id="dropdown-menu"><li><a href>Hello On Body</a></li><li><a href>Hello Again</a></li></ul></li>')($rootScope);
return $compile('<li uib-dropdown dropdown-append-to-body keyboard-nav><a href uib-dropdown-toggle>foo</a><ul uib-dropdown-menu id="dropdown-menu"><li><a href>Hello On Body</a></li><li><a href>Hello Again</a></li></ul></li>')($rootScope);
}

beforeEach(function() {
element = dropdown();
});

it('should focus first list element when down arrow pressed', function() {
$document.find('body').append(element);
clickDropdownToggle();

var dropdownMenu = $document.find('#dropdown-menu');

triggerKeyDown(dropdownMenu, 40);
triggerKeyDown(getFocusedElement(), 40);

expect(dropdownMenu.parent()).toHaveClass(dropdownConfig.appendToOpenClass);
var focusEl = $document.find('ul').eq(0).find('a');
expect(focusEl).toHaveFocus();
});

it('should focus second list element when down arrow pressed twice', function() {
$document.find('body').append(element);
clickDropdownToggle();
var dropdownMenu = $document.find('#dropdown-menu');
triggerKeyDown(dropdownMenu, 40);
triggerKeyDown(dropdownMenu, 40);
triggerKeyDown(dropdownMenu, 40);
triggerKeyDown(getFocusedElement(), 40);
triggerKeyDown(getFocusedElement(), 40);
triggerKeyDown(getFocusedElement(), 40);

expect(dropdownMenu.parent()).toHaveClass(dropdownConfig.appendToOpenClass);
var elem1 = $document.find('ul');
Expand Down

0 comments on commit 6bad759

Please sign in to comment.