Skip to content
This repository was archived by the owner on Jan 13, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/mdc-list/foundation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ export class MDCListFoundation extends MDCFoundation<MDCListAdapter> {
this.toggleCheckboxRange(
currentIndex, this.adapter.getListItemCount() - 1, currentIndex);
} else if (
isLetterA && eventHasModifiers(['Control']) && this.isCheckboxList) {
isLetterA && (eventHasModifiers(['Control']) || eventHasModifiers(['Meta'])) && this.isCheckboxList) {
event.preventDefault();
this.checkboxListToggleAll(
this.selectedIndex === numbers.UNSET_INDEX ?
Expand Down
158 changes: 158 additions & 0 deletions packages/mdc-list/test/foundation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1371,6 +1371,164 @@ describe('MDCListFoundation', () => {
.toHaveBeenCalledWith(2, true);
});

it('#handleKeydown should select all items on command(metaKey) + A, if nothing is selected',
() => {
const {foundation, mockAdapter} = setupTest();
const event = createMockKeyboardEvent('A', ['Meta']);

mockAdapter.hasCheckboxAtIndex.withArgs(0).and.returnValue(true);
mockAdapter.getListItemCount.and.returnValue(3);
foundation.layout();
foundation.handleKeydown(event, false, -1);

expect(event.preventDefault).toHaveBeenCalledTimes(1);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledTimes(3);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(0, true);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(1, true);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(2, true);
});

it('#handleKeydown should select all items on command(metaKey) + lowercase A, if nothing is selected',
() => {
const {foundation, mockAdapter} = setupTest();
const event = createMockKeyboardEvent('a', ['Meta']);

mockAdapter.hasCheckboxAtIndex.withArgs(0).and.returnValue(true);
mockAdapter.getListItemCount.and.returnValue(3);
foundation.layout();
foundation.handleKeydown(event, false, -1);

expect(event.preventDefault).toHaveBeenCalledTimes(1);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledTimes(3);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(0, true);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(1, true);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(2, true);
});

it('#handleKeydown should select all items on command(metaKey) + A, if some items are selected',
() => {
const {foundation, mockAdapter} = setupTest();
const event = createMockKeyboardEvent('A', ['Meta']);

mockAdapter.hasCheckboxAtIndex.withArgs(0).and.returnValue(true);
mockAdapter.getListItemCount.and.returnValue(4);
foundation.layout();
foundation.setSelectedIndex([1, 2]);

// Reset the calls since `setSelectedIndex` will throw it off.
mockAdapter.setCheckedCheckboxOrRadioAtIndex.calls.reset();
foundation.handleKeydown(event, false, -1);

expect(event.preventDefault).toHaveBeenCalledTimes(1);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledTimes(4);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(0, true);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(1, true);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(2, true);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(3, true);
});

it('#handleKeydown should deselect all items on command(metaKey) + A, if all items are selected',
() => {
const {foundation, mockAdapter} = setupTest();
const event = createMockKeyboardEvent('A', ['Meta']);

mockAdapter.hasCheckboxAtIndex.withArgs(0).and.returnValue(true);
mockAdapter.getListItemCount.and.returnValue(3);
foundation.layout();
foundation.setSelectedIndex([0, 1, 2]);

// Reset the calls since `setSelectedIndex` will throw it off.
mockAdapter.setCheckedCheckboxOrRadioAtIndex.calls.reset();
foundation.handleKeydown(event, false, -1);

expect(event.preventDefault).toHaveBeenCalledTimes(1);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledTimes(3);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(0, false);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(1, false);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(2, false);
});

it('#handleKeydown should not select disabled items on command(metaKey) + A', () => {
const {foundation, mockAdapter} = setupTest();
const event = createMockKeyboardEvent('A', ['Meta']);

mockAdapter.hasCheckboxAtIndex.withArgs(0).and.returnValue(true);
mockAdapter.listItemAtIndexHasClass
.withArgs(1, cssClasses.LIST_ITEM_DISABLED_CLASS)
.and.returnValue(true);
mockAdapter.getListItemCount.and.returnValue(3);
foundation.layout();
foundation.handleKeydown(event, false, -1);

expect(event.preventDefault).toHaveBeenCalledTimes(1);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledTimes(3);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(0, true);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(1, false);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(2, true);
});

it('#handleKeydown should not handle command(metaKey) + A on a non-checkbox list', () => {
const {foundation, mockAdapter} = setupTest();
const event = createMockKeyboardEvent('a', ['Meta']);

mockAdapter.hasCheckboxAtIndex.withArgs(0).and.returnValue(false);
mockAdapter.getListItemCount.and.returnValue(3);
foundation.layout();
foundation.handleKeydown(event, false, -1);

expect(event.preventDefault).not.toHaveBeenCalled();
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex).not.toHaveBeenCalled();
});

it('#handleKeydown should not deselect a selected disabled item on command(metaKey) + A',
() => {
const {foundation, mockAdapter} = setupTest();
const event = createMockKeyboardEvent('A', ['Meta']);

mockAdapter.hasCheckboxAtIndex.withArgs(0).and.returnValue(true);
mockAdapter.listItemAtIndexHasClass
.withArgs(1, cssClasses.LIST_ITEM_DISABLED_CLASS)
.and.returnValue(true);
mockAdapter.getListItemCount.and.returnValue(3);
foundation.layout();
foundation.setSelectedIndex([1]);

// Reset the calls since `setSelectedIndex` will throw it off.
mockAdapter.setCheckedCheckboxOrRadioAtIndex.calls.reset();
foundation.handleKeydown(event, false, -1);

expect(event.preventDefault).toHaveBeenCalledTimes(1);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledTimes(3);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(0, true);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(1, true);
expect(mockAdapter.setCheckedCheckboxOrRadioAtIndex)
.toHaveBeenCalledWith(2, true);
});

it('#focusNextElement retains the focus on last item when wrapFocus=false and returns that index',
() => {
const {foundation, mockAdapter} = setupTest();
Expand Down