@eclipse-scout/core
Version:
Eclipse Scout runtime
271 lines (243 loc) • 9.64 kB
text/typescript
/*
* 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 {arrays, Column, ObjectWithType, scout, ShowInvisibleColumnsForm, Table} from '../../index';
/**
* If present on a table, allows adding, removing or modifying columns. If the table is customizable,
* those functions are delegated to the table customizer. Otherwise, adding or removing a column
* changes its `visible` flag, while modifying is currently not supported.
*
* Use {@link install} to attach the table organizer to a table. This happens automatically when
* the table organizer is defined on the {@link Table}.
*
* @see Table.organizer
* @see TableHeaderMenu._renderColumnActionsGroup
* @see ShowInvisibleColumnsForm
*/
export class TableOrganizer implements ObjectWithType {
objectType: string;
table: Table;
constructor() {
this.table = null; // set with install()
}
/**
* Passes the given table to the organizer.
* If the organizer is already installed, an error is thrown.
* In most cases, it is not necessary to call this method manually. Consider using {@link Table.setOrganizer} instead.
*/
install(table: Table) {
if (this.table) {
throw new Error('Already installed');
}
this.table = scout.assertInstance(table, Table);
}
/**
* Removes the table from the organizer.
* If the organizer is not installed, nothing happens.
* In most cases, it is not necessary to call this method manually. Consider using {@link Table.setOrganizer} instead.
*/
uninstall() {
this.table = null;
}
// --------------------
/**
* Returns a list of all currently invisible but displayable columns that can be added to the list of
* visible columns by the table organizer.
*/
getInvisibleColumns(): Column<any>[] {
if (!this.table) {
return []; // not installed
}
let displayableColumns = this.table.displayableColumns();
let visibleColumns = this.table.visibleColumns();
return arrays.diff(displayableColumns, visibleColumns);
}
/**
* Adds the given columns to the list of visible columns. If `insertAfterColumn` is set, the columns are
* also moved after the specified column. Otherwise, they remain at their current position.
*/
showColumns<T>(columns: Column<any>[], insertAfterColumn?: Column<any>) {
if (!this.table) {
return; // not installed
}
columns = arrays.ensure(columns).filter(column => this.table.columns.includes(column));
if (!columns.length) {
return; // nothing to do
}
// Make the columns visible
columns.forEach(column => column.setVisible(true, false)); // parameter 'false' skips call of onColumnVisibilityChanged()
// If a "insertAfterColumn" is provided, move the columns to a position right after that column.
// Otherwise, the selected columns are only made visible, but not moved.
if (insertAfterColumn && insertAfterColumn.visible && this.table.columns.includes(insertAfterColumn)) {
this._moveColumns(columns, insertAfterColumn);
}
this.table.onColumnVisibilityChanged(); // do this only once, will also update the aggregate rows
}
protected _moveColumns(columns: Column<any>[], insertAfterColumn: Column<any>) {
for (const column of columns.reverse()) {
let visibleColumns = this.table.visibleColumns();
let visibleOldPos = visibleColumns.indexOf(column);
let visibleNewPos = visibleColumns.indexOf(insertAfterColumn);
this.table._moveColumn(column, visibleColumns, visibleOldPos, visibleNewPos);
}
}
/**
* Hides the given columns. If it was grouped, the grouping is removed. If it was part of a filter, the filter is removed.
*/
hideColumns(columns: Column<any>[]) {
if (!this.table) {
return; // not installed
}
columns = arrays.ensure(columns).filter(Boolean);
if (!columns.length) {
return; // nothing to do
}
for (let column of columns) {
column.setVisible(false, false); // parameter 'false' skips call of onColumnVisibilityChanged()
if (column.grouped) {
this.table.removeGroupColumn(column);
}
if (column.sortActive) {
this.table.removeSortColumn(column);
}
this.table.removeFilterByKey(column.id);
}
this.table.onColumnVisibilityChanged(); // do this only once, will also update the aggregate rows
}
/**
* Moves the columns to their new position according to the indices in the given `visibleColumns` array.
*/
moveColumns(visibleColumns: Column<any>[]) {
// Add guiOnly columns to visibleColumns array if they are not already included
// moveColumn only works with indices based on all visibleColumns including guiOnly columns
let guiOnlyColumns = this.table.filterColumns(column => column.guiOnly);
for (const column of guiOnlyColumns.reverse()) {
if (!visibleColumns.includes(column)) {
visibleColumns = [column, ...visibleColumns];
}
}
for (let newPos = 0; newPos < visibleColumns.length; newPos++) {
const column = visibleColumns[newPos];
this.table.moveColumn(column, newPos);
}
}
/**
* Returns true if there are addable columns according to {@link getInvisibleColumns}.
*/
isColumnAddable(): boolean {
if (!this.table) {
return false; // not installed
}
if (!this.table.columnAddable) {
return false; // explicitly disabled
}
if (this.table.isCustomizable()) {
return true;
}
let invisibleColumns = this.getInvisibleColumns();
return arrays.hasElements(invisibleColumns);
}
addColumn(column?: Column<any>): JQuery.Promise<void> {
if (this.table.isCustomizable()) {
return this.table.customizer.addColumn(column);
}
return this._showInvisibleColumnsForm(column);
}
/**
* Returns true if the given column can be removed form the table.
*
* @param allowRemovalOfLastColumn true, to allow the removal of the last visible column. Default is false.
*/
isColumnRemovable(column: Column<any>, allowRemovalOfLastColumn = false): boolean {
if (!this.table) {
return false; // not installed
}
if (!column.removable) {
return false; // explicitly disabled
}
if (column.fixedPosition) {
return false;
}
if (this.table.isCustomizable() && this.table.customizer.isCustomizable(column)) {
return true;
}
// Prevent removal of last column, because there may not always be a table organizer menu to add it again
return this.table.visibleColumns(false).length > (allowRemovalOfLastColumn ? 0 : 1);
}
removeColumns(columns: Column<any>[]) {
if (this.table.isCustomizable()) {
let customizableColumns = columns.filter(column => this.table.customizer.isCustomizable(column));
let nonCustomizableColumns = columns.filter(column => !this.table.customizer.isCustomizable(column));
this.table.customizer.removeColumns(customizableColumns);
this.hideColumns(nonCustomizableColumns);
} else {
this.hideColumns(columns);
}
}
/**
* Returns true if the given column can be modified.
*/
isColumnModifiable(column: Column<any>): boolean {
if (!this.table) {
return false; // not installed
}
if (!column.modifiable) {
return false; // explicitly disabled
}
if (this.table.isCustomizable() && this.table.customizer.isCustomizable(column)) {
return true;
}
return false;
}
modifyColumn(column: Column<any>): JQuery.Promise<void> {
if (this.table.isCustomizable() && this.table.customizer.isCustomizable(column)) {
return this.table.customizer.modifyColumn(column);
}
return $.resolvedPromise(); // non-customized columns cannot be modified
}
/**
* @returns true if the column can be moved to the left.
* It cannot be moved if the column is invisible, the column is already at the beginning or if left of the column is a fixed position column.
*/
isColumnMovableToLeft(column: Column<any>): boolean {
if (!column.visible) {
return false;
}
let visibleOldPos = this.table.visibleColumns().indexOf(column);
let visibleNewPos = visibleOldPos - 1;
visibleNewPos = this.table.considerFixedPositionColumns(visibleOldPos, visibleNewPos);
return visibleNewPos >= 0 && visibleNewPos < visibleOldPos;
}
/**
* @returns true if the column can be moved to the right.
* It cannot be moved if the column is invisible, the column is already at the end or if right of the column is a fixed position column.
*/
isColumnMovableToRight(column: Column<any>): boolean {
if (!column.visible) {
return false;
}
let visibleColumns = this.table.visibleColumns();
let visibleOldPos = visibleColumns.indexOf(column);
let visibleNewPos = visibleOldPos + 1;
visibleNewPos = this.table.considerFixedPositionColumns(visibleOldPos, visibleNewPos);
return visibleNewPos < visibleColumns.length && visibleNewPos > visibleOldPos;
}
protected _showInvisibleColumnsForm(insertAfterColumn?: Column<any>): JQuery.Promise<void> {
let form = scout.create(ShowInvisibleColumnsForm, {
parent: this.table,
data: {
columns: this.getInvisibleColumns()
}
});
form.open();
return form.whenSave().then(() => {
this.showColumns(form.data.columns, insertAfterColumn);
});
}
}