UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

272 lines (271 loc) • 10.7 kB
/** * DevExtreme (esm/__internal/ui/overlay/overlay_position_controller.js) * Version: 25.2.3 * Build date: Fri Dec 12 2025 * * Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ import positionUtils from "../../../common/core/animation/position"; import { locate, move, resetPosition } from "../../../common/core/animation/translator"; import $ from "../../../core/renderer"; import { extend } from "../../../core/utils/extend"; import { isDefined, isEvent, isString, isWindow } from "../../../core/utils/type"; import swatch from "../../core/utils/swatch_container"; import windowUtils from "../../core/utils/m_window"; const window = windowUtils.getWindow(); export const OVERLAY_POSITION_ALIASES = { top: { my: "top center", at: "top center" }, bottom: { my: "bottom center", at: "bottom center" }, right: { my: "right center", at: "right center" }, left: { my: "left center", at: "left center" }, center: { my: "center", at: "center" }, "right bottom": { my: "right bottom", at: "right bottom" }, "right top": { my: "right top", at: "right top" }, "left bottom": { my: "left bottom", at: "left bottom" }, "left top": { my: "left top", at: "left top" } }; const DEFAULT_BOUNDARY_OFFSET = { h: 0, v: 0 }; export const isPositionAlignment = position => isString(position); export class OverlayPositionController { constructor(params) { const { properties: properties, elements: elements } = params; const { container: container, position: position, visualContainer: visualContainer } = properties; const { $root: $root, $content: $content, $wrapper: $wrapper } = elements; this._properties = properties; this._$root = $root; this._$content = $content; this._$wrapper = $wrapper; this._$markupContainer = void 0; this._$visualContainer = void 0; this._shouldRenderContentInitialPosition = true; this._visualPosition = void 0; this._initialPosition = void 0; this._previousVisualPosition = void 0; this.updateContainer(container); this.updatePosition(position); this.updateVisualContainer(visualContainer) } get $container() { this.updateContainer(); return this._$markupContainer } get $visualContainer() { return this._$visualContainer } get position() { return this._position } set fixWrapperPosition(fixWrapperPosition) { this._properties._fixWrapperPosition = fixWrapperPosition; this.styleWrapperPosition() } set restorePosition(restorePosition) { this._properties.restorePosition = restorePosition } updatePosition(position) { this._properties.position = position; this._position = this._normalizePosition(position); this.updateVisualContainer() } updateContainer(container) { const element = container ?? this._properties.container; if (isDefined(container)) { this._properties.container = element } if (element) { this._$markupContainer = $(element) } else if (this._$root) { this._$markupContainer = swatch.getSwatchContainer(this._$root) } this.updateVisualContainer(this._properties.visualContainer) } updateVisualContainer(visualContainer) { if (isDefined(visualContainer)) { this._properties.visualContainer = visualContainer } this._$visualContainer = this._getVisualContainer() } restorePositionOnNextRender(value) { this._shouldRenderContentInitialPosition = value || !this._visualPosition } openingHandled() { const shouldRestorePosition = Boolean(this._properties.restorePosition); this.restorePositionOnNextRender(shouldRestorePosition) } detectVisualPositionChange(event) { this._updateVisualPositionValue(); this._raisePositionedEvents(event) } positionContent() { if (this._shouldRenderContentInitialPosition) { this._renderContentInitialPosition() } else { if (this._$content) { move(this._$content, this._visualPosition) } this.detectVisualPositionChange() } } positionWrapper() { if (this._$visualContainer) { positionUtils.setup(this._$wrapper, { my: "top left", at: "top left", of: this._$visualContainer }) } } styleWrapperPosition() { var _this$$visualContaine, _this$_$wrapper; const isContainerWindow = isWindow(null === (_this$$visualContaine = this.$visualContainer) || void 0 === _this$$visualContaine ? void 0 : _this$$visualContaine.get(0)); const useFixed = isContainerWindow || this._properties._fixWrapperPosition; const positionStyle = useFixed ? "fixed" : "absolute"; null === (_this$_$wrapper = this._$wrapper) || void 0 === _this$_$wrapper || _this$_$wrapper.css("position", positionStyle) } clean() { this._$root = void 0; this._$content = void 0; this._$wrapper = void 0; this._$markupContainer = void 0; this._$visualContainer = void 0 } _updateVisualPositionValue() { this._previousVisualPosition = this._visualPosition; if (this._$content) { this._visualPosition = locate(this._$content) } } _renderContentInitialPosition() { var _this$_$wrapper2, _this$_$wrapper3, _this$_$wrapper4; this._renderBoundaryOffset(); if (this._$content) { resetPosition(this._$content) } const wrapperOverflow = (null === (_this$_$wrapper2 = this._$wrapper) || void 0 === _this$_$wrapper2 ? void 0 : _this$_$wrapper2.css("overflow")) ?? ""; null === (_this$_$wrapper3 = this._$wrapper) || void 0 === _this$_$wrapper3 || _this$_$wrapper3.css("overflow", "hidden"); if (!this._properties._skipContentPositioning) { const resultPosition = positionUtils.setup(this._$content, this._position); this._initialPosition = resultPosition } null === (_this$_$wrapper4 = this._$wrapper) || void 0 === _this$_$wrapper4 || _this$_$wrapper4.css("overflow", wrapperOverflow); this.detectVisualPositionChange() } _raisePositionedEvents(event) { var _this$_properties$onP, _this$_properties2; const previousPosition = this._previousVisualPosition; const newPosition = this._visualPosition; const isTopEqual = (null === previousPosition || void 0 === previousPosition ? void 0 : previousPosition.top) === (null === newPosition || void 0 === newPosition ? void 0 : newPosition.top); const isLeftEqual = (null === previousPosition || void 0 === previousPosition ? void 0 : previousPosition.left) === (null === newPosition || void 0 === newPosition ? void 0 : newPosition.left); const isVisualPositionChanged = !(isTopEqual && isLeftEqual); if (isVisualPositionChanged) { var _this$_properties$onV, _this$_properties; null === (_this$_properties$onV = (_this$_properties = this._properties).onVisualPositionChanged) || void 0 === _this$_properties$onV || _this$_properties$onV.call(_this$_properties, { event: event, previousPosition: previousPosition, position: newPosition }) } null === (_this$_properties$onP = (_this$_properties2 = this._properties).onPositioned) || void 0 === _this$_properties$onP || _this$_properties$onP.call(_this$_properties2, { position: this._initialPosition }) } _renderBoundaryOffset() { var _this$_position, _this$_$content; const boundaryOffset = (null === (_this$_position = this._position) || void 0 === _this$_position ? void 0 : _this$_position.boundaryOffset) ?? DEFAULT_BOUNDARY_OFFSET; const { v: v, h: h } = boundaryOffset; if (!(v && h)) { return } null === (_this$_$content = this._$content) || void 0 === _this$_$content || _this$_$content.css("margin", `${boundaryOffset.v}px ${boundaryOffset.h}px`) } _getVisualContainer() { var _this$_properties$pos, _this$_properties$pos2, _this$_properties$pos3; const containerProp = this._properties.container; const visualContainerProp = this._properties.visualContainer; const positionOf = isEvent(null === (_this$_properties$pos = this._properties.position) || void 0 === _this$_properties$pos ? void 0 : _this$_properties$pos.of) ? null === (_this$_properties$pos2 = this._properties.position) || void 0 === _this$_properties$pos2 || null === (_this$_properties$pos2 = _this$_properties$pos2.of) || void 0 === _this$_properties$pos2 ? void 0 : _this$_properties$pos2.target : null === (_this$_properties$pos3 = this._properties.position) || void 0 === _this$_properties$pos3 ? void 0 : _this$_properties$pos3.of; if (visualContainerProp) { return $(visualContainerProp) } if (containerProp) { return $(containerProp) } if (positionOf) { return $(positionOf) } return $(window) } _normalizePosition(position) { const defaultConfiguration = { boundaryOffset: DEFAULT_BOUNDARY_OFFSET }; if (isDefined(position)) { const positionObject = this._positionToObject(position); const configuration = extend(true, {}, defaultConfiguration, positionObject); return configuration } return defaultConfiguration } _positionToObject(position) { if (isPositionAlignment(position)) { const configuration = Object.assign({}, OVERLAY_POSITION_ALIASES[position]); return configuration } return position } }