@eclipse-scout/core
Version:
Eclipse Scout runtime
118 lines (100 loc) • 4.54 kB
text/typescript
/*
* Copyright (c) 2010, 2023 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 {Dimension, graphics, HtmlComponent, HtmlCompPrefSizeOptions, HtmlEnvironment, PopupLayout, SmartFieldPopup} from '../../../index';
/**
* The popup layout is different from other layouts, since it can determine its own size
* when the autoSize flag is set to true. Otherwise it uses the given size, like a regular
* layout. The autoSize feature is used, when a child of the SmartFieldPopupLayout invalidates the
* tree up to the popup. Since the popup is a validate root it must re-layout itself.
* However: the size of the popup depends on the field it belongs to.
*
* The proposal-chooser DIV is not always present.
*/
export class SmartFieldPopupLayout extends PopupLayout {
declare popup: SmartFieldPopup<any>;
animating: boolean;
constructor(popup: SmartFieldPopup<any>) {
super(popup);
this.animating = false;
this.doubleCalcPrefSize = false;
}
override layout($container: JQuery) {
let size, popupSize,
htmlProposalChooser = this._htmlProposalChooser();
// skip layout while CSS animation is running (prefSize would not work while animation is running)
if (this.animating) {
this.popup.htmlComp.$comp.oneAnimationEnd(() => {
this.popup.revalidateLayout();
});
return;
}
super.layout($container);
popupSize = this.popup.htmlComp.size();
size = popupSize.subtract(this.popup.htmlComp.insets());
htmlProposalChooser.setSize(size);
if (this.popup.htmlComp.layouted) {
// Reposition because opening direction may have to be switched if popup gets bigger
// Don't do it the first time (will be done by popup.open), only if the popup is already
// open and gets layouted again
this.popup.position();
} else if (SmartFieldPopup.hasPopupAnimation()) {
// This code here is a bit complicated because:
// 1. we must position the scrollTo position before we start the animation
// because it looks ugly, when we jump to the scroll position after the
// animation has ended
// 2. we must first layout the popup with the table/tree correctly because
// revealSelection doesn't work when popup has not the right size or is
// not visible. That's why we must set the visibility to hidden.
// 3. we wait for the layout validator until the popup layout is validated
// which means the scroll position is set correctly. Then we make the
// popup visible again and start the animation (which shrinks the popup
// to 1px height initially.
this.animating = true;
this.popup.htmlComp.$comp.css('visibility', 'hidden');
this.popup.session.layoutValidator.schedulePostValidateFunction(() => {
this.popup.htmlComp.$comp.css('visibility', '');
this.popup.htmlComp.$comp.addClassForAnimation('animate-open');
this.popup.htmlComp.$comp.oneAnimationEnd(() => {
this.animating = false;
this.popup._onAnimationEnd();
});
});
}
}
override preferredLayoutSize($container: JQuery, options?: HtmlCompPrefSizeOptions): Dimension {
let prefSize,
htmlProposalChooser = this._htmlProposalChooser(),
fieldBounds = graphics.offsetBounds(this.popup.smartField.$field);
if (htmlProposalChooser) {
prefSize = htmlProposalChooser.prefSize(options);
prefSize = prefSize.add(this.popup.htmlComp.insets());
} else {
prefSize = new Dimension(
HtmlEnvironment.get().formColumnWidth,
HtmlEnvironment.get().formRowHeight * 2);
}
prefSize.width = Math.max(fieldBounds.width, prefSize.width);
prefSize.height = Math.max(15, Math.min(350, prefSize.height)); // at least some pixels height in case there is no data, no status, no active filter
if (prefSize.width > this._maxWindowSize()) {
prefSize.width = this._maxWindowSize();
}
return prefSize;
}
protected _htmlProposalChooser(): HtmlComponent {
let proposalChooser = this.popup.proposalChooser;
if (!proposalChooser) {
return null;
}
return proposalChooser.htmlComp;
}
protected _maxWindowSize(): number {
return this.popup.$container.window().width() - (2 * this.popup.windowPaddingX);
}
}