import * as columns from "../../../columns"; import * as headerAction from "../../../header/action"; import * as headerType from "../../../header/type"; import type { CellRange, LayoutObjectId } from "../../../ts-types"; import type { ColumnData, ColumnDefine, GroupHeaderDefine, HeaderData, HeadersDefine, LayoutMapAPI, } from "../api"; import { EmptyDataCache } from "./utils"; let seqId = 0; export class SimpleHeaderLayoutMap implements LayoutMapAPI { private _headerObjects: HeaderData[]; private _headerObjectMap: { [key in LayoutObjectId]: HeaderData }; private _headerCellIds: number[][]; private _columns: ColumnData[]; readonly bodyRowCount: number = 1; private _emptyDataCache = new EmptyDataCache(); constructor(header: HeadersDefine) { this._columns = []; this._headerCellIds = []; this._headerObjects = this._addHeaders(0, header, []); this._headerObjectMap = this._headerObjects.reduce((o, e) => { o[e.id as number] = e; return o; }, {} as { [key in LayoutObjectId]: HeaderData }); } get columnWidths(): ColumnData[] { return this._columns; } get headerRowCount(): number { return this._headerCellIds.length; } get colCount(): number { return this._columns.length; } get headerObjects(): HeaderData[] { return this._headerObjects; } get columnObjects(): ColumnData[] { return this._columns; } getCellId(col: number, row: number): LayoutObjectId { if (this.headerRowCount <= row) { return this._columns[col].id; } //in header return this._headerCellIds[row][col]; } getHeader(col: number, row: number): HeaderData { const id = this.getCellId(col, row); return ( this._headerObjectMap[id as number] || this._emptyDataCache.getHeader(col, row) ); } getBody(col: number, _row: number): ColumnData { return this._columns[col] || this._emptyDataCache.getBody(col, 0); } getBodyLayoutRangeById(id: LayoutObjectId): CellRange { for (let col = 0; col < this.colCount; col++) { if (id === this._columns[col].id) { return { start: { col, row: 0 }, end: { col, row: 0 }, }; } } throw new Error(`can not found body layout @id=${id as number}`); } getCellRange(col: number, row: number): CellRange { const result: CellRange = { start: { col, row }, end: { col, row } }; if (this.headerRowCount <= row) { return result; } //in header const id = this.getCellId(col, row); for (let c = col - 1; c >= 0; c--) { if (id !== this.getCellId(c, row)) { break; } result.start.col = c; } for (let c = col + 1; c < this.colCount; c++) { if (id !== this.getCellId(c, row)) { break; } result.end.col = c; } for (let r = row - 1; r >= 0; r--) { if (id !== this.getCellId(col, r)) { break; } result.start.row = r; } for (let r = row + 1; r < this.headerRowCount; r++) { if (id !== this.getCellId(col, r)) { break; } result.end.row = r; } return result; } getRecordIndexByRow(row: number): number { if (row < this.headerRowCount) { return -1; } else { return row - this.headerRowCount; } } getRecordStartRowByRecordIndex(index: number): number { return this.headerRowCount + index; } private _addHeaders( row: number, header: HeadersDefine, roots: number[] ): HeaderData[] { const results: HeaderData[] = []; const rowCells = this._headerCellIds[row] || this._newRow(row); header.forEach((hd) => { const col = this._columns.length; const id = seqId++; const cell: HeaderData = { id, caption: hd.caption, field: hd.headerField || (hd as ColumnDefine).field, headerIcon: hd.headerIcon, style: hd.headerStyle, headerType: headerType.ofCell(hd), action: headerAction.ofCell(hd), define: hd, }; results[id] = cell; rowCells[col] = id; for (let r = row - 1; r >= 0; r--) { this._headerCellIds[r][col] = roots[r]; } if ((hd as GroupHeaderDefine).columns) { this._addHeaders(row + 1, (hd as GroupHeaderDefine).columns, [ ...roots, id, ]).forEach((c) => results.push(c)); } else { const colDef = hd as ColumnDefine; this._columns.push({ id: seqId++, field: colDef.field, width: colDef.width, minWidth: colDef.minWidth, maxWidth: colDef.maxWidth, icon: colDef.icon, message: colDef.message, columnType: columns.type.of(colDef.columnType), action: columns.action.of(colDef.action), style: colDef.style, define: colDef, }); for (let r = row + 1; r < this._headerCellIds.length; r++) { this._headerCellIds[r][col] = id; } } }); return results; } private _newRow(row: number): number[] { const newRow: number[] = (this._headerCellIds[row] = []); if (!this._columns.length) { return newRow; } const prev = this._headerCellIds[row - 1]; for (let col = 0; col < prev.length; col++) { newRow[col] = prev[col]; } return newRow; } }