UNPKG

@siberiaweb/components

Version:
408 lines (331 loc) 11.4 kB
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(); } }