@eclipse-scout/core
Version:
Eclipse Scout runtime
148 lines (127 loc) • 6.07 kB
text/typescript
/*
* Copyright (c) 2010, 2024 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 {EventHandler, icons, InitModelOf, NavigateButton, OutlinePageChangedEvent, OutlinePageRowLinkEvent, Page, TableAllRowsDeletedEvent, TableRowsDeletedEvent, TableRowsInsertedEvent, TableRowsSelectedEvent} from '../../../index';
export class NavigateDownButton extends NavigateButton {
protected _detailTableRowsSelectedHandler: EventHandler<TableRowsSelectedEvent>;
protected _detailTableRowsChangedHandler: EventHandler<TableRowsInsertedEvent | TableRowsDeletedEvent | TableAllRowsDeletedEvent>;
protected _outlinePageRowLinkHandler: EventHandler<OutlinePageRowLinkEvent>;
protected _outlinePageChangedHandler: EventHandler<OutlinePageChangedEvent>;
constructor() {
super();
this._defaultIconId = icons.ANGLE_DOWN;
this._defaultText = 'ui.Continue';
this.iconId = this._defaultIconId;
this.keyStroke = 'enter';
this._detailTableRowsSelectedHandler = this._onDetailTableRowsSelected.bind(this);
this._detailTableRowsChangedHandler = this._onDetailTableRowsChanged.bind(this);
this._outlinePageRowLinkHandler = this._onOutlinePageRowLink.bind(this);
this._outlinePageChangedHandler = this._onOutlinePageChanged.bind(this);
}
protected override _init(options: InitModelOf<this>) {
super._init(options);
if (this.node.detailTable) {
this.node.detailTable.on('rowsSelected', this._detailTableRowsSelectedHandler);
this.node.detailTable.on('rowsInserted rowsDeleted allRowsDeleted', this._detailTableRowsChangedHandler);
}
this.outline.on('pageRowLink', this._outlinePageRowLinkHandler);
this.outline.on('pageChanged', this._outlinePageChangedHandler);
}
protected override _destroy() {
if (this.node.detailTable) {
this.node.detailTable.off('rowsSelected', this._detailTableRowsSelectedHandler);
this.node.detailTable.off('rowsInserted rowsDeleted allRowsDeleted', this._detailTableRowsChangedHandler);
}
this.outline.off('pageRowLink', this._outlinePageRowLinkHandler);
this.outline.off('pageChanged', this._outlinePageChangedHandler);
super._destroy();
}
protected override _render() {
super._render();
this.$container.addClass('down');
}
protected _isDetail(): boolean {
// Button is in "detail mode" if there are both detail form and detail table visible and detail form is _not_ hidden.
return this._hasDetailForm() && this._hasDetailTable() && this.node.detailFormVisibleByUi;
}
protected _toggleDetail(): boolean {
return false;
}
protected _buttonEnabled(): boolean {
if (this._isDetail()) {
return true;
}
return !!this._getDrillNode();
}
protected _getDrillNode(): Page {
if (this.node.leaf) {
return null;
}
// If there is a detail table that defines the child pages, check if a row is selected.
if (this._hasDetailTable(false)) {
let selectedRows = this.node.detailTable.selectedRows;
// Drill down is only possible when a single row is selected and that row is linked to a page
if (selectedRows.length === 1 && selectedRows[0].page) {
return selectedRows[0].page;
}
return null;
}
// If the detail table is not available, the user cannot select a row, thus we default to the first child node.
// Further child nodes cannot be reached by this, this is considered to be a configuration error.
return this.node.childNodes[0];
}
protected _drill() {
let drillNode = this._getDrillNode();
if (drillNode) {
// Collapse other expanded child nodes
let parentNode = drillNode.parentNode;
if (parentNode) {
parentNode.childNodes.forEach(childNode => {
if (childNode.expanded && childNode !== drillNode) {
this.outline.collapseNode(childNode, {
renderAnimated: false
});
}
});
}
this.outline.drillDown(drillNode);
}
}
// Notes about event listeners:
// - There are up to two instances for each navigate button per page: one for the detail form, one for the detail table.
// They only _look_ like the same button because they occupy the same space.
// - Listeners are attached when buttons are created, which is the case when the page is first activated.
// - Listeners remain attached until the page is destroyed. Deselecting the page does not change the listeners.
// - Buttons only need to be updated when "their" rows/nodes change. This is naturally the case for detail table events.
// Outline listeners on the other hand will be triggered for _any_ change in the tree. To prevent too many or unnecessary
// updates, some additional filters are applied in the event handlers.
protected _onDetailTableRowsSelected(event: TableRowsSelectedEvent) {
this.updateEnabled();
}
protected _onDetailTableRowsChanged(event: TableRowsInsertedEvent | TableRowsDeletedEvent | TableAllRowsDeletedEvent) {
this.updateEnabled();
}
protected _onOutlinePageRowLink(event: OutlinePageRowLinkEvent) {
// This listener is needed because linking a row with a page can happen independent of other events,
// e.g. OutlineAdapter#_linkNodeWithRowLater. However, we only need to update the button when exactly
// one row is selected and that row is referenced in the event. In all other cases the availability
// of the button would not change anyway (see logic in _getDrillNode).
if (this._hasDetailTable(false)) {
let selectedRows = this.node.detailTable.selectedRows;
if (selectedRows.length === 1 && selectedRows[0] === event.row) {
this.updateEnabled();
}
}
}
protected _onOutlinePageChanged(event: OutlinePageChangedEvent) {
if (event.page === this.node) {
this.updateEnabled();
}
}
}