Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/core/body/body.ctrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { PathService } from '../path/path.service';
import { Fastdom } from '../services/fastdom';
import { GRID_PREFIX } from '../definition';
import { jobLine } from '../services/job.line';
import { ScrollService } from '../scroll/scroll.service';

const MOUSE_LEFT_BUTTON = 1;
const VERTICAL_SCROLL_CLASS = `${GRID_PREFIX}-scroll-vertical`;
Expand All @@ -12,6 +13,7 @@ export class BodyCtrl {
this.model = model;
this.view = view;
this.bag = bag;
this.scrollService = new ScrollService(model, table, bag, view);
this.table = table;
this.rangeStartCell = null;
this.scrollingJob = jobLine(100);
Expand Down Expand Up @@ -131,6 +133,7 @@ export class BodyCtrl {
if (startCell && endCell) {
this.navigate(endCell);
this.view.selection.selectRange(startCell, endCell, 'body');
this.scrollService.start(e, startCell);
}
}
}
Expand All @@ -147,8 +150,10 @@ export class BodyCtrl {
}

onMouseUp(e) {
const mode = this.selection.mode;
const edit = this.model.edit;
this.scrollService.stop();

const { mode } = this.selection;
const { edit } = this.model;

if (e.which === MOUSE_LEFT_BUTTON) {
const pathFinder = new PathService(this.bag.body);
Expand Down
10 changes: 10 additions & 0 deletions src/core/scroll/scroll.model.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ export declare interface ScrollModel {
*/
cursor?: number;

/**
* Scroll velocity.
*/
velocity?: number;

/**
* Defines the distance from borders where scrolling should be initiated.
*/
offset?: number;

map: {
rowToView: (index: number) => number,
viewToRow: (index: number) => number,
Expand Down
2 changes: 2 additions & 0 deletions src/core/scroll/scroll.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export class ScrollModel {
this.top = 0;
this.left = 0;
this.cursor = 0;
this.velocity = 10;
this.offset = 50;

this.map = {
rowToView: identity,
Expand Down
10 changes: 10 additions & 0 deletions src/core/scroll/scroll.service.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Bag } from '../dom/bag';
import { Model } from '../infrastructure/model';
import { Table } from '../dom/table';

export declare class ScrollService {
constructor(model: Model, table: Table, bag: Bag, view: any);

start(): void;
stop(): void;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add scroll method

}
185 changes: 185 additions & 0 deletions src/core/scroll/scroll.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import { AppError } from '../infrastructure/error';
import { jobLine } from '../services/job.line';
import { PathService } from '../path/path.service';

export class ScrollService {
constructor(model, table, bag, view) {
this.model = model;
this.table = table;
this.bag = bag;
this.view = view;
this.job = jobLine(50);
this.startCell = null;
this.mouseEvent = null;
this.inMotion = false;
this.allowScroll = false;

const pathFinder = new PathService(bag.body);
model.scrollChanged.watch(e => {
const path = this.getPath(this.mouseEvent);
const td = pathFinder.cell(path);

if (td) {
this.navigate(td);
this.view.selection.selectRange(this.startCell, td, 'body');
}
});
}

canScroll(e) {
const rect = this.rect;
const offset = this.offset;

const mouseOnTopSide = e.clientY < (rect.top + offset);
const mouseOnBottomSide = e.clientY > (rect.bottom - offset);
const mouseOnLeftSide = e.clientX < (rect.left + offset);
const mouseOnRightSide = e.clientX > (rect.right - offset);

return mouseOnTopSide || mouseOnBottomSide || mouseOnLeftSide || mouseOnRightSide;
}

start(e, startCell) {
this.mouseEvent = e;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we calculate td here? not in scrollChanged event

this.startCell = startCell;

const direction = this.onEdgeOf(e);
if (direction) {
this.allowScroll = true;
this.scroll(direction);
}
}

scroll(direction) {
const { scroll } = this.model;
const scrollState = scroll();
const { velocity } = scrollState;
const scrolledToEnd = () => this.isScrolledToEnd(direction);

const timeout = () => setTimeout(() => {
if (this.allowScroll && this.canScroll(this.mouseEvent) && !scrolledToEnd()) {
this.inMotion = true;
switch (direction) {
case 'right':
case 'bottom': {
const course = direction === 'bottom' ? 'top' : 'left';
const origin = scrollState[course];
scroll({ [course]: origin + velocity });
break;
}
case 'left':
case 'top': {
const course = direction === 'top' ? 'top' : 'left';
const origin = scrollState[course];
scroll({ [course]: origin - velocity });
break;
}
default: {
throw new AppError('scroll.service', `doScroll: Wrong direction`);
}
}
} else {
this.inMotion = false;
return;
}

timeout();

}, 50);

if(!this.inMotion) {
timeout();
}
}

isScrolledToEnd(direction) {
const body = this.body;

switch (direction) {
case 'top': {
return body.scrollTop === 0;
}
case 'bottom': {
return body.clientHeight === body.scrollHeight - body.scrollTop;
}
case 'left': {
return body.scrollLeft === 0;
}
case 'right': {
return body.scrollLeft === body.scrollWidth - body.clientWidth;
}
default: {
throw new AppError('scroll.service', `isScrolledToEnd: Wrong direction`);
}
}
}

onEdgeOf(e) {
const rect = this.rect;
const offset = this.offset;

if (e.clientY < (rect.top + offset) &&
e.clientX > (rect.left + offset) &&
e.clientX < (rect.right - offset)) {
return 'top';
}

if (e.clientY > (rect.bottom - offset) &&
e.clientX > (rect.left + offset) &&
e.clientX < (rect.right - offset)) {
return 'bottom';
}

if (e.clientX < (rect.left + offset) &&
e.clientY > (rect.top + offset) &&
e.clientY < (rect.bottom - offset)) {
return 'left';
}

if (e.clientX > (rect.right - offset) &&
e.clientY > (rect.top + offset) &&
e.clientY < (rect.bottom - offset)) {
return 'right';
}

return false;
}

stop() {
this.allowScroll = false;
}

clearInterval() {
clearInterval(this.interval);
this.interval = null;
}

navigate(cell) {
const { focus } = this.view.nav;
if (focus.canExecute(cell)) {
focus.execute(cell);
}
}

getPath(e) {
const path = [];
let element = document.elementFromPoint(e.clientX, e.clientY);
while (element) {
path.push(element);
element = element.parentElement;
}

return path;
}

get rect() {
return this.table.view.rect(this.body);
}

get body() {
return this.table.view.markup.body;
}

get offset() {
return this.model.scroll().offset;
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Write unit tests

15 changes: 12 additions & 3 deletions src/lib/main/core/body/body-core.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, ElementRef, OnInit, NgZone, Input, ChangeDetectorRef } from '@angular/core';
import { Component, ElementRef, OnInit, NgZone, Input, ChangeDetectorRef, Inject } from '@angular/core';
import { EventListener } from 'ng2-qgrid/core/infrastructure/event.listener';
import { EventManager } from 'ng2-qgrid/core/infrastructure/event.manager';
import { ColumnView } from 'ng2-qgrid/core/scene/view/column.view';
Expand All @@ -12,7 +12,8 @@ import { TableCoreService } from '../table/table-core.service';

@Component({
selector: 'tbody[q-grid-core-body]',
templateUrl: './body-core.component.html'
templateUrl: './body-core.component.html',
providers: [{ provide: 'window', useValue: window }]
})
export class BodyCoreComponent extends NgComponent implements OnInit {
@Input() pin = 'body';
Expand All @@ -21,6 +22,7 @@ export class BodyCoreComponent extends NgComponent implements OnInit {
rowId: (index: number, row: any) => any;

constructor(
@Inject('window') private window: Window,
private element: ElementRef,
public $view: ViewCoreService,
public $table: TableCoreService,
Expand All @@ -39,6 +41,7 @@ export class BodyCoreComponent extends NgComponent implements OnInit {
const table = this.$table;
const ctrl = new BodyCtrl(model, view, this.root.table, this.root.bag);
const listener = new EventListener(element, new EventManager(this));
const windowListener = new EventListener(this.window, new EventManager(this));

this.zone.runOutsideAngular(() => {
listener.on('wheel', e => ctrl.onWheel(e));
Expand All @@ -56,7 +59,13 @@ export class BodyCoreComponent extends NgComponent implements OnInit {
});

listener.on('mousedown', ctrl.onMouseDown.bind(ctrl));
listener.on('mouseup', ctrl.onMouseUp.bind(ctrl));

windowListener.on('mouseup', (e) => {
const isActive = model.focus().isActive;
if (isActive) {
ctrl.onMouseUp(e);
}
});

const { id } = model.data();
this.rowId = id.row;
Expand Down
11 changes: 3 additions & 8 deletions src/lib/main/core/cell/cell-handler.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,14 +175,9 @@ export class CellHandlerComponent implements OnInit, AfterViewInit {
}

get isMarkerVisible() {
const model = this.root.model;
const { column } = model.navigation();

if (column) {
const type = column.type;
return model.edit().method === 'batch';
}
const { model } = this.root;
const { method } = model.edit();

return false;
return method === 'batch';
}
}