/// /// Copyright 2015-2026 Micro Focus or one of its affiliates. /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// import { DOWN_ARROW, ENTER, SPACE, UP_ARROW } from '@angular/cdk/keycodes'; import { SelectionStrategy } from '../../../directives/selection/index'; export class MultipleSelectListStrategy extends SelectionStrategy { private _lastSelection: T; /** Prevent the browser from highlighting text on shift click */ mousedown(event: MouseEvent): void { event.preventDefault(); } click(event: MouseEvent, data: T): void { // activate the clicked item this.selectionService.activate(data); // if the shift key is pressed we want to perform a multiple selection if (event.shiftKey) { return this.multipleSelect(data); } // otherwise perform a single toggle selection if (this.selectionService.isSelected(data)) { this.deselect(data); this._lastSelection = null; } else { this.select(data); this._lastSelection = data; } } keydown(event: KeyboardEvent, data: T): void { switch (event.which) { case UP_ARROW: { event.preventDefault(); const sibling = this.selectionService.activateSibling(true); if (event.shiftKey) { this.select(data, sibling); this._lastSelection = sibling; } break; } case DOWN_ARROW: { event.preventDefault(); const sibling = this.selectionService.activateSibling(false); if (event.shiftKey) { this.select(data, sibling); this._lastSelection = sibling; } break; } case SPACE: case ENTER: event.preventDefault(); this.toggle(data); this._lastSelection = this.selectionService.isSelected(data) ? data : null; break; } } multipleSelect(data: T): void { // if there is no start item selected if (!this._lastSelection) { this.select(data); this._lastSelection = data; return; } // if there already is a start item then find the items in the range this.select(...this.getSelectedItems(this._lastSelection, data)); // store the selection end point this._lastSelection = data; } private getSelectedItems(start: T, end: T): T[] { // get the latest dataset const { dataset } = this.selectionService; // get the indexes of the start and end point const startIdx = dataset.indexOf(start); const endIdx = dataset.indexOf(end); // get the region of the array that is selected - note the endIdx may be before the startIdx so account for this return dataset.slice(Math.min(startIdx, endIdx), Math.max(startIdx, endIdx) + 1); } }