@siberiaweb/components
Version:
408 lines (331 loc) • 11.4 kB
text/typescript
import { SortOrder } from "../custom-grid/Types";
import Col from "../custom-grid/Col";
import CustomGrid from "../custom-grid/CustomGrid";
import HandlerTypes from "./HandlerTypes";
import * as moment from "moment";
/**
* Сетка.
*
* @template TRecord Тип записи.
*/
export default class Grid< TRecord > extends CustomGrid< TRecord > {
/**
* Наименование компонента.
*/
public static readonly COMPONENT_NAME: string = "sw-grid";
/**
* Отключение прокрутки в начало таблицы после сортировки.
*/
private static readonly ATTR_SCROLL_TOP_AFTER_SORT_DISABLED: string = "scroll-top-after-sort-disabled";
/**
* Изначальный порядок записей в наборе данных для восстановления сортировки по умолчанию.
*/
private readonly dataSetInitialOrder: Map< TRecord, number > = new Map();
/**
* Обработчик сортировки набора данных.
*/
public onSortDataSet: HandlerTypes.SortDataSet< TRecord > | null = null;
/**
* Функция обратного вызова для сортировки неопределенных значений.
*
* @param a Первое значение.
* @param b Второе значение.
* @param sortOrder Порядок сортировки.
*/
protected sortNullsCallback(
a: any,
b: any,
sortOrder: SortOrder
): number {
if ( ( a === null ) && ( b !== null ) ) {
return sortOrder === "asc" ? -1 : 1;
}
if ( ( a !== null ) && ( b === null ) ) {
return sortOrder === "asc" ? 1 : -1;
}
return 0;
}
/**
* Функция обратного вызова для восстановления порядка следования записей.
*
* @param a Первая запись.
* @param b Вторая запись.
*/
public sortDefaultCallback(
a: TRecord,
b: TRecord,
): number {
let indexA: number | undefined = this.dataSetInitialOrder.get( a );
let indexB: number | undefined = this.dataSetInitialOrder.get( b );
if ( ( indexA !== undefined ) && ( indexB !== undefined ) ) {
return indexA - indexB;
}
return 0;
}
/**
* Функция обратного вызова для сортировки логических значений.
*
* @param a Первая запись.
* @param b Вторая запись.
* @param col Столбец.
*/
protected sortBooleanCallback(
a: TRecord,
b: TRecord,
col: Col
): number {
if ( col.sortOrder === "none" ) {
return this.sortDefaultCallback( a, b );
}
let booleanA: boolean | null = this.getFieldValue( col, a );
let booleanB: boolean | null = this.getFieldValue( col, b );
if ( ( booleanA === null ) || ( booleanB === null ) ) {
return this.sortNullsCallback( booleanA, booleanB, col.sortOrder );
}
if ( booleanA === booleanB ) {
return 0;
}
if ( booleanA ) {
return col.sortOrder === "asc" ? 1 : -1;
}
return col.sortOrder === "desc" ? -1 : 1;
}
/**
* Функция обратного вызова для сортировки чисел.
*
* @param a Первая запись.
* @param b Вторая запись.
* @param col Столбец.
*/
protected sortNumberCallback(
a: TRecord,
b: TRecord,
col: Col
): number {
if ( col.sortOrder === "none" ) {
return this.sortDefaultCallback( a, b );
}
let numberA: number | null = this.getFieldValue( col, a );
let numberB: number | null = this.getFieldValue( col, b );
if ( ( numberA === null ) || ( numberB === null ) ) {
return this.sortNullsCallback( numberA, numberB, col.sortOrder );
}
return col.sortOrder === "asc" ? numberA - numberB : numberB - numberA;
}
/**
* Функция обратного вызова для сортировки дат.
*
* @param a Первая запись.
* @param b Вторая запись.
* @param col Столбец.
*/
protected sortDateCallback(
a: TRecord,
b: TRecord,
col: Col
): number {
if ( col.sortOrder === "none" ) {
return this.sortDefaultCallback( a, b );
}
let dateA: Date | null = this.getFieldValue( col, a );
let dateB: Date | null = this.getFieldValue( col, b );
if ( ( dateA === null ) || ( dateB === null ) ) {
return this.sortNullsCallback( dateA, dateB, col.sortOrder );
}
return col.sortOrder === "asc" ? dateA.getTime() - dateB.getTime() : dateB.getTime() - dateA.getTime();
}
/**
* Функция обратного вызова для сортировки дат, представленных в виде строки.
*
* @param a Первая запись.
* @param b Вторая запись.
* @param col Столбец.
* @param pattern Шаблон даты.
*/
protected sortDateStringCallback(
a: TRecord,
b: TRecord,
col: Col,
pattern: string
): number {
if ( col.sortOrder === "none" ) {
return this.sortDefaultCallback( a, b );
}
let dateA: Date | null = this.getFieldValue( col, a );
let dateB: Date | null = this.getFieldValue( col, b );
if ( ( dateA === null ) || ( dateB === null ) ) {
return this.sortNullsCallback( dateA, dateB, col.sortOrder );
}
let momentA: moment.Moment = moment( dateA, pattern );
let momentB: moment.Moment = moment( dateB, pattern );
return col.sortOrder === "asc" ? momentA.toDate().getTime() - momentB.toDate().getTime() :
momentB.toDate().getTime() - momentA.toDate().getTime();
}
/**
* Функция обратного вызова для сортировки текста.
*
* @param a Первая запись.
* @param b Вторая запись.
* @param col Столбец.
*/
protected sortTextCallback(
a: TRecord,
b: TRecord,
col: Col
): number {
if ( col.sortOrder === "none" ) {
return this.sortDefaultCallback( a, b );
}
let valueA: string | null = this.getFieldValue( col, a );
let valueB: string | null = this.getFieldValue( col, b );
if ( ( valueA === null ) || ( valueB === null ) ) {
return this.sortNullsCallback( valueA, valueB, col.sortOrder );
}
if ( valueA < valueB ) {
return col.sortOrder === "asc" ? -1 : 1;
}
if ( valueA > valueB ) {
return col.sortOrder === "asc" ? 1 : -1;
}
return 0;
}
/**
* Сортировка набора данных.
*
* @param col Столбец.
*/
protected sortDataSet(
col: Col
): void {
if ( ( this.onSortDataSet !== null ) && this.onSortDataSet( this.getDataSet(), col ) ) {
return;
}
switch ( col.fieldType ) {
case "boolean":
this.getDataSet().sort( (
a: TRecord,
b: TRecord
): number => {
return this.sortBooleanCallback( a, b, col );
} );
break;
case "date":
this.getDataSet().sort( (
a: TRecord,
b: TRecord
): number => {
return this.sortDateCallback( a, b, col );
} );
break;
case "date-string":
let pattern: string | null = col.pattern;
this.getDataSet().sort( (
a: TRecord,
b: TRecord
): number => {
return pattern === null ? this.sortTextCallback( a, b, col ) :
this.sortDateStringCallback( a, b, col, pattern );
} );
break;
case "number":
this.getDataSet().sort( (
a: TRecord,
b: TRecord
): number => {
return this.sortNumberCallback( a, b, col );
} );
break;
default:
this.getDataSet().sort( (
a: TRecord,
b: TRecord
): number => {
return this.sortTextCallback( a, b, col );
} );
break;
}
}
/**
* @override
*/
public sort(
col: Col
): void {
super.sort( col );
if ( col.sortDisabled ) {
return;
}
this.sortDataSet( col );
if ( !this.scrollTopAfterSortDisabled ) {
this.scrollTop = 0;
}
this.renderBody( true );
}
/**
* @override
*/
public setDataSet(
dataSet: TRecord[]
): void {
super.setDataSet( dataSet );
this.dataSetInitialOrder.clear();
for ( let i: number = 0; i < this.getDataSet().length; i++ ) {
this.dataSetInitialOrder.set( this.getDataSet()[ i ], i );
}
if ( this.sortCol !== null ) {
this.sort( this.sortCol );
}
}
/**
* @override
*/
public addDataSet(
dataSet: TRecord[]
): void {
let length: number = this.getDataSet().length;
super.addDataSet( dataSet );
for ( let i: number = length; i < this.getDataSet().length; i++ ) {
this.dataSetInitialOrder.set( this.getDataSet()[ i ], i );
}
}
/**
* @override
*/
public addRecord(
record: TRecord
): void {
super.addRecord( record );
this.dataSetInitialOrder.set( record, this.getDataSet().length - 1 );
}
/**
* @override
*/
public removeRecord(
record: TRecord
): void {
super.removeRecord( record );
this.dataSetInitialOrder.delete( record );
}
/**
* Получение признака отключения прокрутки в начало сетки после сортировки.
*/
public get scrollTopAfterSortDisabled(): boolean {
return this.hasAttribute( Grid.ATTR_SCROLL_TOP_AFTER_SORT_DISABLED );
}
/**
* Установка признака отключения прокрутки в начало сетки после сортировки.
*
* @param value Значение.
*/
public set scrollTopAfterSortDisabled(
value: boolean
) {
this.toggleAttribute( Grid.ATTR_SCROLL_TOP_AFTER_SORT_DISABLED, value );
}
/**
* Конструктор.
*/
constructor() {
super();
}
}