angular2-data-table
Version:
angular2-data-table is a Angular2 component for presenting large and complex data.
167 lines (138 loc) • 4.79 kB
text/typescript
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { Keys, selectRows, selectRowsBetween } from '../../utils';
import { SelectionType } from '../../types';
export interface Model {
type: string;
event: MouseEvent | KeyboardEvent;
row: any;
rowElement: any;
cellElement: any;
cellIndex: number;
}
export class DataTableSelectionComponent {
rows: any[];
selected: any[];
selectEnabled: boolean;
selectionType: SelectionType;
rowIdentity: any;
selectCheck: any;
activate: EventEmitter<any> = new EventEmitter();
select: EventEmitter<any> = new EventEmitter();
prevIndex: number;
selectRow(event: KeyboardEvent | MouseEvent, index: number, row: any): void {
if (!this.selectEnabled) return;
const chkbox = this.selectionType === SelectionType.checkbox;
const multi = this.selectionType === SelectionType.multi;
let selected: any[] = [];
if (multi || chkbox) {
if (event.shiftKey) {
const newSelected = [...this.selected];
selected = selectRowsBetween(
newSelected,
this.rows,
index,
this.prevIndex,
this.getRowSelectedIdx.bind(this));
} else if (!event.shiftKey) {
selected.push(row);
} else {
const newSelected = [...this.selected];
selected = selectRows(newSelected, row, this.getRowSelectedIdx.bind(this));
}
} else {
selected.push(row);
}
if(this.selectCheck) {
selected = selected.filter(this.selectCheck.bind(this));
}
this.selected.splice(0, this.selected.length);
this.selected.push(...selected);
this.prevIndex = index;
this.select.emit({
selected
});
}
onActivate(model: Model, index: number): void {
const { type, event, row } = model;
const chkbox = this.selectionType === SelectionType.checkbox;
const select = (!chkbox && (type === 'click' || type === 'dblclick')) ||
(chkbox && type === 'checkbox');
if(select) {
this.selectRow(event, index, row);
} else if(type === 'keydown') {
if ((<KeyboardEvent>event).keyCode === Keys.return) {
this.selectRow(event, index, row);
} else {
this.onKeyboardFocus(model);
}
}
this.activate.emit(model);
}
onKeyboardFocus(model: Model): void {
const { keyCode } = <KeyboardEvent>model.event;
const shouldFocus =
keyCode === Keys.up ||
keyCode === Keys.down ||
keyCode === Keys.right ||
keyCode === Keys.left;
if(shouldFocus) {
const isCellSelection =
this.selectionType === SelectionType.cell;
if(!model.cellElement || !isCellSelection) {
this.focusRow(model.rowElement, keyCode);
} else if(isCellSelection) {
this.focusCell(model.cellElement, model.rowElement, keyCode, model.cellIndex);
}
}
}
focusRow(rowElement: any, keyCode: number): void {
const nextRowElement = this.getPrevNextRow(rowElement, keyCode);
if(nextRowElement) nextRowElement.focus();
}
getPrevNextRow(rowElement: any, keyCode: number): any {
const parentElement = rowElement.parentElement;
if(parentElement) {
let focusElement: HTMLElement;
if(keyCode === Keys.up) {
focusElement = parentElement.previousElementSibling;
} else if(keyCode === Keys.down) {
focusElement = parentElement.nextElementSibling;
}
if(focusElement && focusElement.children.length) {
return focusElement.children[0];
}
}
}
focusCell(cellElement: any, rowElement: any, keyCode: number, cellIndex: number): void {
let nextCellElement: HTMLElement;
if(keyCode === Keys.left) {
nextCellElement = cellElement.previousElementSibling;
} else if(keyCode === Keys.right) {
nextCellElement = cellElement.nextElementSibling;
} else if(keyCode === Keys.up || keyCode === Keys.down) {
const nextRowElement = this.getPrevNextRow(rowElement, keyCode);
if(nextRowElement) {
const children = nextRowElement.getElementsByClassName('datatable-body-cell');
if(children.length) nextCellElement = children[cellIndex];
}
}
if(nextCellElement) nextCellElement.focus();
}
getRowSelected(row: any): boolean {
return this.getRowSelectedIdx(row, this.selected) > -1;
}
getRowSelectedIdx(row: any, selected: any[]): number {
if(!selected || !selected.length) return -1;
const rowId = this.rowIdentity(row);
return selected.findIndex((r) => {
const id = this.rowIdentity(r);
return id === rowId;
});
}
}