@eclipse-scout/core
Version:
Eclipse Scout runtime
169 lines (151 loc) • 6.04 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 {AbstractLayout, Desktop, DesktopNavigation, Dimension, HtmlComponent, ResponsiveManager, Tree} from '../index';
export class DesktopLayout extends AbstractLayout {
desktop: Desktop;
constructor(desktop: Desktop) {
super();
this.desktop = desktop;
}
override layout($container: JQuery) {
let animationProps,
navigationWidth = 0,
headerHeight = 0,
desktop = this.desktop,
navigation = desktop.navigation,
header = desktop.header,
bench = desktop.bench,
// Animation moves header and bench to the left when navigation gets invisible or moves bench to the right if bench gets invisible (used for mobile)
animated = desktop.animateLayoutChange,
containerSize = this.containerSize(),
fullWidthNavigation = navigation && navigation.htmlComp.layoutData.fullWidth;
ResponsiveManager.get().handleResponsive(desktop, $container.width());
if (navigation) {
navigationWidth = this.calculateNavigationWidth(containerSize);
if (desktop.splitter) {
desktop.splitter.setPosition(navigationWidth);
}
if (desktop.navigationVisible) {
let htmlNavigation = navigation.htmlComp;
let navigationSize = new Dimension(navigationWidth, containerSize.height)
.subtract(htmlNavigation.margins());
htmlNavigation.setSize(navigationSize);
}
}
if (header) {
let htmlHeader = header.htmlComp;
headerHeight = htmlHeader.$comp.outerHeight(true);
if (desktop.headerVisible) {
// positioning
if (!animated) {
header.$container.cssLeft(navigationWidth);
}
// sizing
let headerSize = new Dimension(containerSize.width - navigationWidth, headerHeight)
.subtract(htmlHeader.margins());
if (!animated || fullWidthNavigation) {
htmlHeader.setSize(headerSize);
}
if (animated) {
animationProps = {
left: containerSize.width
};
prepareAnimate(animationProps, htmlHeader, headerSize);
this._animate(animationProps, htmlHeader);
}
}
}
if (bench) {
let htmlBench = bench.htmlComp;
if (desktop.benchVisible) {
// positioning
bench.$container.cssTop(headerHeight);
if (!animated) {
bench.$container.cssLeft(navigationWidth);
}
// sizing
let benchSize = new Dimension(containerSize.width - navigationWidth, containerSize.height - headerHeight)
.subtract(htmlBench.margins());
if (!animated || fullWidthNavigation) {
htmlBench.setSize(benchSize);
}
if (animated) {
animationProps = {
left: containerSize.width
};
prepareAnimate(animationProps, htmlBench, benchSize);
this._animate(animationProps, htmlBench);
}
}
}
function prepareAnimate(animationProps: any, htmlComp: HtmlComponent, size: Dimension) {
if (fullWidthNavigation) {
// Slide bench in from right to left, don't resize
htmlComp.$comp.cssLeft(containerSize.width);
} else {
// Resize bench
animationProps.width = size.width;
// Layout once before animation begins
// Resizing on every step/progress would result in poor performance (e.g. when a form is open in the bench)
htmlComp.setSize(size);
}
// Move to new point (=0, if navigation is invisible)
animationProps.left = navigationWidth;
}
}
/**
* Used to animate bench and header
*/
protected _animate(animationProps: any, htmlComp: HtmlComponent) {
// If animation is already running, stop the existing and don't use timeout to schedule the new to have a smoother transition
// Concurrent animation of the same element is bad because jquery messes up the overflow style
if (htmlComp.$comp.is(':animated')) {
animate.call(this);
} else {
// schedule animation to have a smoother start
setTimeout(animate.bind(this));
}
function animate() {
htmlComp.$comp.stop().animate(animationProps, {
complete: this.desktop.onLayoutAnimationComplete.bind(this.desktop),
step: this.desktop.onLayoutAnimationStep.bind(this.desktop)
});
}
}
containerSize(): Dimension {
let htmlContainer = this.desktop.htmlComp,
containerSize = htmlContainer.availableSize({exact: true});
return containerSize.subtract(htmlContainer.insets());
}
calculateNavigationWidth(containerSize: Dimension): number {
if (!this.desktop.navigationVisible) {
return 0;
}
let navigationLayoutData = this.desktop.navigation.htmlComp.layoutData;
if (navigationLayoutData.fullWidth) {
return containerSize.width;
}
let splitterPosition = 0;
if (this.desktop.splitter) {
splitterPosition = this.desktop.splitter.position;
}
let outline = this.desktop.outline;
if (!this.desktop.resizing && outline && outline.toggleBreadcrumbStyleEnabled) {
// If toggleBreadcrumbStyleEnabled is true, BREADCRUMB_STYLE_WIDTH triggers the toggling between the two modes.
// This code ensures this rule is never violated (necessary if mode is toggled programmatically rather than by the user)
if (outline.displayStyle === Tree.DisplayStyle.BREADCRUMB) {
splitterPosition = DesktopNavigation.BREADCRUMB_STYLE_WIDTH;
} else if (Math.floor(splitterPosition) <= DesktopNavigation.BREADCRUMB_STYLE_WIDTH) {
splitterPosition = DesktopNavigation.DEFAULT_STYLE_WIDTH;
}
}
return Math.max(splitterPosition, DesktopNavigation.MIN_WIDTH); // ensure newSize is not negative
}
}