The Record Test app is used to test aspects of the record module. It also includes some performance testing. (It may be easier to open this link in another tab or window)
The record data type is declared in the following namespace:
export namespace Record {
export type Data = [intVal: Integer, strVal: string, dblVal:number, dateVal: Date, statusId: TDataItemStatusId];
export namespace Data {
export const intValIndex = 0;
export const strValIndex = 1;
export const numberValIndex = 2;
export const dateValIndex = 3;
export const statusIdIndex = 4;
}
export function createCopy(value: Record): Record {
return {
index: value.index,
data: [...value.data],
}
}
}
Records will be passed to client (as DataRows) where each is an array with 5 elements (fields).
The GridField
classes implement RevRecordField
and provide access to the values in the fields for each record/row.
export abstract class GridField implements RevRecordField {
index = -1;
constructor(readonly name: string, public heading: string, readonly columnSettings: RevSimpleBehavioredColumnSettings) {}
getViewValue(record: RecordStore.Record): RevDataServer.ViewValue {
return this.getEditValue(record);
}
abstract getEditValue(record: RecordStore.Record): RevDataServer.EditValue;
abstract setEditValue(record: RecordStore.Record, value: RevDataServer.EditValue): void;
abstract modifyValue(record: RecordStore.Record): RevRecordValueRecentChangeTypeId | undefined;
}
export class IntValGridField extends GridField {
constructor(columnSettings: RevSimpleBehavioredColumnSettings) {
super('IntVal', 'Int', columnSettings);
}
getEditValue(record: RecordStore.Record): RevDataServer.EditValue {
return record.data[RecordStore.Record.Data.intValIndex];
}
setEditValue(record: RecordStore.Record, value: RevDataServer.EditValue) {
record.data[RecordStore.Record.Data.intValIndex] = value as number;
}
compare(left: RecordStore.Record, right: RecordStore.Record): number {
const index = RecordStore.Record.Data.intValIndex;
return right.data[index] - left.data[index];
}
compareDesc(left: RecordStore.Record, right: RecordStore.Record): number {
const index = RecordStore.Record.Data.intValIndex;
return left.data[index] - right.data[index];
}
override modifyValue(record: RecordStore.Record): RevRecordValueRecentChangeTypeId | undefined {
const oldValue = record.data[RecordStore.Record.Data.intValIndex];
const newValue = Math.floor(Math.random() * 200);
const valueRecentChangeTypeId = calculateNumberValueRecentChangeId(oldValue, newValue);
if (valueRecentChangeTypeId !== undefined) {
record.data[RecordStore.Record.Data.intValIndex] = newValue;
}
return valueRecentChangeTypeId;
}
}
RecordStore implements RevRecordStore
. It provides the client with access to records (rows) and also allows records to be added and deleted by the user interface. Whenever records are added or deleted, RecordStore will send a notification to the client. It will also send an invalidate
notification to the client if the grid, a record, or any values in a record are changed.
export class RecordStore implements RevRecordStore {
private _records: RecordStore.Record[] = [];
private _recordsEventers!: RevRecordStore.RecordsEventers;
constructor() {
for (let I = 0; I < RecordStore.initialValues.length; I++) {
this._records.push(RecordStore.Record.createCopy(RecordStore.initialValues[I]));
}
}
get recordCount(): number { return this._records.length;}
setRecordEventers(recordsEventers: RevRecordStore.RecordsEventers): void {
this._recordsEventers = recordsEventers;
const recordCount = this._records.length;
if (recordCount > 0) {
recordsEventers.recordsInserted(0, recordCount);
}
}
getRecord(index: RevRecordIndex): RecordStore.Record {
return this._records[index];
}
getRecords(): RecordStore.Record[] {
return this._records;
}
addRecordData(data: RecordStore.Record.Data): void {
const index = this._records.length;
const record: RecordStore.Record = {
index,
data,
}
this._records.push(record);
}
clearRecords(): void {
this._records.length = 0;
this.eventifyAllRecordsDeleted();
}
deleteRecord(index: number, eventify: boolean): void {
this._records.splice(index, 1);
this.reindex(index);
if (eventify) {
this.eventifyRecordDeleted(index);
}
}
deleteRecords(index: number, count: number): void {
this._records.splice(index, count);
this.reindex(index);
this._recordsEventers.recordsDeleted(index, count);
}
insertRecord(index: number, data: RecordStore.Record.Data, recent: boolean, eventify: boolean): void {
const record: RecordStore.Record = {
index,
data,
}
this._records.splice(index, 0, record);
this.reindex(index + 1);
if (eventify) {
this.eventifyRecordInserted(index, recent);
}
}
insertRecords(index: number, recordDatas: RecordStore.Record.Data[], recent: boolean): void {
const count = recordDatas.length;
const records = new Array<RecordStore.Record>(count);
for (let i = 0; i < count; i++) {
records[i] = {
index: index + i,
data: recordDatas[i],
};
}
this._records.splice(index, 0, ...records);
this.reindex(index + count);
this._recordsEventers.recordsInserted(index, count, recent);
}
beginChange(): void {
this._recordsEventers.beginChange();
}
endChange(): void {
this._recordsEventers.endChange();
}
invalidateAll(): void {
this._recordsEventers.invalidateAll();
}
invalidateRecord(index: number): void {
this._recordsEventers.invalidateRecord(index);
}
invalidateValue(fieldIndex: RevRecordFieldIndex, recordIndex: RevRecordIndex, valueRecentChangeTypeId: RevRecordValueRecentChangeTypeId): void {
this._recordsEventers.invalidateValue(fieldIndex, recordIndex, valueRecentChangeTypeId);
}
eventifyRecordsInserted(idx: number, count: number, recent: boolean): void {
this._recordsEventers.recordsInserted(idx, count, recent);
}
eventifyRecordDeleted(idx: number): void {
this._recordsEventers.recordDeleted(idx);
}
private reindex(fromIndex: number) {
const count = this._records.length;
for (let i = fromIndex; i < count; i++) {
this._records[i].index = i;
}
}
private eventifyRecordInserted(idx: number, recent: boolean): void {
this._recordsEventers.recordInserted(idx, recent);
}
private eventifyAllRecordsDeleted() {
this._recordsEventers.allRecordsDeleted();
}
}
The cell painter will paint a cell whenever it is invalidated. Note that this class will use JavaScript default toString()
to convert field values to a string.
import { UnreachableCaseError } from '@pbkware/js-utils';
import {
RevCellPainter,
RevClientGrid,
RevRecordDataServer,
RevRecordRecentChangeTypeId,
RevRecordValueRecentChangeTypeId,
RevSelectionAreaTypeId,
RevSimpleBehavioredColumnSettings,
RevStandardCellPainter,
RevStandardTextPainter,
RevViewCell,
} from '../..';
import { AppBehavioredGridSettings } from './app-behaviored-grid-settings';
import { GridField } from './grid-field';
export class MainCellPainter
extends RevStandardCellPainter<AppBehavioredGridSettings, RevSimpleBehavioredColumnSettings, GridField>
implements RevCellPainter<RevSimpleBehavioredColumnSettings, GridField> {
protected declare readonly _dataServer: RevRecordDataServer<GridField>;
private readonly _textPainter: RevStandardTextPainter;
constructor(
grid: RevClientGrid<AppBehavioredGridSettings, RevSimpleBehavioredColumnSettings, GridField>,
dataServer: RevRecordDataServer<GridField>,
) {
super(grid, dataServer);
this._textPainter = new RevStandardTextPainter(this._renderingContext);
}
paint(cell: RevViewCell<RevSimpleBehavioredColumnSettings, GridField>, prefillColor: string | undefined): number | undefined {
const grid = this._grid;
const gridSettings = this._gridSettings;
const columnSettings = cell.columnSettings;
this._textPainter.setColumnSettings(columnSettings);
const gc = this._renderingContext;
const subgrid = cell.subgrid;
const subgridRowIndex = cell.viewLayoutRow.subgridRowIndex;
const activeColumnIndex = cell.viewLayoutColumn.activeColumnIndex;
const foreColor = gridSettings.color;
const field = cell.viewLayoutColumn.column.field;
const foreText = this._dataServer.getViewValue(field, subgridRowIndex) as string;
const foreFont = gridSettings.font;
let internalBorderRowOnly = false;
const valueRecentChangeTypeId = this._dataServer.getValueRecentChangeTypeId(field, subgridRowIndex);
const focus = grid.focus;
let internalBorderColor: string | undefined;
let focusedCellBorderColor: string | undefined;
const rowFocused = focus.isMainSubgridRowFocused(subgridRowIndex);
let cellFocused: boolean;
if (rowFocused) {
if (gridSettings.focusedRowBorderColor !== undefined) {
internalBorderColor = gridSettings.focusedRowBorderColor;
internalBorderRowOnly = true;
}
cellFocused = focus.isCellFocused(cell);
if (cellFocused) {
focusedCellBorderColor = gridSettings.focusedCellBorderColor;
}
} else {
cellFocused = false;
}
let bkgdColor: string;
const selectionBackgroundColor = this._gridSettings.selectionBackgroundColor;
const selection = grid.selection;
let cellSelectionAreaTypeId: RevSelectionAreaTypeId | undefined;
if (
selectionBackgroundColor !== undefined &&
(cellSelectionAreaTypeId = selection.getOneCellSelectionAreaTypeId(activeColumnIndex, subgridRowIndex, subgrid)) !== undefined &&
(!cellFocused || !selection.isSelectedCellTheOnlySelectedCell(activeColumnIndex, subgridRowIndex, subgrid, cellSelectionAreaTypeId))
) {
bkgdColor = selectionBackgroundColor;
} else {
if (prefillColor !== undefined) {
bkgdColor = prefillColor;
} else {
bkgdColor = gridSettings.backgroundColor;
}
}
if (valueRecentChangeTypeId !== undefined) {
switch (valueRecentChangeTypeId) {
case RevRecordValueRecentChangeTypeId.Update:
internalBorderColor = gridSettings.valueRecentlyModifiedBorderColor;
break;
case RevRecordValueRecentChangeTypeId.Increase:
internalBorderColor = gridSettings.valueRecentlyModifiedUpBorderColor;
break;
case RevRecordValueRecentChangeTypeId.Decrease:
internalBorderColor = gridSettings.valueRecentlyModifiedDownBorderColor;
break;
default:
throw new UnreachableCaseError('TCPPRVCTU02775', valueRecentChangeTypeId);
}
internalBorderRowOnly = false;
} else {
const rowRecentChangeTypeId = this._dataServer.getRecordRecentChangeTypeId(subgridRowIndex);
if (rowRecentChangeTypeId !== undefined) {
switch (rowRecentChangeTypeId) {
case RevRecordRecentChangeTypeId.Update:
internalBorderColor = gridSettings.recordRecentlyUpdatedBorderColor;
break;
case RevRecordRecentChangeTypeId.Insert:
internalBorderColor = gridSettings.recordRecentlyInsertedBorderColor;
break;
case RevRecordRecentChangeTypeId.Remove:
internalBorderColor = undefined;
break;
default:
throw new UnreachableCaseError('TCPPRRCTU02775', rowRecentChangeTypeId);
}
internalBorderRowOnly = true;
}
}
let bkgdRenderingRequired: boolean;
let textProcessingRequired: boolean;
let internalBorderProcessingRequired: boolean;
if (prefillColor !== undefined) {
bkgdRenderingRequired = prefillColor !== bkgdColor;
textProcessingRequired = true;
internalBorderProcessingRequired = true;
} else {
const fingerprint = cell.paintFingerprint as PaintFingerprint | undefined;
if (fingerprint === undefined) {
bkgdRenderingRequired = true;
textProcessingRequired = true;
internalBorderProcessingRequired = true;
} else {
if (fingerprint.bkgdColor !== bkgdColor) {
bkgdRenderingRequired = true;
textProcessingRequired = true;
internalBorderProcessingRequired = true;
} else {
bkgdRenderingRequired = false;
textProcessingRequired = fingerprint.foreColor !== foreColor || fingerprint.foreText !== foreText;
internalBorderProcessingRequired =
fingerprint.internalBorderColor !== internalBorderColor ||
fingerprint.internalBorderRowOnly !== internalBorderRowOnly ||
fingerprint.focusedCellBorderColor !== focusedCellBorderColor;
}
}
}
if (
!bkgdRenderingRequired &&
!textProcessingRequired &&
!internalBorderProcessingRequired
) {
return undefined;
} else {
const newFingerprint: PaintFingerprint = {
bkgdColor,
foreColor,
internalBorderColor,
internalBorderRowOnly,
focusedCellBorderColor,
foreText,
};
cell.paintFingerprint = newFingerprint;
const bounds = cell.bounds;
const x = bounds.x;
const y = bounds.y;
const width = bounds.width;
const height = bounds.height;
if (bkgdRenderingRequired) {
gc.cache.fillStyle = bkgdColor;
gc.fillRect(x, y, width, height);
}
if (internalBorderProcessingRequired) {
if (internalBorderColor !== undefined) {
gc.cache.strokeStyle = internalBorderColor;
gc.cache.lineWidth = 1;
gc.cache.lineDash = [];
if (internalBorderRowOnly) {
gc.beginPath();
gc.moveTo(x, y + 0.5);
gc.lineTo(x + width, y + 0.5);
gc.stroke();
gc.beginPath();
gc.moveTo(x, y + height - 0.5);
gc.lineTo(x + width, y + height - 0.5);
gc.stroke();
} else {
gc.beginPath();
gc.strokeRect(x + 0.5, y + 0.5, width - 1, height - 1);
}
}
if (focusedCellBorderColor !== undefined) {
gc.cache.strokeStyle = focusedCellBorderColor;
gc.cache.lineWidth = 1;
gc.cache.lineDash = [2, 1];
gc.beginPath();
gc.strokeRect(x + 0.5, y + 0.5, width - 1, height - 1);
}
}
const cellPadding = gridSettings.cellPadding;
if (textProcessingRequired && foreText === '') {
return undefined;
} else {
gc.cache.fillStyle = foreColor;
gc.cache.font = foreFont;
return this._textPainter.renderSingleLineText(bounds, foreText, cellPadding, cellPadding, columnSettings.horizontalAlignId);
}
}
}
}
export namespace AppCellPainter {
export type GetValueRecentChangeTypeIdEventer = (this: void, field: GridField, subgridRowIndex: number) => RevRecordValueRecentChangeTypeId;
export type GetRecordRecentChangeTypeIdEventer = (this: void, subgridRowIndex: number) => RevRecordRecentChangeTypeId;
}
interface PaintFingerprintInterface {
bkgdColor: string;
foreColor: string;
internalBorderColor: string | undefined;
internalBorderRowOnly: boolean;
focusedCellBorderColor: string | undefined;
foreText: string;
}
type PaintFingerprint = IndexSignatureHack<PaintFingerprintInterface>;
type IndexSignatureHack<T> = { [K in keyof T]: IndexSignatureHack<T[K]> };
The grid itself extends from RevRecordGrid
. This sub-class processes various events from the base class by overriding various functions:
import {
RevColumn,
RevLinedHoverCell,
RevListChangedTypeId,
RevPoint,
RevRecordGrid,
RevSimpleBehavioredColumnSettings,
RevViewCell
} from '../..';
import { AppBehavioredGridSettings } from './app-behaviored-grid-settings';
import {
GridField
} from './grid-field';
export class RecordGrid extends RevRecordGrid<
AppBehavioredGridSettings,
RevSimpleBehavioredColumnSettings,
GridField
> {
columnSortEventer: RecordGrid.ColumnSortEventer | undefined;
columnsWidthChangedEventer: RecordGrid.ColumnsWidthChangedEventer | undefined;
cellFocusChangedEventer: RecordGrid.CellFocusChangedEventer | undefined;
cellClickEventer: RecordGrid.CellClickEventer | undefined;
cellDblClickEventer: RecordGrid.CellDblClickEventer | undefined;
resizedEventer: RecordGrid.ResizedEventer | undefined;
fieldColumnListChanged: RecordGrid.FieldColumnListChanged | undefined;
columnsViewWidthsChangedEventer: RecordGrid.ColumnsViewWidthsChangedEventer | undefined;
renderedEventer: RecordGrid.RenderedEventer | undefined;
get columnCount(): number { return this.activeColumnCount; }
protected override descendantProcessColumnsWidthChanged(columns: RevColumn<RevSimpleBehavioredColumnSettings, GridField>[], ui: boolean) {
super.descendantProcessColumnsWidthChanged(columns, ui);
if (this.columnsWidthChangedEventer !== undefined) {
this.columnsWidthChangedEventer(columns);
}
}
protected override descendantProcessColumnSort(event: MouseEvent, headerOrFixedRowCell: RevViewCell<RevSimpleBehavioredColumnSettings, GridField>) {
super.descendantProcessColumnSort(event, headerOrFixedRowCell);
if (this.columnSortEventer !== undefined) {
this.columnSortEventer(headerOrFixedRowCell);
}
}
protected override descendantProcessClick(event: MouseEvent, hoverCell: RevLinedHoverCell<RevSimpleBehavioredColumnSettings, GridField> | null | undefined) {
if (hoverCell === null) {
hoverCell = this.viewLayout.findLinedHoverCellAtCanvasOffset(event.offsetX, event.offsetY);
}
if (hoverCell !== undefined) {
if (!RevLinedHoverCell.isMouseOverLine(hoverCell) && this.cellClickEventer !== undefined) {
const viewCell = hoverCell.viewCell;
this.cellClickEventer(viewCell);
}
}
}
protected override descendantProcessDblClick(event: MouseEvent, hoverCell: RevLinedHoverCell<RevSimpleBehavioredColumnSettings, GridField> | null | undefined) {
if (hoverCell === null) {
hoverCell = this.viewLayout.findLinedHoverCellAtCanvasOffset(event.offsetX, event.offsetY);
}
if (hoverCell !== undefined) {
if (!RevLinedHoverCell.isMouseOverLine(hoverCell) && this.cellDblClickEventer !== undefined) {
const viewCell = hoverCell.viewCell;
this.cellDblClickEventer(viewCell);
}
}
}
protected override descendantProcessCellFocusChanged(newPoint: RevPoint | undefined, oldPoint: RevPoint | undefined) {
if (this.cellFocusChangedEventer !== undefined) {
this.cellFocusChangedEventer(newPoint, oldPoint);
}
}
protected override descendantProcessResized() {
if (this.resizedEventer !== undefined) {
this.resizedEventer();
}
}
protected override descendantProcessColumnsViewWidthsChanged() {
if (this.columnsViewWidthsChangedEventer !== undefined) {
this.columnsViewWidthsChangedEventer();
}
}
protected override descendantProcessRendered() {
if (this.renderedEventer !== undefined) {
this.renderedEventer();
}
}
}
export namespace RecordGrid {
export type FieldNameToHeaderMap = Map<string, string | undefined>;
export type CtrlKeyMouseMoveEventer = (this: void) => void;
export type CellFocusChangedEventer = (this: void, newFocusPoint: RevPoint | undefined, oldFocusPoint: RevPoint | undefined) => void;
export type CellClickEventer = (this: void, viewCell: RevViewCell<RevSimpleBehavioredColumnSettings, GridField>) => void;
export type CellDblClickEventer = (this: void, viewCell: RevViewCell<RevSimpleBehavioredColumnSettings, GridField>) => void;
export type ResizedEventer = (this: void) => void;
export type ColumnsViewWidthsChangedEventer = (this: void) => void;
export type RenderedEventer = (this: void) => void;
export type ColumnSortEventer = (this: void, headerOrFixedRowCell: RevViewCell<RevSimpleBehavioredColumnSettings, GridField>) => void;
export type ColumnsWidthChangedEventer = (this: void, columns: RevColumn<RevSimpleBehavioredColumnSettings, GridField>[]) => void;
export type FieldColumnListChanged = (typeId: RevListChangedTypeId, index: number, count: number, targetIndex: number) => void;
export type RenderedCallback = (this: void) => void;
}
Finally, we have the main class which ties everything together:
/* eslint-disable @typescript-eslint/non-nullable-type-assertion-style */
import {
RevGridDefinition,
RevGridOptions,
RevPoint,
RevRecordDataServer,
RevRecordSchemaServer,
RevSimpleBehavioredColumnSettings,
RevSimpleInMemoryBehavioredColumnSettings,
RevSingleHeadingDataServer,
RevStandardHeaderTextCellPainter,
RevSubgrid,
RevViewCell,
revSimpleReadonlyDefaultBehavioredColumnSettings
} from '../..';
import { AppBehavioredGridSettings } from './app-behaviored-grid-settings';
import { AppGridSettings } from './app-grid-settings';
import { Controls } from './controls';
import { defaultAppGridSettings } from './default-app-grid-settings';
import {
DateValGridField,
GridField, HiddenStrValGridField, IntValGridField, NumberValGridField, RecordIndexGridField, StatusIdValGridField, StrValGridField
} from './grid-field';
import { InMemoryAppBehavioredGridSettings } from './in-memory-app-behaviored-grid-settings';
import { MainCellPainter } from './main-cell-painter';
import { RecordGrid } from './record-grid';
import { RecordStore } from './record-store';
export class Main {
private readonly _gridHostElement: HTMLElement;
private readonly _recordStore: RecordStore;
private readonly _schemaServer: RevRecordSchemaServer<GridField>;
private readonly _headerDataServer: RevSingleHeadingDataServer<GridField>;
private readonly _mainDataServer: RevRecordDataServer<GridField>;
private readonly _mainCellPainter: MainCellPainter;
private readonly _headerCellPainter: RevStandardHeaderTextCellPainter<AppBehavioredGridSettings, RevSimpleBehavioredColumnSettings, GridField>;
private readonly _recordIndexGridField = new RecordIndexGridField(revSimpleReadonlyDefaultBehavioredColumnSettings);
private readonly _hiddenStrValGridField = new HiddenStrValGridField(revSimpleReadonlyDefaultBehavioredColumnSettings);
private readonly _intValGridField = new IntValGridField(revSimpleReadonlyDefaultBehavioredColumnSettings);
private readonly _strValGridField = new StrValGridField(revSimpleReadonlyDefaultBehavioredColumnSettings);
private readonly _numberValGridField = new NumberValGridField(revSimpleReadonlyDefaultBehavioredColumnSettings);
private readonly _dateValGridField = new DateValGridField(revSimpleReadonlyDefaultBehavioredColumnSettings);
private readonly _statusIdValGridField = new StatusIdValGridField(revSimpleReadonlyDefaultBehavioredColumnSettings);
private readonly _grid: RecordGrid;
private readonly _gridSettings: InMemoryAppBehavioredGridSettings = new InMemoryAppBehavioredGridSettings();
private readonly _debugEnabled = true;
private readonly _controls: Controls;
constructor() {
const gridHostElement = document.querySelector('#gridHost') as HTMLElement;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (gridHostElement === null) {
throw new Error('gridHost not found');
}
this._gridHostElement = gridHostElement;
const initialSettings: AppGridSettings = {
...defaultAppGridSettings,
horizontalGridLinesWidth: 0,
fixedColumnCount: 1,
font: 'Tahoma, Geneva, sans-serif 13px',
columnHeaderFont: 'Tahoma, Geneva, sans-serif 12px',
backgroundColor: backgroundColor,
color: foregroundColor,
rowStripeBackgroundColor: '#2b2b2b',
columnHeaderBackgroundColor: columnHeaderBackgroundColor,
columnHeaderForegroundColor: columnHeaderForegroundColor,
selectionBackgroundColor: 'DarkSlateBlue',
verticalGridLinesColor: '#595959',
horizontalGridLinesColor: '#595959',
grayedOutForegroundColor: '#595959',
focusedRowBorderColor: '#C8B900',
focusedCellBorderColor: 'magenta',
scrollerThumbColor: '#858585',
valueRecentlyModifiedBorderColor: '#8C5F46',
valueRecentlyModifiedUpBorderColor: '#4646FF',
valueRecentlyModifiedDownBorderColor: '#64FA64',
recordRecentlyUpdatedBorderColor: 'orange',
recordRecentlyInsertedBorderColor: 'pink',
};
this._gridSettings.merge(initialSettings);
this._recordStore = new RecordStore();
this._schemaServer = new RevRecordSchemaServer<GridField>();
this._mainDataServer = new RevRecordDataServer<GridField>(this._schemaServer, this._recordStore);
this._headerDataServer = new RevSingleHeadingDataServer();
const definition: RevGridDefinition<RevSimpleBehavioredColumnSettings, GridField> = {
schemaServer: this._schemaServer,
subgrids: [
{
role: RevSubgrid.Role.header,
dataServer: this._headerDataServer,
getCellPainterEventer: (viewCell) => this.getHeaderCellPainter(viewCell),
},
{
role: RevSubgrid.Role.main,
dataServer: this._mainDataServer,
getCellPainterEventer: (viewCell) => this.getMainCellPainter(viewCell),
}
],
};
const options: RevGridOptions<AppBehavioredGridSettings, RevSimpleBehavioredColumnSettings, GridField> = {
externalParent: this,
canvasRenderingContext2DSettings: {
alpha: false,
}
}
this._grid = new RecordGrid(
this._gridHostElement,
definition,
this._gridSettings,
() => new RevSimpleInMemoryBehavioredColumnSettings(this._gridSettings),
options,
);
const grid = this._grid;
this._mainCellPainter = new MainCellPainter(grid, this._mainDataServer);
this._headerCellPainter = new RevStandardHeaderTextCellPainter<AppBehavioredGridSettings, RevSimpleBehavioredColumnSettings, GridField>(grid, this._headerDataServer);
grid.cellFocusChangedEventer = (newPoint, oldPoint) => this.handleCellFocusChanged(newPoint, oldPoint)
grid.cellClickEventer = (cell) => this.handleCellFocusClick(cell);
grid.cellDblClickEventer = (cell) => this.handleRecordFocusDblClick(cell);
grid.columnSortEventer = (headerOrFixedRowCell) => this.handleColumnSort(headerOrFixedRowCell);
this._controls = new Controls(
grid,
this._gridSettings,
this._recordStore,
this._schemaServer,
this._mainDataServer,
this._recordIndexGridField,
this._intValGridField,
this._strValGridField,
this._debugEnabled
);
grid.activate();
this._schemaServer.addFields([
this._recordIndexGridField,
this._hiddenStrValGridField,
this._intValGridField,
this._strValGridField,
this._numberValGridField,
this._dateValGridField,
this._statusIdValGridField,
]);
}
start(): void {
// no code needed
}
private getMainCellPainter(_viewCell: RevViewCell<RevSimpleBehavioredColumnSettings, GridField>) {
return this._mainCellPainter;
}
private getHeaderCellPainter(_viewCell: RevViewCell<RevSimpleBehavioredColumnSettings, GridField>) {
return this._headerCellPainter;
}
private handleCellFocusChanged(newPoint: RevPoint | undefined, oldPoint: RevPoint | undefined): void {
const newText = newPoint === undefined ? '()' : `(${newPoint.x}, ${newPoint.y})`;
const oldText = oldPoint === undefined ? '()' : `(${oldPoint.x}, ${oldPoint.y})`;
console.log(`Focus for Record: New: ${newText} Old: ${oldText}`);
}
private handleCellFocusClick(cell: RevViewCell<RevSimpleBehavioredColumnSettings, GridField>): void {
if (cell.isHeader) {
console.log(`Click for Header in field ${cell.viewLayoutColumn.column.field.name}`);
} else {
if (cell.isMain) {
const recordIndex = this._mainDataServer.getRecordIndexFromRowIndex(cell.viewLayoutRow.subgridRowIndex);
console.log(`Click for Record ${recordIndex} field ${cell.viewLayoutColumn.column.field.name}`);
} else {
throw new Error('Click in unknown subgrid');
}
}
}
private handleRecordFocusDblClick(cell: RevViewCell<RevSimpleBehavioredColumnSettings, GridField>): void {
if (cell.isHeader) {
console.log(`Double click for Header in field ${cell.viewLayoutColumn.column.field.name}`);
} else {
if (cell.isMain) {
const recordIndex = this._mainDataServer.getRecordIndexFromRowIndex(cell.viewLayoutRow.subgridRowIndex);
console.log(`Double click for Record ${recordIndex} field ${cell.viewLayoutColumn.column.field.name}`);
} else {
throw new Error('Double click in unknown subgrid');
}
}
}
private handleColumnSort(headerOrFixedRowCell: RevViewCell<RevSimpleBehavioredColumnSettings, GridField>) {
this._mainDataServer.sortBy(headerOrFixedRowCell.viewLayoutColumn.column.field.index);
}
}
const backgroundColor = '#212121';
const foregroundColor = '#f9f0f0';
const columnHeaderBackgroundColor = '#626262';
const columnHeaderForegroundColor = 'white';