Skip to content

Commit cf063c6

Browse files
authored
Merge pull request #27 from kreuzerk/feature/shift-selection-problems
Feature/shift selection problems
2 parents f395389 + 6795d60 commit cf063c6

File tree

4 files changed

+80
-24
lines changed

4 files changed

+80
-24
lines changed

projects/ng-sortgrid/src/lib/mutliselect/ngsg-selection.service.spec.ts

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
import createSpyObj = jasmine.createSpyObj;
22
import createSpy = jasmine.createSpy;
33

4-
import {NgsgSelectionService} from './ngsg-selection.service';
5-
import {NgsgClassService} from '../helpers/class/ngsg-class.service';
6-
import {NgsgStoreService} from '../store/ngsg-store.service';
7-
import {NgsgElementsHelper} from '../helpers/element/ngsg-elements.helper';
4+
import { NgsgSelectionService } from './ngsg-selection.service';
5+
import { NgsgClassService } from '../helpers/class/ngsg-class.service';
6+
import { NgsgStoreService } from '../store/ngsg-store.service';
7+
import { NgsgElementsHelper } from '../helpers/element/ngsg-elements.helper';
88

99
describe('NgsgSelectionService', () => {
10-
11-
const ngsgClassService = createSpyObj<NgsgClassService>('classService',
12-
['addSelectedClass', 'addSelectedClass', 'removeSelectedClass']);
13-
const ngsgStore = createSpyObj<NgsgStoreService>('ngsgStore',
14-
['addSelectedItem', 'hasSelectedItems', 'removeSelectedItem']);
10+
const ngsgClassService = createSpyObj<NgsgClassService>('classService', [
11+
'addSelectedClass',
12+
'addSelectedClass',
13+
'removeSelectedClass'
14+
]);
15+
const ngsgStore = createSpyObj<NgsgStoreService>('ngsgStore', [
16+
'addSelectedItem',
17+
'getSelectedItems',
18+
'hasSelectedItems',
19+
'removeSelectedItem',
20+
'resetSelectedItems'
21+
]);
1522
let sut: NgsgSelectionService;
1623

1724
beforeEach(() => {
@@ -24,7 +31,6 @@ describe('NgsgSelectionService', () => {
2431
});
2532

2633
describe('selectElementIfNoSelection', () => {
27-
2834
it('should call hasSelectedItems with the group', () => {
2935
ngsgStore.hasSelectedItems.and.returnValue(true);
3036
const dragedElement = 'Cool element' as any;
@@ -57,14 +63,13 @@ describe('NgsgSelectionService', () => {
5763

5864
expect(findIndexSpy).toHaveBeenCalledWith(dragedElement);
5965
expect(ngsgStore.addSelectedItem).toHaveBeenCalledWith(group, {
60-
node: dragedElement, originalIndex
66+
node: dragedElement,
67+
originalIndex
6168
});
6269
});
6370

6471
describe('Selection change', () => {
65-
6672
it('should add the selectedItem if the Meta key is pressed and the item is clicked', () => {
67-
6873
const event = new KeyboardEvent('keydown', {
6974
key: 'Meta'
7075
});
@@ -77,11 +82,10 @@ describe('NgsgSelectionService', () => {
7782
window.dispatchEvent(event);
7883
sut.updateSelectedDragItem(group, item, selected);
7984

80-
expect(ngsgStore.addSelectedItem).toHaveBeenCalledWith(group, {node: item, originalIndex: index});
85+
expect(ngsgStore.addSelectedItem).toHaveBeenCalledWith(group, { node: item, originalIndex: index });
8186
});
8287

8388
it('should remove the selectedItem if the Meta key is pressed and the selected item is clicked', () => {
84-
8589
const event = new KeyboardEvent('keydown', {
8690
key: 'Meta'
8791
});
@@ -99,7 +103,6 @@ describe('NgsgSelectionService', () => {
99103

100104
it(`should remove the selected class from the selected item if the Meta key is pressed
101105
and the selected item is clicked`, () => {
102-
103106
const event = new KeyboardEvent('keydown', {
104107
key: 'Meta'
105108
});
@@ -114,7 +117,28 @@ describe('NgsgSelectionService', () => {
114117

115118
expect(ngsgClassService.removeSelectedClass).toHaveBeenCalledWith(item);
116119
});
117-
});
118120

121+
it(`should reset the selected items if we click on an item without holding the shift key`, () => {
122+
const event = new KeyboardEvent('keyup', {
123+
key: 'Meta'
124+
});
125+
const itemOne = { node: 'Foo' };
126+
const itemTwo = { node: 'Bar' };
127+
const items = [itemOne, itemTwo];
128+
const group = 'groupOne';
129+
const item = 'Some element' as any;
130+
const selected = false;
131+
const index = 2;
132+
133+
NgsgElementsHelper.findIndex = () => index;
134+
ngsgStore.getSelectedItems.and.returnValue(items);
135+
window.dispatchEvent(event);
136+
sut.updateSelectedDragItem(group, item, selected);
137+
138+
expect(ngsgClassService.removeSelectedClass).toHaveBeenCalledWith(itemOne.node);
139+
expect(ngsgClassService.removeSelectedClass).toHaveBeenCalledWith(itemTwo.node);
140+
expect(ngsgStore.resetSelectedItems).toHaveBeenCalledWith(group);
141+
});
142+
});
119143
});
120144
});

projects/ng-sortgrid/src/lib/mutliselect/ngsg-selection.service.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { Injectable } from '@angular/core';
2-
import { fromEvent, merge, NEVER, Observable, Subject } from 'rxjs';
3-
import { filter, mapTo, switchMap } from 'rxjs/operators';
1+
import {Injectable} from '@angular/core';
2+
import {fromEvent, merge, NEVER, Observable, Subject} from 'rxjs';
3+
import {filter, mapTo, switchMap, withLatestFrom} from 'rxjs/operators';
44
import {NgsgClassService} from '../helpers/class/ngsg-class.service';
55
import {NgsgStoreService} from '../store/ngsg-store.service';
66
import {NgsgElementsHelper} from '../helpers/element/ngsg-elements.helper';
@@ -27,9 +27,18 @@ export class NgsgSelectionService {
2727

2828
constructor(private classService: NgsgClassService, private ngsgStore: NgsgStoreService) {
2929
const selectionKeyPressed$ = this.selectionKeyPressed();
30-
selectionKeyPressed$
31-
.pipe(switchMap(pressed => (pressed ? this.selectionChange$ : NEVER)))
32-
.subscribe((selectionChange: SelectionChange) => this.handleSelectionChange(selectionChange));
30+
this.selectionChange$
31+
.pipe(withLatestFrom(selectionKeyPressed$))
32+
.subscribe(([selectionChange, selectionKeyPressed]) => {
33+
selectionKeyPressed
34+
? this.handleSelectionChange(selectionChange)
35+
: this.resetSelectedItems(selectionChange.key);
36+
});
37+
}
38+
39+
private resetSelectedItems(group: string): void {
40+
this.ngsgStore.getSelectedItems(group).forEach(item => this.classService.removeSelectedClass(item.node));
41+
this.ngsgStore.resetSelectedItems(group);
3342
}
3443

3544
private handleSelectionChange(selectionChange: SelectionChange): void {

projects/ng-sortgrid/src/lib/ngsg-item.directive.spec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {NgsgReflectService} from './sort/reflection/ngsg-reflect.service';
88
import {NgsgStoreService} from './store/ngsg-store.service';
99
import {NgsgEventsService} from './shared/ngsg-events.service';
1010
import {NgsgOrderChange} from './shared/ngsg-order-change.model';
11+
import {NgsgElementsHelper} from './helpers/element/ngsg-elements.helper';
1112

1213
describe('NgsgItemDirective', () => {
1314
let sut: NgsgItemDirective;
@@ -22,6 +23,7 @@ describe('NgsgItemDirective', () => {
2223
const ngsgStore = createSpyObj<NgsgStoreService>('ngsgStore', [
2324
'initState',
2425
'hasSelectedItems',
26+
'getSelectedItems',
2527
'resetSelectedItems',
2628
'hasGroup',
2729
'hasItems',
@@ -169,12 +171,26 @@ describe('NgsgItemDirective', () => {
169171

170172
it('should call the selctionservice with the host if the event occured on the host', () => {
171173
const group = 'test-group';
174+
NgsgElementsHelper.findIndex = () => 0;
175+
ngsgStore.getSelectedItems.and.returnValue([]);
172176
sut.ngSortGridGroup = group;
173177

174178
sut.clicked();
175179
expect(ngsgSelectionService.updateSelectedDragItem).toHaveBeenCalledWith(group, elementRef.nativeElement, true);
176180
});
177181

182+
it('should call the selection service with false if the item is selected', () => {
183+
const originalIndex = 0;
184+
const group = 'test-group';
185+
const element = {originalIndex};
186+
NgsgElementsHelper.findIndex = () => originalIndex;
187+
ngsgStore.getSelectedItems.and.returnValue([element]);
188+
sut.ngSortGridGroup = group;
189+
190+
sut.clicked();
191+
expect(ngsgSelectionService.updateSelectedDragItem).toHaveBeenCalledWith(group, elementRef.nativeElement, false);
192+
});
193+
178194
it(`should init the state with empty items if group has yet not been
179195
initialized and the currentValue is null`, () => {
180196
const group = 'test-group';

projects/ng-sortgrid/src/lib/ngsg-item.directive.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {NgsgStoreService} from './store/ngsg-store.service';
2222
import {NgsgEventsService} from './shared/ngsg-events.service';
2323
import {ScrollHelperService} from './helpers/scroll/scroll-helper.service';
2424
import {NgsgOrderChange} from './shared/ngsg-order-change.model';
25+
import {NgsgElementsHelper} from './helpers/element/ngsg-elements.helper';
2526

2627
const selector = '[ngSortgridItem]';
2728

@@ -135,10 +136,16 @@ export class NgsgItemDirective implements OnInit, OnChanges, AfterViewInit, OnDe
135136

136137
@HostListener('click', ['$event'])
137138
clicked(): void {
138-
this.selected = !this.selected;
139+
this.selected = !this.isItemCurrentlySelected();
139140
this.selectionService.updateSelectedDragItem(this.ngSortGridGroup, this.el.nativeElement, this.selected);
140141
}
141142

143+
private isItemCurrentlySelected(): boolean {
144+
const index = NgsgElementsHelper.findIndex(this.el.nativeElement);
145+
return !!this.ngsgStore.getSelectedItems(this.ngSortGridGroup)
146+
.find(element => element.originalIndex === index);
147+
}
148+
142149
private occuredOnHost(event): boolean {
143150
return event.target.matches(selector);
144151
}

0 commit comments

Comments
 (0)