UNPKG

@eclipse-scout/core

Version:
257 lines (221 loc) 8.8 kB
/* * Copyright (c) 2010, 2025 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 */ import { BooleanColumn, Cell, Column, CompactBean, CompactLine, Event, EventHandler, InitModelOf, objects, ObjectWithType, SomeRequired, Table, TableCompactHandlerModel, TableRow, TableRowsInsertedEvent, TableRowsUpdatedEvent } from '../index'; export class TableCompactHandler implements TableCompactHandlerModel, ObjectWithType { declare model: TableCompactHandlerModel; declare initModel: SomeRequired<this['model'], 'table'>; objectType: string; table: Table; useOnlyVisibleColumns: boolean; maxContentLines: number; moreLinkAvailable: boolean; lineCustomizer: (line: CompactLine) => void; protected _oldStates: Record<string, any>; protected _updateHandler: EventHandler<TableRowsInsertedEvent | TableRowsUpdatedEvent | Event<Table>>; constructor() { this.table = null; this.useOnlyVisibleColumns = true; this.maxContentLines = 3; this.moreLinkAvailable = true; this.lineCustomizer = null; this._oldStates = objects.createMap(); this._updateHandler = null; } init(model: InitModelOf<this>) { $.extend(this, model); } setUseOnlyVisibleColumns(useOnlyVisibleColumns: boolean) { this.useOnlyVisibleColumns = useOnlyVisibleColumns; } setMaxContentLines(maxContentLines: number) { this.maxContentLines = maxContentLines; } setMoreLinkAvailable(moreLinkAvailable: boolean) { this.moreLinkAvailable = moreLinkAvailable; } setLineCustomizer(lineCustomizer: (line: CompactLine) => void) { this.lineCustomizer = lineCustomizer; } handle(compact: boolean) { if (compact) { this._compactColumns(true); this._attachTableHandler(); } else { this._detachTableHandler(); this._compactColumns(false); } this._adjustTable(compact); if (compact) { this.updateValues(this.table.rows); } } protected _adjustTable(compact: boolean) { if (compact) { this._cacheAndSetProperty('headerVisible', () => this.table.headerVisible, () => this.table.setHeaderVisible(false)); this._cacheAndSetProperty('autoResizeColumns', () => this.table.autoResizeColumns, () => this.table.setAutoResizeColumns(true)); } else { this._resetProperty('headerVisible', value => this.table.setHeaderVisible(value)); this._resetProperty('autoResizeColumns', value => this.table.setAutoResizeColumns(value)); } } protected _cacheAndSetProperty(propertyName: string, getter: () => any, setter: () => void) { if (objects.isNullOrUndefined(this._oldStates[propertyName])) { this._oldStates[propertyName] = getter(); } setter(); } protected _resetProperty(propertyName: string, setter: (oldValue: any) => void) { let oldState = this._oldStates[propertyName]; if (!objects.isNullOrUndefined(oldState)) { setter(oldState); delete this._oldStates[propertyName]; } } protected _compactColumns(compact: boolean) { this.table.displayableColumns(false).forEach(column => column.setCompacted(compact, false)); this.table.onColumnVisibilityChanged(); } protected _attachTableHandler() { if (this._updateHandler == null) { this._updateHandler = this._onTableEvent.bind(this); this.table.on('rowsInserted rowsUpdated columnStructureChanged', this._updateHandler); } } protected _detachTableHandler() { if (this._updateHandler != null) { this.table.off('rowsInserted rowsUpdated columnStructureChanged', this._updateHandler); this._updateHandler = null; } } updateValues(rows: TableRow[]) { if (rows.length === 0) { return; } let columns = this.getColumns(); rows.forEach(row => this._updateValue(columns, row)); } protected _updateValue(columns: Column<any>[], row: TableRow) { row.setCompactValue(this.buildValue(columns, row)); } buildValue(columns: Column<any>[], row: TableRow): string { return this._buildValue(this._createBean(columns, row)); } protected _createBean(columns: Column<any>[], row: TableRow): CompactBean { let bean = new CompactBean(); this._processColumns(columns, row, bean); this._postProcessBean(bean); return bean; } protected _processColumns(columns: Column<any>[], row: TableRow, bean: CompactBean) { columns.forEach((column, i) => this._processColumn(column, i, row, bean)); } getColumns(): Column<any>[] { return this.table.filterColumns(column => this._acceptColumn(column)); } protected _acceptColumn(column: Column<any>): boolean { return !column.guiOnly && (!this.useOnlyVisibleColumns || column.visibleIgnoreCompacted); } protected _processColumn(column: Column<any>, index: number, row: TableRow, bean: CompactBean) { this._updateBean(bean, column, index, row); } /** * @param bean * the bean for the current row * @param column * the currently processed column * @param index * visible column index of the currently processed column * @param row * the current row */ protected _updateBean(bean: CompactBean, column: Column<any>, index: number, row: TableRow) { if (this._acceptColumnForTitle(column, index)) { bean.setTitleLine(this._createCompactLine(column, index, row)); } else if (this._acceptColumnForTitleSuffix(column, index)) { bean.setTitleSuffixLine(this._createCompactLine(column, index, row)); } else if (this._acceptColumnForSubtitle(column, index)) { bean.setSubtitleLine(this._createCompactLine(column, index, row)); } else { bean.addContentLine(this._createCompactLine(column, index, row)); } } protected _acceptColumnForTitle(column: Column<any>, index: number): boolean { return index === 0; } protected _acceptColumnForSubtitle(column: Column<any>, index: number): boolean { return index === 1; } protected _acceptColumnForTitleSuffix(column: Column<any>, index: number): boolean { return false; } protected _createCompactLine(column: Column<any>, index: number, row: TableRow): CompactLine { let headerCell: Cell; if (this._showLabel(column, index, row)) { headerCell = column.headerCell(); } let cell = column.cell(row); let line = new CompactLine(headerCell, cell); this._adaptCompactLine(line, column, headerCell, cell); return line; } protected _showLabel(column: Column<any>, index: number, row: TableRow): boolean { return !this._acceptColumnForTitle(column, index) && !this._acceptColumnForSubtitle(column, index) && !this._acceptColumnForTitleSuffix(column, index); } protected _adaptCompactLine<TValue>(line: CompactLine, column: Column<TValue>, headerCell: Cell<TValue>, cell: Cell<TValue>) { if (column instanceof BooleanColumn) { let text = ''; let value = cell.value as boolean; if (value) { text = 'X'; } else if (value === null) { text = '?'; } line.textBlock.setText(text); } this.lineCustomizer?.(line); } protected _postProcessBean(bean: CompactBean) { bean.transform({ maxContentLines: this.maxContentLines, moreLinkAvailable: this.moreLinkAvailable }); // If only title is set move it to content. A title without content does not look good. if (bean.title && !bean.subtitle && !bean.titleSuffix && !bean.content) { bean.setContent(bean.title); bean.setTitle(''); } } protected _buildValue(bean: CompactBean): string { let hasHeader = (bean.title + bean.titleSuffix + bean.subtitle) ? ' has-header' : ''; let moreLink = (this.moreLinkAvailable && bean.moreContent) ? `<div class="compact-cell-more"><span class="more-link link">${this.table.session.text('More')}</span></div>` : ''; return ` <div class="compact-cell-header"> <div class="compact-cell-title"> <span class="left">${bean.title}</span> <span class="right">${bean.titleSuffix}</span> </div> <div class="compact-cell-subtitle">${bean.subtitle}</div> </div> <div class="compact-cell-content${hasHeader}">${bean.content}</div> <div class="compact-cell-more-content hidden${hasHeader}">${bean.moreContent}</div> ${moreLink}`; } protected _onTableEvent(event: TableRowsInsertedEvent | TableRowsUpdatedEvent | Event<Table>) { let rows: TableRow[]; if (event.type === 'columnStructureChanged') { rows = this.table.rows; } else { rows = (event as TableRowsInsertedEvent | TableRowsUpdatedEvent).rows; } this.updateValues(rows); } }