Skip to content

Commit

Permalink
Merge pull request #16 from kreuzerk/feature/scrollPoints
Browse files Browse the repository at this point in the history
Feature/scroll points
  • Loading branch information
nivekcode authored Sep 30, 2019
2 parents 507e1ca + e8f6d07 commit a8f4c2a
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 77 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
[![codecov](https://codecov.io/gh/kreuzerk/ng-sortgrid/branch/master/graph/badge.svg)](https://codecov.io/gh/kreuzerk/ng-sortgrid)
[![angular7](https://img.shields.io/badge/angular%207%20ready-true-green.svg)]()

# Ng-sortgrid

![Logo](https://raw.githubusercontent.com/kreuzerk/ng-sortgrid/master/projects/ng-sortgrid-demo/src/assets/logo-new.png)

![Grid demo](https://raw.githubusercontent.com/kreuzerk/ng-sortgrid/master/projects/ng-sortgrid-demo/src/assets/grid-demo.gif)
Expand Down
79 changes: 79 additions & 0 deletions projects/ng-sortgrid/src/lib/helpers/scroll-helper.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import {ScrollHelperService} from './scroll-helper.service';
import SpyObj = jasmine.SpyObj;

describe('Scroll helper', () => {

let sut: ScrollHelperService;
const documentMock = {
defaultView: {
innerHeight: 0,
innerWidth: 0,
scrollBy: () => {
}
}
};
let scrollSpy: SpyObj<any>;

beforeEach(() => {
sut = new ScrollHelperService(documentMock);
scrollSpy = spyOn(documentMock.defaultView, 'scrollBy');
});

describe('Top scroll', () => {

it('should scroll to the top with the default scroll speed when we drag over the top viewport', () => {
const element = {
getBoundingClientRect: () => ({top: -100, left: 0, bottom: 0, right: 0})
} as any;
sut.scrollIfNecessary(element);
expect(scrollSpy).toHaveBeenCalledWith({top: -50, behavior: 'smooth'});
});

it('should scroll to the top with the default scroll speed when we drag over the top scroll position', () => {
const element = {
getBoundingClientRect: () => ({top: 120, left: 0, bottom: 0, right: 0})
} as any;
sut.scrollIfNecessary(element, {top: 140});
expect(scrollSpy).toHaveBeenCalledWith({top: -50, behavior: 'smooth'});
});

it('should scroll to the top with the custom scroll speed when we drag over the top viewport', () => {
const element = {
getBoundingClientRect: () => ({top: -100, left: 0, bottom: 0, right: 0})
} as any;
const scrollSpeed = 100;
sut.scrollIfNecessary(element, {}, scrollSpeed);
expect(scrollSpy).toHaveBeenCalledWith({top: -scrollSpeed, behavior: 'smooth'});
});

});

describe('Bottom scroll', () => {

it('should scroll to the bottom with the default scroll speed when we drag over the bottom viewport', () => {
const element = {
getBoundingClientRect: () => ({top: 100, left: 0, bottom: 20, right: 0})
} as any;
sut.scrollIfNecessary(element);
expect(scrollSpy).toHaveBeenCalledWith({top: 50, behavior: 'smooth'});
});

it('should scroll to the bottom with the default scroll speed when we drag over the bottom scroll position', () => {
const element = {
getBoundingClientRect: () => ({top: 120, left: 0, bottom: 200, right: 0})
} as any;
sut.scrollIfNecessary(element, {bottom: 140});
expect(scrollSpy).toHaveBeenCalledWith({top: 50, behavior: 'smooth'});
});

it('should scroll to the top with the custom scroll speed when we drag over the top viewport', () => {
const element = {
getBoundingClientRect: () => ({top: 20, left: 0, bottom: 20, right: 0})
} as any;
const scrollSpeed = 100;
sut.scrollIfNecessary(element, {}, scrollSpeed);
expect(scrollSpy).toHaveBeenCalledWith({top: scrollSpeed, behavior: 'smooth'});
});

});
});
40 changes: 40 additions & 0 deletions projects/ng-sortgrid/src/lib/helpers/scroll-helper.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {Inject, Injectable} from '@angular/core';
import {DOCUMENT} from '@angular/common';

export interface ScrollPoints {
top?: number;
bottom?: number;
}

@Injectable({
providedIn: 'root'
})
export class ScrollHelperService {

private window: WindowProxy;
private DEFAULT_SCROLLSPEED = 50;

constructor(@Inject(DOCUMENT) private document) {
this.window = document.defaultView;
}

public scrollIfNecessary(element: HTMLElement, scrollPoints: ScrollPoints = {}, scrollSpeed?: number): void {
const bounding = element.getBoundingClientRect();
if (this.isTopScrollNeeded(bounding.top, scrollPoints.top)) {
this.window.scrollBy({top: -scrollSpeed || -this.DEFAULT_SCROLLSPEED, behavior: 'smooth'});
return;
}

if (this.isBottomScrollNeeded(bounding.top, scrollPoints.bottom)) {
this.window.scrollBy({top: scrollSpeed || this.DEFAULT_SCROLLSPEED, behavior: 'smooth'});
}
}

private isTopScrollNeeded(topBounding: number, scrollPointTop: number): boolean {
return scrollPointTop ? topBounding < scrollPointTop : topBounding < 0;
}

private isBottomScrollNeeded(bottomBounding: number, scrollPointBottom: number): boolean {
return scrollPointBottom ? bottomBounding < scrollPointBottom : bottomBounding > this.window.innerHeight;
}
}
32 changes: 0 additions & 32 deletions projects/ng-sortgrid/src/lib/helpers/view-port.helper.service.ts

This file was deleted.

28 changes: 0 additions & 28 deletions projects/ng-sortgrid/src/lib/helpers/view-port.service.ts

This file was deleted.

10 changes: 4 additions & 6 deletions projects/ng-sortgrid/src/lib/ngsg-item.directive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,9 @@ describe('NgsgItemDirective', () => {
'setItems'
]);
const ngsgEventService = new NgsgEventsService();
const viewPortService = {
isOutOfViewport: () => ({
top: false,
bottom: false
})
const scrollHelperService = {
scrollIfNecessary: () => {
}
} as any;

beforeEach(() => {
Expand All @@ -42,7 +40,7 @@ describe('NgsgItemDirective', () => {
ngsgReflectService,
ngsgStore,
ngsgEventService,
viewPortService
scrollHelperService
);
});

Expand Down
16 changes: 5 additions & 11 deletions projects/ng-sortgrid/src/lib/ngsg-item.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,22 @@ import {NgsgStoreService} from './ngsg-store.service';
import {NgsgSortService} from './ngsg-sort.service';
import {NgsgSelectionService} from './ngsg-selection.service';
import {NgsgEventsService} from './ngsg-events.service';
import {ScrollHelperService} from './helpers/scroll-helper.service';
import {Subject} from 'rxjs';
import {takeUntil} from 'rxjs/operators';
import {ViewPortService} from './helpers/view-port.service';

const selector = '[ngSortgridItem]';

@Directive({selector})
export class NgsgItemDirective implements OnInit, OnChanges, AfterViewInit, OnDestroy {
@Input() ngSortGridGroup = 'defaultGroup';
@Input() ngSortGridItems;
@Input() scrollPointTop;
@Input() scrollSpeed;

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

private selected = false;
private SCROLLSPEED = 100;
private destroy$ = new Subject();

constructor(
Expand All @@ -41,7 +42,7 @@ export class NgsgItemDirective implements OnInit, OnChanges, AfterViewInit, OnDe
private reflectService: NgsgReflectService,
private ngsgStore: NgsgStoreService,
private ngsgEventService: NgsgEventsService,
private viewPortService: ViewPortService
private scrollHelperService: ScrollHelperService
) {
}

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

@HostListener('dragover', ['$event'])
dragOver(event): boolean {

if (this.viewPortService.isOutOfViewport(event.target).top) {
window.scrollBy({top: -this.SCROLLSPEED, behavior: 'smooth'});
}

if (this.viewPortService.isOutOfViewport(event.target).bottom) {
window.scrollBy({top: this.SCROLLSPEED, behavior: 'smooth'});
}
this.scrollHelperService.scrollIfNecessary(event.target, {top: this.scrollPointTop}, this.scrollSpeed);

if (event.preventDefault) {
// Necessary. Allows us to drop.
Expand Down

0 comments on commit a8f4c2a

Please sign in to comment.