diff --git a/src/lib/list/selection-list.spec.ts b/src/lib/list/selection-list.spec.ts index ff75fb24088..73b6b610d04 100644 --- a/src/lib/list/selection-list.spec.ts +++ b/src/lib/list/selection-list.spec.ts @@ -196,6 +196,26 @@ describe('MatSelectionList without forms', () => { expect(ENTER_EVENT.defaultPrevented).toBe(true); }); + it('should not be able to toggle an item when pressing a modifier key', () => { + const testListItem = listOptions[1].nativeElement as HTMLElement; + const selectList = + selectionList.injector.get(MatSelectionList).selectedOptions; + + expect(selectList.selected.length).toBe(0); + + [ENTER, SPACE].forEach(key => { + const event = createKeyboardEvent('keydown', key, testListItem); + Object.defineProperty(event, 'ctrlKey', { get: () => true }); + + dispatchFakeEvent(testListItem, 'focus'); + selectionList.componentInstance._keydown(event); + fixture.detectChanges(); + expect(event.defaultPrevented).toBe(false); + }); + + expect(selectList.selected.length).toBe(0); + }); + it('should not be able to toggle a disabled option using SPACE', () => { const testListItem = listOptions[1].nativeElement as HTMLElement; const selectionModel = selectionList.componentInstance.selectedOptions; @@ -332,6 +352,20 @@ describe('MatSelectionList without forms', () => { expect(event.defaultPrevented).toBe(true); }); + it('should not change focus when pressing HOME with a modifier key', () => { + const manager = selectionList.componentInstance._keyManager; + expect(manager.activeItemIndex).toBe(-1); + + const event = createKeyboardEvent('keydown', HOME); + Object.defineProperty(event, 'shiftKey', { get: () => true }); + + dispatchEvent(selectionList.nativeElement, event); + fixture.detectChanges(); + + expect(manager.activeItemIndex).toBe(-1); + expect(event.defaultPrevented).toBe(false); + }); + it('should focus the last item when pressing END', () => { const manager = selectionList.componentInstance._keyManager; expect(manager.activeItemIndex).toBe(-1); @@ -343,6 +377,20 @@ describe('MatSelectionList without forms', () => { expect(event.defaultPrevented).toBe(true); }); + it('should not change focus when pressing END with a modifier key', () => { + const manager = selectionList.componentInstance._keyManager; + expect(manager.activeItemIndex).toBe(-1); + + const event = createKeyboardEvent('keydown', END); + Object.defineProperty(event, 'shiftKey', { get: () => true }); + + dispatchEvent(selectionList.nativeElement, event); + fixture.detectChanges(); + + expect(manager.activeItemIndex).toBe(-1); + expect(event.defaultPrevented).toBe(false); + }); + it('should select all items using ctrl + a', () => { const event = createKeyboardEvent('keydown', A, selectionList.nativeElement); Object.defineProperty(event, 'ctrlKey', {get: () => true}); diff --git a/src/lib/list/selection-list.ts b/src/lib/list/selection-list.ts index 4d6adeeef88..06934817a22 100644 --- a/src/lib/list/selection-list.ts +++ b/src/lib/list/selection-list.ts @@ -9,7 +9,16 @@ import {FocusableOption, FocusKeyManager} from '@angular/cdk/a11y'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {SelectionModel} from '@angular/cdk/collections'; -import {SPACE, ENTER, HOME, END, UP_ARROW, DOWN_ARROW, A} from '@angular/cdk/keycodes'; +import { + SPACE, + ENTER, + HOME, + END, + UP_ARROW, + DOWN_ARROW, + A, + hasModifierKey, +} from '@angular/cdk/keycodes'; import { AfterContentInit, Attribute, @@ -417,21 +426,26 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu const keyCode = event.keyCode; const manager = this._keyManager; const previousFocusIndex = manager.activeItemIndex; + const hasModifier = hasModifierKey(event); switch (keyCode) { case SPACE: case ENTER: - this._toggleFocusedOption(); - // Always prevent space from scrolling the page since the list has focus - event.preventDefault(); + if (!hasModifier) { + this._toggleFocusedOption(); + // Always prevent space from scrolling the page since the list has focus + event.preventDefault(); + } break; case HOME: case END: - keyCode === HOME ? manager.setFirstItemActive() : manager.setLastItemActive(); - event.preventDefault(); + if (!hasModifier) { + keyCode === HOME ? manager.setFirstItemActive() : manager.setLastItemActive(); + event.preventDefault(); + } break; case A: - if (event.ctrlKey) { + if (hasModifierKey(event, 'ctrlKey')) { this.options.find(option => !option.selected) ? this.selectAll() : this.deselectAll(); event.preventDefault(); }