@eclipse-scout/core
Version:
Eclipse Scout runtime
144 lines (125 loc) • 4.71 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, DisplayParent, Form, InitModelOf, ObjectModel, ObjectWithType, scout, Session, SomeRequired, Widget} from '../index';
/**
* Controller with functionality to register and render display children.
*/
export class DisplayChildController implements DisplayChildControllerModel, ObjectWithType {
declare model: DisplayChildControllerModel;
declare initModel: SomeRequired<this['model'], 'displayParent' | 'session'>;
objectType: string;
displayParent: DisplayParent;
session: Session;
constructor(model: InitModelOf<DisplayChildController>) {
this.displayParent = model.displayParent;
this.session = model.session;
}
/**
* Adds the given display child to this controller and renders it.
*/
registerAndRender(child: DisplayChild) {
scout.assertProperty(child, 'displayParent');
this._render(child, true);
}
/**
* Removes the given display child from this controller and DOM. However, the display child's adapter is not destroyed. That only happens once the display child is closed.
*/
unregisterAndRemove(child: DisplayChild) {
if (child) {
this._unregister(child);
this._remove(child);
}
}
protected _render(child: DisplayChild, register?: boolean) {
// missing displayParent (when render is called by reload), use displayParent of DisplayChildController
if (!child.displayParent) {
child._setProperty('displayParent', this.displayParent);
}
// Prevent "Already rendered" errors (see #162954).
if (child.rendered) {
return;
}
if (register) {
this._register(child);
}
// Use parent's function or (if not implemented) our own.
if (this.displayParent.acceptView) {
if (!this.displayParent.acceptView(child)) {
return;
}
} else if (!this.acceptView(child)) {
return;
}
// Open all display children in the center of the desktop, except the ones that belong to a popup-window
// Since the display child doesn't have a DOM element as parent when render is called, we must find the
// entryPoint by using the model.
let $parent;
if (this.displayParent instanceof Form && this.displayParent.isPopupWindow()) {
$parent = this.displayParent.popupWindow.$container;
} else {
$parent = this.session.desktop.$container;
}
// start focus tracking if not already started.
child.setTrackFocus(true);
child.render($parent);
// Only display the display child if its 'displayParent' is visible to the user.
if (!this.displayParent.inFront()) {
child.detach();
}
}
protected _remove(child: DisplayChild) {
child.remove();
}
acceptView(view: DisplayChild): boolean {
// Only render display child if displayParent is already rendered.
// If not, the child will be rendered once the displayParent is rendered.
return this.displayParent.rendered;
}
protected _register(child: DisplayChild) {
// use _registerChild in subclass
}
protected _unregister(child: DisplayChild) {
// use _unregisterChild in subclass
}
protected _registerChild(child: DisplayChild, propertyName: string, position?: number) {
const children: DisplayChild[] = arrays.ensure(this.displayParent[propertyName]);
if (children.includes(child)) {
return;
}
child.one('destroy', e => this._unregisterChild(child, propertyName));
let newChildren;
if (position !== undefined) {
newChildren = [...children];
arrays.insert(newChildren, child, position);
} else {
newChildren = [...children, child];
}
// Using _setProperty to just set the property and trigger the event without calling _set[propertyName] or any render function
this.displayParent._setProperty(propertyName, newChildren);
}
protected _unregisterChild(child: DisplayChild, propertyName: string) {
const children: DisplayChild[] = this.displayParent[propertyName];
if (!children?.length) {
return;
}
let newChildren = children.filter(f => f !== child);
if (arrays.equals(children, newChildren)) {
return;
}
this.displayParent._setProperty(propertyName, newChildren);
}
}
export interface DisplayChild extends Widget {
displayParent: DisplayParent;
}
export interface DisplayChildControllerModel extends ObjectModel<DisplayChild> {
displayParent?: DisplayParent;
session?: Session;
}