Skip to content

Commit a8f4c2a

Browse files
authored
Merge pull request #16 from kreuzerk/feature/scrollPoints
Feature/scroll points
2 parents 507e1ca + e8f6d07 commit a8f4c2a

File tree

7 files changed

+130
-77
lines changed

7 files changed

+130
-77
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
[![codecov](https://codecov.io/gh/kreuzerk/ng-sortgrid/branch/master/graph/badge.svg)](https://codecov.io/gh/kreuzerk/ng-sortgrid)
33
[![angular7](https://img.shields.io/badge/angular%207%20ready-true-green.svg)]()
44

5+
# Ng-sortgrid
6+
57
![Logo](https://raw.githubusercontent.com/kreuzerk/ng-sortgrid/master/projects/ng-sortgrid-demo/src/assets/logo-new.png)
68

79
![Grid demo](https://raw.githubusercontent.com/kreuzerk/ng-sortgrid/master/projects/ng-sortgrid-demo/src/assets/grid-demo.gif)
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import {ScrollHelperService} from './scroll-helper.service';
2+
import SpyObj = jasmine.SpyObj;
3+
4+
describe('Scroll helper', () => {
5+
6+
let sut: ScrollHelperService;
7+
const documentMock = {
8+
defaultView: {
9+
innerHeight: 0,
10+
innerWidth: 0,
11+
scrollBy: () => {
12+
}
13+
}
14+
};
15+
let scrollSpy: SpyObj<any>;
16+
17+
beforeEach(() => {
18+
sut = new ScrollHelperService(documentMock);
19+
scrollSpy = spyOn(documentMock.defaultView, 'scrollBy');
20+
});
21+
22+
describe('Top scroll', () => {
23+
24+
it('should scroll to the top with the default scroll speed when we drag over the top viewport', () => {
25+
const element = {
26+
getBoundingClientRect: () => ({top: -100, left: 0, bottom: 0, right: 0})
27+
} as any;
28+
sut.scrollIfNecessary(element);
29+
expect(scrollSpy).toHaveBeenCalledWith({top: -50, behavior: 'smooth'});
30+
});
31+
32+
it('should scroll to the top with the default scroll speed when we drag over the top scroll position', () => {
33+
const element = {
34+
getBoundingClientRect: () => ({top: 120, left: 0, bottom: 0, right: 0})
35+
} as any;
36+
sut.scrollIfNecessary(element, {top: 140});
37+
expect(scrollSpy).toHaveBeenCalledWith({top: -50, behavior: 'smooth'});
38+
});
39+
40+
it('should scroll to the top with the custom scroll speed when we drag over the top viewport', () => {
41+
const element = {
42+
getBoundingClientRect: () => ({top: -100, left: 0, bottom: 0, right: 0})
43+
} as any;
44+
const scrollSpeed = 100;
45+
sut.scrollIfNecessary(element, {}, scrollSpeed);
46+
expect(scrollSpy).toHaveBeenCalledWith({top: -scrollSpeed, behavior: 'smooth'});
47+
});
48+
49+
});
50+
51+
describe('Bottom scroll', () => {
52+
53+
it('should scroll to the bottom with the default scroll speed when we drag over the bottom viewport', () => {
54+
const element = {
55+
getBoundingClientRect: () => ({top: 100, left: 0, bottom: 20, right: 0})
56+
} as any;
57+
sut.scrollIfNecessary(element);
58+
expect(scrollSpy).toHaveBeenCalledWith({top: 50, behavior: 'smooth'});
59+
});
60+
61+
it('should scroll to the bottom with the default scroll speed when we drag over the bottom scroll position', () => {
62+
const element = {
63+
getBoundingClientRect: () => ({top: 120, left: 0, bottom: 200, right: 0})
64+
} as any;
65+
sut.scrollIfNecessary(element, {bottom: 140});
66+
expect(scrollSpy).toHaveBeenCalledWith({top: 50, behavior: 'smooth'});
67+
});
68+
69+
it('should scroll to the top with the custom scroll speed when we drag over the top viewport', () => {
70+
const element = {
71+
getBoundingClientRect: () => ({top: 20, left: 0, bottom: 20, right: 0})
72+
} as any;
73+
const scrollSpeed = 100;
74+
sut.scrollIfNecessary(element, {}, scrollSpeed);
75+
expect(scrollSpy).toHaveBeenCalledWith({top: scrollSpeed, behavior: 'smooth'});
76+
});
77+
78+
});
79+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import {Inject, Injectable} from '@angular/core';
2+
import {DOCUMENT} from '@angular/common';
3+
4+
export interface ScrollPoints {
5+
top?: number;
6+
bottom?: number;
7+
}
8+
9+
@Injectable({
10+
providedIn: 'root'
11+
})
12+
export class ScrollHelperService {
13+
14+
private window: WindowProxy;
15+
private DEFAULT_SCROLLSPEED = 50;
16+
17+
constructor(@Inject(DOCUMENT) private document) {
18+
this.window = document.defaultView;
19+
}
20+
21+
public scrollIfNecessary(element: HTMLElement, scrollPoints: ScrollPoints = {}, scrollSpeed?: number): void {
22+
const bounding = element.getBoundingClientRect();
23+
if (this.isTopScrollNeeded(bounding.top, scrollPoints.top)) {
24+
this.window.scrollBy({top: -scrollSpeed || -this.DEFAULT_SCROLLSPEED, behavior: 'smooth'});
25+
return;
26+
}
27+
28+
if (this.isBottomScrollNeeded(bounding.top, scrollPoints.bottom)) {
29+
this.window.scrollBy({top: scrollSpeed || this.DEFAULT_SCROLLSPEED, behavior: 'smooth'});
30+
}
31+
}
32+
33+
private isTopScrollNeeded(topBounding: number, scrollPointTop: number): boolean {
34+
return scrollPointTop ? topBounding < scrollPointTop : topBounding < 0;
35+
}
36+
37+
private isBottomScrollNeeded(bottomBounding: number, scrollPointBottom: number): boolean {
38+
return scrollPointBottom ? bottomBounding < scrollPointBottom : bottomBounding > this.window.innerHeight;
39+
}
40+
}

projects/ng-sortgrid/src/lib/helpers/view-port.helper.service.ts

Lines changed: 0 additions & 32 deletions
This file was deleted.

projects/ng-sortgrid/src/lib/helpers/view-port.service.ts

Lines changed: 0 additions & 28 deletions
This file was deleted.

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,9 @@ describe('NgsgItemDirective', () => {
2727
'setItems'
2828
]);
2929
const ngsgEventService = new NgsgEventsService();
30-
const viewPortService = {
31-
isOutOfViewport: () => ({
32-
top: false,
33-
bottom: false
34-
})
30+
const scrollHelperService = {
31+
scrollIfNecessary: () => {
32+
}
3533
} as any;
3634

3735
beforeEach(() => {
@@ -42,7 +40,7 @@ describe('NgsgItemDirective', () => {
4240
ngsgReflectService,
4341
ngsgStore,
4442
ngsgEventService,
45-
viewPortService
43+
scrollHelperService
4644
);
4745
});
4846

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

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,22 @@ import {NgsgStoreService} from './ngsg-store.service';
1717
import {NgsgSortService} from './ngsg-sort.service';
1818
import {NgsgSelectionService} from './ngsg-selection.service';
1919
import {NgsgEventsService} from './ngsg-events.service';
20+
import {ScrollHelperService} from './helpers/scroll-helper.service';
2021
import {Subject} from 'rxjs';
2122
import {takeUntil} from 'rxjs/operators';
22-
import {ViewPortService} from './helpers/view-port.service';
2323

2424
const selector = '[ngSortgridItem]';
2525

2626
@Directive({selector})
2727
export class NgsgItemDirective implements OnInit, OnChanges, AfterViewInit, OnDestroy {
2828
@Input() ngSortGridGroup = 'defaultGroup';
2929
@Input() ngSortGridItems;
30+
@Input() scrollPointTop;
31+
@Input() scrollSpeed;
3032

3133
@Output() sorted = new EventEmitter<any>();
3234

3335
private selected = false;
34-
private SCROLLSPEED = 100;
3536
private destroy$ = new Subject();
3637

3738
constructor(
@@ -41,7 +42,7 @@ export class NgsgItemDirective implements OnInit, OnChanges, AfterViewInit, OnDe
4142
private reflectService: NgsgReflectService,
4243
private ngsgStore: NgsgStoreService,
4344
private ngsgEventService: NgsgEventsService,
44-
private viewPortService: ViewPortService
45+
private scrollHelperService: ScrollHelperService
4546
) {
4647
}
4748

@@ -90,14 +91,7 @@ export class NgsgItemDirective implements OnInit, OnChanges, AfterViewInit, OnDe
9091

9192
@HostListener('dragover', ['$event'])
9293
dragOver(event): boolean {
93-
94-
if (this.viewPortService.isOutOfViewport(event.target).top) {
95-
window.scrollBy({top: -this.SCROLLSPEED, behavior: 'smooth'});
96-
}
97-
98-
if (this.viewPortService.isOutOfViewport(event.target).bottom) {
99-
window.scrollBy({top: this.SCROLLSPEED, behavior: 'smooth'});
100-
}
94+
this.scrollHelperService.scrollIfNecessary(event.target, {top: this.scrollPointTop}, this.scrollSpeed);
10195

10296
if (event.preventDefault) {
10397
// Necessary. Allows us to drop.

0 commit comments

Comments
 (0)