diff --git a/projects/ng-sortgrid/src/lib/helpers/view-port.helper.service.ts b/projects/ng-sortgrid/src/lib/helpers/view-port.helper.service.ts new file mode 100644 index 0000000..fee6ed7 --- /dev/null +++ b/projects/ng-sortgrid/src/lib/helpers/view-port.helper.service.ts @@ -0,0 +1,32 @@ +import {ViewPortService} from './view-port.service'; +import {beforeEach} from '@angular/core/testing/src/testing_internal'; + +describe('Viewport helper', () => { + + let sut: ViewPortService; + const documentMock = { + defaultView: { + innerHeight: 0, + innerWidth: 0 + }, + }; + + beforeEach(() => sut = new ViewPortService(documentMock)); + + it('should detect when we drag over the top viewport', () => { + const element = { + getBoundingClientRect: () => ({top: -100, left: 0, bottom: 0, right: 0}) + } as any; + const viewPortOverflow = sut.isOutOfViewport(element); + expect(viewPortOverflow.top).toBeTruthy(); + }); + + it('should detect when we drag over the bottom viewport', () => { + spyOn(window, 'innerHeight').and.returnValue(0); + const element = { + getBoundingClientRect: () => ({top: 0, left: 0, bottom: 100, right: 0}) + } as any; + const viewPortOverflow = sut.isOutOfViewport(element); + expect(viewPortOverflow.bottom).toBeTruthy(); + }); +}); diff --git a/projects/ng-sortgrid/src/lib/helpers/view-port.service.ts b/projects/ng-sortgrid/src/lib/helpers/view-port.service.ts new file mode 100644 index 0000000..1a04a3f --- /dev/null +++ b/projects/ng-sortgrid/src/lib/helpers/view-port.service.ts @@ -0,0 +1,28 @@ +import {Inject, Injectable} from '@angular/core'; +import {DOCUMENT} from '@angular/common'; + +export interface ViewPortOverflow { + top: boolean; + bottom: boolean; +} + +@Injectable({ + providedIn: 'root' +}) +export class ViewPortService { + + private window: WindowProxy; + + constructor(@Inject(DOCUMENT) private document) { + this.window = document.defaultView; + } + + public isOutOfViewport(element: HTMLElement): ViewPortOverflow { + + const bounding = element.getBoundingClientRect(); + return { + top: bounding.top < 0, + bottom: bounding.bottom > (this.window.innerHeight || document.documentElement.clientHeight) + }; + } +} diff --git a/projects/ng-sortgrid/src/lib/ngsg-item.directive.spec.ts b/projects/ng-sortgrid/src/lib/ngsg-item.directive.spec.ts index 8dbfe98..012e390 100644 --- a/projects/ng-sortgrid/src/lib/ngsg-item.directive.spec.ts +++ b/projects/ng-sortgrid/src/lib/ngsg-item.directive.spec.ts @@ -27,6 +27,12 @@ describe('NgsgItemDirective', () => { 'setItems' ]); const ngsgEventService = new NgsgEventsService(); + const viewPortService = { + isOutOfViewport: () => ({ + top: false, + bottom: false + }) + } as any; beforeEach(() => { sut = new NgsgItemDirective( @@ -35,7 +41,8 @@ describe('NgsgItemDirective', () => { ngsgSelectionService, ngsgReflectService, ngsgStore, - ngsgEventService + ngsgEventService, + viewPortService ); }); diff --git a/projects/ng-sortgrid/src/lib/ngsg-item.directive.ts b/projects/ng-sortgrid/src/lib/ngsg-item.directive.ts index 22b4da6..2512252 100644 --- a/projects/ng-sortgrid/src/lib/ngsg-item.directive.ts +++ b/projects/ng-sortgrid/src/lib/ngsg-item.directive.ts @@ -5,21 +5,21 @@ import { EventEmitter, HostListener, Input, - NgZone, OnChanges, OnDestroy, + OnChanges, + OnDestroy, OnInit, - Output, SimpleChanges + Output, + SimpleChanges } from '@angular/core'; import {NgsgReflectService} from './ngsg-reflect.service'; import {NgsgStoreService} from './ngsg-store.service'; import {NgsgSortService} from './ngsg-sort.service'; import {NgsgSelectionService} from './ngsg-selection.service'; -import {NgsgClassService} from './ngsg-class.service'; -import {NgsgElementsHelper} from './ngsg-elements.helper'; import {NgsgEventsService} from './ngsg-events.service'; import {Subject} from 'rxjs'; import {takeUntil} from 'rxjs/operators'; -import {group} from '@angular/animations'; +import {ViewPortService} from './helpers/view-port.service'; const selector = '[ngSortgridItem]'; @@ -31,6 +31,7 @@ export class NgsgItemDirective implements OnInit, OnChanges, AfterViewInit, OnDe @Output() sorted = new EventEmitter(); private selected = false; + private SCROLLSPEED = 100; private destroy$ = new Subject(); constructor( @@ -39,7 +40,8 @@ export class NgsgItemDirective implements OnInit, OnChanges, AfterViewInit, OnDe private selectionService: NgsgSelectionService, private reflectService: NgsgReflectService, private ngsgStore: NgsgStoreService, - private ngsgEventService: NgsgEventsService + private ngsgEventService: NgsgEventsService, + private viewPortService: ViewPortService ) { } @@ -88,6 +90,15 @@ 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'}); + } + if (event.preventDefault) { // Necessary. Allows us to drop. event.preventDefault();