UNPKG

devextreme

Version:

JavaScript/TypeScript Component Suite for Responsive Web Development

1,161 lines (1,160 loc) • 45.8 kB
/** * DevExtreme (esm/__internal/ui/popup/m_popup.js) * Version: 25.2.5 * Build date: Fri Feb 20 2026 * * Copyright (c) 2012 - 2026 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ import "../../../ui/toolbar/ui.toolbar.base"; import { triggerResizeEvent } from "../../../common/core/events/visibility_change"; import messageLocalization from "../../../common/core/localization/message"; import registerComponent from "../../../core/component_registrator"; import devices from "../../../core/devices"; import { getPublicElement } from "../../../core/element"; import Guid from "../../../core/guid"; import $ from "../../../core/renderer"; import resizeObserverSingleton from "../../../core/resize_observer"; import { EmptyTemplate } from "../../../core/templates/empty_template"; import { noop } from "../../../core/utils/common"; import { extend } from "../../../core/utils/extend"; import { camelize } from "../../../core/utils/inflector"; import { each } from "../../../core/utils/iterator"; import { getBoundingRect } from "../../../core/utils/position"; import { addOffsetToMaxHeight, addOffsetToMinHeight, getHeight, getOuterWidth, getVerticalOffsets, getVisibleHeight, getWidth } from "../../../core/utils/size"; import { isDefined, isObject } from "../../../core/utils/type"; import Button from "../../../ui/button"; import Resizable from "../../../ui/resizable"; import { current, isFluent, isMaterial, isMaterialBased } from "../../../ui/themes"; import windowUtils from "../../core/utils/m_window"; import Overlay from "../../ui/overlay/overlay"; import * as zIndexPool from "../../ui/overlay/z_index"; import { TOOLBAR_CLASS } from "../../ui/toolbar/constants"; import PopupDrag from "./m_popup_drag"; import { createBodyOverflowManager } from "./m_popup_overflow_manager"; import { PopupPositionController } from "./popup_position_controller"; const window = windowUtils.getWindow(); export const POPUP_CLASS = "dx-popup"; const POPUP_WRAPPER_CLASS = "dx-popup-wrapper"; const POPUP_FULL_SCREEN_CLASS = "dx-popup-fullscreen"; const POPUP_FULL_SCREEN_WIDTH_CLASS = "dx-popup-fullscreen-width"; const POPUP_NORMAL_CLASS = "dx-popup-normal"; export const POPUP_CONTENT_CLASS = "dx-popup-content"; export const POPUP_CONTENT_SCROLLABLE_CLASS = "dx-popup-content-scrollable"; const DISABLED_STATE_CLASS = "dx-state-disabled"; const POPUP_DRAGGABLE_CLASS = "dx-popup-draggable"; const POPUP_TITLE_CLASS = "dx-popup-title"; export const POPUP_TITLE_CLOSEBUTTON_CLASS = "dx-closebutton"; const POPUP_BOTTOM_CLASS = "dx-popup-bottom"; const POPUP_HAS_CLOSE_BUTTON_CLASS = "dx-has-close-button"; export const TEMPLATE_WRAPPER_CLASS = "dx-template-wrapper"; const POPUP_CONTENT_FLEX_HEIGHT_CLASS = "dx-popup-flex-height"; const POPUP_CONTENT_INHERIT_HEIGHT_CLASS = "dx-popup-inherit-height"; const TOOLBAR_LABEL_CLASS = "dx-toolbar-label"; const ALLOWED_TOOLBAR_ITEM_ALIASES = ["cancel", "clear", "done"]; const BUTTON_DEFAULT_TYPE = "default"; const BUTTON_NORMAL_TYPE = "normal"; const BUTTON_TEXT_MODE = "text"; const BUTTON_CONTAINED_MODE = "contained"; const BUTTON_OUTLINED_MODE = "outlined"; const TOOLBAR_NAME_BASE = "dxToolbarBase"; const HEIGHT_STRATEGIES = { static: "", inherit: "dx-popup-inherit-height", flex: "dx-popup-flex-height" }; const getButtonPlace = name => { const device = devices.current(); const { platform: platform } = device; let toolbar = "bottom"; let location = "before"; if ("ios" === platform) { switch (name) { case "cancel": toolbar = "top"; break; case "clear": toolbar = "top"; location = "after"; break; case "done": location = "after" } } else if ("android" === platform) { switch (name) { case "cancel": case "done": location = "after" } } return { toolbar: toolbar, location: location } }; const getLocalizationKey = itemType => "done" === itemType.toLowerCase() ? "OK" : camelize(itemType, true); const getHeightStrategyChangeOffset = (currentHeightStrategyClass, popupVerticalPaddings) => currentHeightStrategyClass === HEIGHT_STRATEGIES.flex ? -popupVerticalPaddings : 0; class Popup extends Overlay { _supportedKeys() { return Object.assign({}, super._supportedKeys(), { upArrow: e => { var _this$_drag; null === (_this$_drag = this._drag) || void 0 === _this$_drag || _this$_drag.moveUp(e) }, downArrow: e => { var _this$_drag2; null === (_this$_drag2 = this._drag) || void 0 === _this$_drag2 || _this$_drag2.moveDown(e) }, leftArrow: e => { var _this$_drag3; null === (_this$_drag3 = this._drag) || void 0 === _this$_drag3 || _this$_drag3.moveLeft(e) }, rightArrow: e => { var _this$_drag4; null === (_this$_drag4 = this._drag) || void 0 === _this$_drag4 || _this$_drag4.moveRight(e) } }) } _getDefaultOptions() { return Object.assign({}, super._getDefaultOptions(), { fullScreen: false, title: "", showTitle: true, titleTemplate: "title", onTitleRendered: null, dragOutsideBoundary: false, dragEnabled: false, enableBodyScroll: true, outsideDragFactor: 0, onResizeStart: null, onResize: null, onResizeEnd: null, resizeEnabled: false, toolbarItems: [], showCloseButton: false, bottomTemplate: "bottom", useDefaultToolbarButtons: false, useFlatToolbarButtons: false, autoResizeEnabled: true }) } _defaultOptionsRules() { return super._defaultOptionsRules().concat([{ device: { platform: "ios" }, options: { animation: this._iosAnimation } }, { device: { platform: "android" }, options: { animation: this._androidAnimation } }, { device: { platform: "generic" }, options: { showCloseButton: true } }, { device: device => "desktop" === devices.real().deviceType && "generic" === device.platform, options: { dragEnabled: true } }, { device: () => "desktop" === devices.real().deviceType && !devices.isSimulator(), options: { focusStateEnabled: true } }, { device: () => isMaterialBased(current()), options: { useFlatToolbarButtons: true } }, { device: () => isMaterial(current()), options: { useDefaultToolbarButtons: true, showCloseButton: false } }]) } _iosAnimation() { return { show: { type: "slide", duration: 400, from: { position: { my: "top", at: "bottom" } }, to: { position: { my: "center", at: "center" } } }, hide: { type: "slide", duration: 400, from: { opacity: 1, position: { my: "center", at: "center" } }, to: { opacity: 1, position: { my: "top", at: "bottom" } } } } } _androidAnimation() { return this.option("fullScreen") ? { show: { type: "slide", duration: 300, from: { top: "30%", opacity: 0 }, to: { top: 0, opacity: 1 } }, hide: { type: "slide", duration: 300, from: { top: 0, opacity: 1 }, to: { top: "30%", opacity: 0 } } } : { show: { type: "fade", duration: 400, from: 0, to: 1 }, hide: { type: "fade", duration: 400, from: 1, to: 0 } } } _init() { var _this$$wrapper, _this$_$content; const { _wrapperClassExternal: popupWrapperClassExternal } = this.option(); const popupWrapperClasses = popupWrapperClassExternal ? `dx-popup-wrapper ${popupWrapperClassExternal}` : "dx-popup-wrapper"; super._init(); this._createBodyOverflowManager(); this._updateResizeCallbackSkipCondition(); this.$element().addClass("dx-popup"); null === (_this$$wrapper = this.$wrapper()) || void 0 === _this$$wrapper || _this$$wrapper.addClass(popupWrapperClasses); this._$popupContent = null === (_this$_$content = this._$content) || void 0 === _this$_$content ? void 0 : _this$_$content.wrapInner($("<div>").addClass("dx-popup-content")).children().eq(0); this._toggleContentScrollClass(); this.$overlayContent().attr("role", "dialog") } _render() { const isFullscreen = Boolean(this.option("fullScreen")); this._toggleFullScreenClass(isFullscreen); super._render() } _createBodyOverflowManager() { this._bodyOverflowManager = createBodyOverflowManager() } _toggleFullScreenClass(value) { this.$overlayContent().toggleClass("dx-popup-fullscreen", value).toggleClass("dx-popup-normal", !value) } _initTemplates() { super._initTemplates(); this._templateManager.addDefaultTemplates({ title: new EmptyTemplate, bottom: new EmptyTemplate }) } _getActionsList() { return super._getActionsList().concat(["onResizeStart", "onResize", "onResizeEnd"]) } _contentResizeHandler(entry) { if (!this._shouldSkipContentResize(entry)) { this._renderGeometry({ shouldOnlyReposition: true }) } } _isShowAnimationResizing() { const animation = this.option("animation"); return ["to", "from"].some((prop => { var _animation$show; const config = null === animation || void 0 === animation || null === (_animation$show = animation.show) || void 0 === _animation$show ? void 0 : _animation$show[prop]; return isObject(config) && ("width" in config || "height" in config) })) } _updateResizeCallbackSkipCondition() { const isShowAnimationResizing = this._isShowAnimationResizing(); this._shouldSkipContentResize = entry => isShowAnimationResizing && this._showAnimationProcessing || this._areContentDimensionsRendered(entry) } _observeContentResize(shouldObserve) { var _this$_$content2; if (!this.option("useResizeObserver")) { return } const contentElement = null === (_this$_$content2 = this._$content) || void 0 === _this$_$content2 ? void 0 : _this$_$content2.get(0); if (shouldObserve) { resizeObserverSingleton.observe(contentElement, (entry => { this._contentResizeHandler(entry) })) } else { resizeObserverSingleton.unobserve(contentElement) } } _areContentDimensionsRendered(entry) { var _entry$contentBoxSize, _this$_renderedDimens3, _this$_renderedDimens4; const contentBox = null === (_entry$contentBoxSize = entry.contentBoxSize) || void 0 === _entry$contentBoxSize ? void 0 : _entry$contentBoxSize[0]; if (contentBox) { var _this$_renderedDimens, _this$_renderedDimens2; return parseInt(contentBox.inlineSize, 10) === (null === (_this$_renderedDimens = this._renderedDimensions) || void 0 === _this$_renderedDimens ? void 0 : _this$_renderedDimens.width) && parseInt(contentBox.blockSize, 10) === (null === (_this$_renderedDimens2 = this._renderedDimensions) || void 0 === _this$_renderedDimens2 ? void 0 : _this$_renderedDimens2.height) } const { contentRect: contentRect } = entry; return parseInt(contentRect.width, 10) === (null === (_this$_renderedDimens3 = this._renderedDimensions) || void 0 === _this$_renderedDimens3 ? void 0 : _this$_renderedDimens3.width) && parseInt(contentRect.height, 10) === (null === (_this$_renderedDimens4 = this._renderedDimensions) || void 0 === _this$_renderedDimens4 ? void 0 : _this$_renderedDimens4.height) } _renderContent() { super._renderContent(); this._observeContentResize(true) } _processContentRendering() { this._renderTopToolbar(); this._renderBottomToolbar(); this._renderResize(); super._processContentRendering() } _getTopToolbarItems() { const { showTitle: showTitle, title: title } = this.option(); const { ios: isIOS } = devices.current(); const items = this._getToolbarItems("top"); if (showTitle && Boolean(title)) { items.unshift({ location: isIOS ? "center" : "before", text: title }) } return items } _renderTopToolbar() { const { showTitle: showTitle } = this.option(); const items = this._getTopToolbarItems(); const shouldBeShown = showTitle || items.length > 0; if (shouldBeShown) { var _this$_$topToolbar; if (this._$topToolbar) { this._updateToolbarOptions("top", { items: items }) } else { this._renderTopToolbarImpl() } null === (_this$_$topToolbar = this._$topToolbar) || void 0 === _this$_$topToolbar || _this$_$topToolbar.toggleClass("dx-has-close-button", this._hasCloseButton()) } else { var _this$_$topToolbar2; null === (_this$_$topToolbar2 = this._$topToolbar) || void 0 === _this$_$topToolbar2 || _this$_$topToolbar2.remove(); this._$topToolbar = void 0 } this._toggleAriaLabel() } _renderTopToolbarImpl() { var _this$_$topToolbar3; null === (_this$_$topToolbar3 = this._$topToolbar) || void 0 === _this$_$topToolbar3 || _this$_$topToolbar3.remove(); const items = this._getTopToolbarItems(); const $content = this.$content(); if (!$content) { return } const $toolbarContainer = $("<div>").addClass("dx-popup-title").addClass(TOOLBAR_CLASS).insertBefore($content); this._$topToolbar = this._renderToolbar("titleTemplate", items, $toolbarContainer, { onInitialized: e => { this._topToolbar = e.component } }); this._$topToolbar.addClass("dx-popup-title"); this._renderDrag(); this._executeTitleRenderAction(this._$topToolbar) } _renderBottomToolbar() { const items = this._getToolbarItems("bottom"); if (!items.length) { var _this$_$bottomToolbar; null === (_this$_$bottomToolbar = this._$bottomToolbar) || void 0 === _this$_$bottomToolbar || _this$_$bottomToolbar.remove(); this._$bottomToolbar = void 0; return } if (this._$bottomToolbar) { this._updateToolbarOptions("bottom", { items: items }) } else { this._renderBottomToolbarImpl() } this._toggleClasses() } _renderBottomToolbarImpl() { var _this$_$bottomToolbar2; null === (_this$_$bottomToolbar2 = this._$bottomToolbar) || void 0 === _this$_$bottomToolbar2 || _this$_$bottomToolbar2.remove(); const items = this._getToolbarItems("bottom"); const $content = this.$content(); if (!$content) { return } const $toolbarContainer = $("<div>").addClass("dx-popup-bottom").addClass(TOOLBAR_CLASS).insertAfter($content); this._$bottomToolbar = this._renderToolbar("bottomTemplate", items, $toolbarContainer, { compactMode: true, onInitialized: e => { this._bottomToolbar = e.component } }); this._$bottomToolbar.addClass("dx-popup-bottom") } _triggerToolbarResizeEvent() { [this._$topToolbar, this._$bottomToolbar].forEach(($toolbar => { if ($toolbar) { triggerResizeEvent($toolbar); triggerResizeEvent($toolbar) } })) } _renderToolbar(optionName, items, $container) { let additionalToolbarOptions = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : {}; const template = this._getTemplateByOption(optionName); const isEmptyTemplate = template instanceof EmptyTemplate; if (isEmptyTemplate) { return this._renderByPolymorphicTemplate(items, $container, additionalToolbarOptions) } return this._renderByTemplate(template, $container) } _getIntegrationOptions() { const { integrationOptions: integrationOptions } = this.option(); return Object.assign({}, integrationOptions, { skipTemplates: ["content", "title"] }) } _renderByPolymorphicTemplate(items, $container, additionalToolbarOptions) { const { disabled: disabled, rtlEnabled: rtlEnabled, useDefaultToolbarButtons: useDefaultToolbarButtons, useFlatToolbarButtons: useFlatToolbarButtons } = this.option(); const integrationOptions = this._getIntegrationOptions(); const toolbarOptions = extend(additionalToolbarOptions, { disabled: disabled, rtlEnabled: rtlEnabled, items: items, useDefaultButtons: useDefaultToolbarButtons, useFlatButtons: useFlatToolbarButtons, integrationOptions: integrationOptions }); const template = this._getTemplate("dx-polymorph-widget"); template.render({ container: $container, model: { widget: this._getToolbarName(), options: toolbarOptions } }); const $toolbar = $container.children("div"); $container.replaceWith($toolbar); return $toolbar } _renderByTemplate(template, $container) { const $result = $(template.render({ container: getPublicElement($container) })); if ($result.hasClass("dx-template-wrapper")) { $container.replaceWith($result); $container = $result } return $container } _updateToolbarOptions(toolbar, options) { const instance = "top" === toolbar ? this._topToolbar : this._bottomToolbar; if (!instance) { return } const integrationOptions = this._getIntegrationOptions(); instance.option(Object.assign({}, options, { integrationOptions: integrationOptions })) } _toggleAriaLabel() { var _this$_$topToolbar4; const { title: title, showTitle: showTitle } = this.option(); const shouldSetAriaLabel = showTitle && Boolean(title); const titleId = shouldSetAriaLabel ? (new Guid).toString() : null; null === (_this$_$topToolbar4 = this._$topToolbar) || void 0 === _this$_$topToolbar4 || _this$_$topToolbar4.find(".dx-toolbar-label").eq(0).attr("id", titleId); this.$overlayContent().attr("aria-labelledby", titleId) } _animateShowing() { this._triggerToolbarResizeEvent(); super._animateShowing() } _renderVisibilityAnimate(visible) { return super._renderVisibilityAnimate(visible) } _hide() { this._observeContentResize(false); return super._hide() } _executeTitleRenderAction($titleElement) { this._getTitleRenderAction()({ titleElement: getPublicElement($titleElement) }) } _getTitleRenderAction() { return this._titleRenderAction ?? this._createTitleRenderAction() } _createTitleRenderAction() { this._titleRenderAction = this._createActionByOption("onTitleRendered", { element: this.element(), excludeValidators: ["disabled", "readOnly"] }); return this._titleRenderAction } _getCloseButton() { return { toolbar: "top", location: "after", template: this._getCloseButtonRenderer() } } _getCloseButtonRenderer() { return (_, __, container) => { const $button = $("<div>").addClass("dx-closebutton"); this._createComponent($button, Button, { icon: "close", onClick: this._createToolbarItemAction(void 0), stylingMode: "text", integrationOptions: {} }); $(container).append($button) } } _getToolbarItems(toolbar) { const { platform: currentPlatform } = devices.current(); const { toolbarItems: toolbarItems } = this.option(); const toolbarsItems = []; this._toolbarItemClasses = []; let index = 0; each(toolbarItems, ((_, data) => { const isShortcut = isDefined(data.shortcut); const item = isShortcut ? getButtonPlace(data.shortcut) : data; if (isShortcut && "ios" === currentPlatform && index < 2) { item.toolbar = "top"; index++ } item.toolbar = data.toolbar || item.toolbar || "top"; if (item && item.toolbar === toolbar) { if (isShortcut) { extend(item, { location: data.location }, this._getToolbarItemByAlias(data)) } const isLTROrder = "generic" === currentPlatform; if ("done" === data.shortcut && isLTROrder || "cancel" === data.shortcut && !isLTROrder) { toolbarsItems.unshift(item) } else { toolbarsItems.push(item) } } })); if ("top" === toolbar && this._hasCloseButton()) { toolbarsItems.push(this._getCloseButton()) } return toolbarsItems } _hasCloseButton() { const { showCloseButton: showCloseButton, showTitle: showTitle } = this.option(); return showCloseButton && showTitle } _getToolbarButtonStylingMode(shortcut) { if (isFluent(current())) { return "done" === shortcut ? "contained" : "outlined" } return this.option("useFlatToolbarButtons") ? "text" : "contained" } _getToolbarButtonType(shortcut) { if (isFluent(current()) && "done" === shortcut || this.option("useDefaultToolbarButtons")) { return "default" } return "normal" } _getToolbarItemByAlias(data) { const itemType = data.shortcut; if (!ALLOWED_TOOLBAR_ITEM_ALIASES.includes(itemType)) { return false } const itemConfig = extend({ text: messageLocalization.format(getLocalizationKey(itemType)), onClick: this._createToolbarItemAction(data.onClick), integrationOptions: {}, type: this._getToolbarButtonType(itemType), stylingMode: this._getToolbarButtonStylingMode(itemType) }, data.options || {}); const itemClass = `dx-popup-${itemType}`; this._toolbarItemClasses.push(itemClass); return { template: (_, __, container) => { const $toolbarItem = $("<div>").addClass(itemClass).appendTo(container); this._createComponent($toolbarItem, Button, itemConfig) } } } _createToolbarItemAction(clickAction) { return this._createAction(clickAction, { afterExecute(e) { e.component.hide() } }) } _getToolbarName() { return "dxToolbarBase" } _toggleDisabledState(value) { var _this$$content; super._toggleDisabledState(...arguments); null === (_this$$content = this.$content()) || void 0 === _this$$content || _this$$content.toggleClass("dx-state-disabled", Boolean(value)) } _toggleClasses() { const aliases = ALLOWED_TOOLBAR_ITEM_ALIASES; each(aliases, ((_, alias) => { var _this$$wrapper2, _this$_$bottomToolbar3; const className = `dx-popup-${alias}`; const isVisible = this._toolbarItemClasses.includes(className); null === (_this$$wrapper2 = this.$wrapper()) || void 0 === _this$$wrapper2 || _this$$wrapper2.toggleClass(`${className}-visible`, isVisible); null === (_this$_$bottomToolbar3 = this._$bottomToolbar) || void 0 === _this$_$bottomToolbar3 || _this$_$bottomToolbar3.toggleClass(className, isVisible) })) } _toggleFocusClass(isFocused, $element) { super._toggleFocusClass(isFocused, $element); if (isFocused && !zIndexPool.isLastZIndexInStack(this._zIndex)) { var _this$_$wrapper, _this$_$content3; const zIndex = zIndexPool.create(this._zIndexInitValue()); zIndexPool.remove(this._zIndex); this._zIndex = zIndex; null === (_this$_$wrapper = this._$wrapper) || void 0 === _this$_$wrapper || _this$_$wrapper.css("zIndex", zIndex); null === (_this$_$content3 = this._$content) || void 0 === _this$_$content3 || _this$_$content3.css("zIndex", zIndex) } } _toggleContentScrollClass() { var _this$$content2; const isNativeScrollingEnabled = !this.option("preventScrollEvents"); null === (_this$$content2 = this.$content()) || void 0 === _this$$content2 || _this$$content2.toggleClass("dx-popup-content-scrollable", isNativeScrollingEnabled) } _getPositionControllerConfig() { const superConfiguration = super._getPositionControllerConfig(); const { fullScreen: fullScreen, forceApplyBindings: forceApplyBindings, dragOutsideBoundary: dragOutsideBoundary, dragAndResizeArea: dragAndResizeArea, outsideDragFactor: outsideDragFactor } = this.option(); const properties = Object.assign({}, superConfiguration.properties, { fullScreen: fullScreen, forceApplyBindings: forceApplyBindings, dragOutsideBoundary: dragOutsideBoundary, dragAndResizeArea: dragAndResizeArea, outsideDragFactor: outsideDragFactor }); const elements = Object.assign({}, superConfiguration.elements); const configuration = { properties: properties, elements: elements }; return configuration } _initPositionController() { if (this._positionController) { return } this._positionController = new PopupPositionController(this._getPositionControllerConfig()) } _getDragTarget() { return this.topToolbar() } _renderGeometry() { let options = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; const { visible: visible, useResizeObserver: useResizeObserver } = this.option(); const { forceStopAnimation: forceStopAnimation, shouldOnlyReposition: shouldOnlyReposition, isDimensionChange: isDimensionChange } = options; if (visible && windowUtils.hasWindow()) { const isAnimated = this._showAnimationProcessing; const shouldRepeatAnimation = isAnimated && !forceStopAnimation && useResizeObserver; this._isAnimationPaused = shouldRepeatAnimation || void 0; this._stopAnimation(); if (shouldOnlyReposition) { this._renderPosition(false) } else { this._renderGeometryImpl(isDimensionChange) } if (shouldRepeatAnimation) { this._animateShowing(); this._isAnimationPaused = void 0 } } } _cacheDimensions() { if (!this.option("useResizeObserver")) { return } this._renderedDimensions = { width: parseInt(getWidth(this._$content), 10), height: parseInt(getHeight(this._$content), 10) } } _renderGeometryImpl() { let isDimensionChange = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : false; if (!isDimensionChange) { this._resetContentHeight() } super._renderGeometryImpl(); this._cacheDimensions(); this._setContentHeight() } _resetContentHeight() { const height = this._getOptionValue("height"); if ("auto" === height) { var _this$$content3; null === (_this$$content3 = this.$content()) || void 0 === _this$$content3 || _this$$content3.css({ height: "auto", maxHeight: "none" }) } } _renderDrag() { var _this$_$content4; const $dragTarget = this._getDragTarget(); const { dragEnabled: dragEnabled } = this.option(); if (!$dragTarget) { return } const config = { dragEnabled: dragEnabled, handle: $dragTarget.get(0), draggableElement: null === (_this$_$content4 = this._$content) || void 0 === _this$_$content4 ? void 0 : _this$_$content4.get(0), positionController: this._positionController }; if (this._drag) { this._drag.init(config) } else { this._drag = new PopupDrag(config) } this.$overlayContent().toggleClass("dx-popup-draggable", dragEnabled) } _renderResize() { if (!this._$content) { return } this._resizable = this._createComponent(this._$content, Resizable, { handles: this.option("resizeEnabled") ? "all" : "none", onResizeStart: e => { var _this$_actions, _this$_actions$onResi; this._observeContentResize(false); null === (_this$_actions = this._actions) || void 0 === _this$_actions || null === (_this$_actions$onResi = _this$_actions.onResizeStart) || void 0 === _this$_actions$onResi || _this$_actions$onResi.call(_this$_actions, e) }, onResize: e => { var _this$_actions2, _this$_actions2$onRes; this._setContentHeight(); null === (_this$_actions2 = this._actions) || void 0 === _this$_actions2 || null === (_this$_actions2$onRes = _this$_actions2.onResize) || void 0 === _this$_actions2$onRes || _this$_actions2$onRes.call(_this$_actions2, e) }, onResizeEnd: e => { this._resizeEndHandler(e); this._observeContentResize(true) }, minHeight: 100, minWidth: 100, area: this._positionController.$dragResizeContainer, keepAspectRatio: false }) } _resizeEndHandler(e) { var _this$_actions3, _this$_actions3$onRes; const width = this._resizable.option("width"); const height = this._resizable.option("height"); if (width) { this._setOptionWithoutOptionChange("width", width) } if (height) { this._setOptionWithoutOptionChange("height", height) } this._cacheDimensions(); this._positionController.resizeHandled(); this._positionController.detectVisualPositionChange(e.event); null === (_this$_actions3 = this._actions) || void 0 === _this$_actions3 || null === (_this$_actions3$onRes = _this$_actions3.onResizeEnd) || void 0 === _this$_actions3$onRes || _this$_actions3$onRes.call(_this$_actions3, e) } _setContentHeight() { var _this$$content4; const { forceApplyBindings: forceApplyBindings } = this.option(); (forceApplyBindings ?? noop)(); const overlayContent = this.$overlayContent().get(0); const currentHeightStrategyClass = this._chooseHeightStrategy(overlayContent); null === (_this$$content4 = this.$content()) || void 0 === _this$$content4 || _this$$content4.css(this._getHeightCssStyles(currentHeightStrategyClass, overlayContent)); this._setHeightClasses(this.$overlayContent(), currentHeightStrategyClass) } _chooseHeightStrategy(overlayContent) { const isAutoWidth = "auto" === overlayContent.style.width || "" === overlayContent.style.width; let currentHeightStrategyClass = HEIGHT_STRATEGIES.static; if (this._isAutoHeight() && this.option("autoResizeEnabled")) { if (isAutoWidth) { currentHeightStrategyClass = HEIGHT_STRATEGIES.inherit } else { currentHeightStrategyClass = HEIGHT_STRATEGIES.flex } } return currentHeightStrategyClass } _getHeightCssStyles(currentHeightStrategyClass, overlayContent) { let cssStyles = {}; const contentMaxHeight = this._getOptionValue("maxHeight", overlayContent); const contentMinHeight = this._getOptionValue("minHeight", overlayContent); const popupHeightParts = this._splitPopupHeight(); const heightStrategyChangeOffset = getHeightStrategyChangeOffset(currentHeightStrategyClass, popupHeightParts.popupVerticalPaddings); const toolbarsAndVerticalOffsetsHeight = popupHeightParts.header + popupHeightParts.footer + popupHeightParts.contentVerticalOffsets + popupHeightParts.popupVerticalOffsets + heightStrategyChangeOffset; if (currentHeightStrategyClass === HEIGHT_STRATEGIES.static) { if (!this._isAutoHeight() || contentMaxHeight || contentMinHeight) { const overlayHeight = this.option("fullScreen") ? Math.min(getBoundingRect(overlayContent).height, windowUtils.getWindow().innerHeight) : getBoundingRect(overlayContent).height; const contentHeight = overlayHeight - toolbarsAndVerticalOffsetsHeight; cssStyles = { height: Math.max(0, contentHeight), minHeight: "auto", maxHeight: "auto" } } } else { const container = $(this._positionController.$visualContainer).get(0); const maxHeightValue = addOffsetToMaxHeight(contentMaxHeight, -toolbarsAndVerticalOffsetsHeight, container); const minHeightValue = addOffsetToMinHeight(contentMinHeight, -toolbarsAndVerticalOffsetsHeight, container); cssStyles = { height: "auto", minHeight: minHeightValue, maxHeight: maxHeightValue } } return cssStyles } _setHeightClasses($container, currentClass) { let excessClasses = ""; for (const name in HEIGHT_STRATEGIES) { if (HEIGHT_STRATEGIES[name] !== currentClass) { excessClasses += ` ${HEIGHT_STRATEGIES[name]}` } } $container.removeClass(excessClasses).addClass(currentClass) } _isAutoHeight() { return "auto" === this.$overlayContent().get(0).style.height } _splitPopupHeight() { var _this$$content5, _this$$content6; const topToolbar = this.topToolbar(); const bottomToolbar = this.bottomToolbar(); return { header: getVisibleHeight(null === topToolbar || void 0 === topToolbar ? void 0 : topToolbar.get(0)), footer: getVisibleHeight(null === bottomToolbar || void 0 === bottomToolbar ? void 0 : bottomToolbar.get(0)), contentVerticalOffsets: getVerticalOffsets(this.$overlayContent().get(0), true), popupVerticalOffsets: getVerticalOffsets(null === (_this$$content5 = this.$content()) || void 0 === _this$$content5 ? void 0 : _this$$content5.get(0), true), popupVerticalPaddings: getVerticalOffsets(null === (_this$$content6 = this.$content()) || void 0 === _this$$content6 ? void 0 : _this$$content6.get(0), false) } } _isAllWindowCovered() { const { fullScreen: fullScreen } = this.option(); return super._isAllWindowCovered() || Boolean(fullScreen) } _renderDimensions() { if (this.option("fullScreen")) { this.$overlayContent().css({ width: "100%", height: "100%", minWidth: "", maxWidth: "", minHeight: "", maxHeight: "" }) } else { super._renderDimensions() } if (windowUtils.hasWindow()) { this._renderFullscreenWidthClass() } } _dimensionChanged() { this._renderGeometry({ isDimensionChange: true }) } _clean() { super._clean(); this._observeContentResize(false) } _dispose() { super._dispose(); this._toggleBodyScroll(true); this._$topToolbar = null; this._$bottomToolbar = null; this._$popupContent = null } _renderFullscreenWidthClass() { const isFullScreen = getOuterWidth(this.$overlayContent()) === getWidth(window); this.$overlayContent().toggleClass("dx-popup-fullscreen-width", isFullScreen) } _toggleSafariScrolling() { if (!this.option("enableBodyScroll")) { return } super._toggleSafariScrolling() } _toggleBodyScroll(enabled) { if (!this._bodyOverflowManager) { return } const { setOverflow: setOverflow, restoreOverflow: restoreOverflow } = this._bodyOverflowManager; if (enabled) { restoreOverflow() } else { setOverflow() } } refreshPosition() { this._renderPosition() } _optionChanged(args) { var _this$_resizable2; const { value: value, name: name } = args; switch (name) { case "rtlEnabled": case "disabled": { super._optionChanged(args); const options = { [name]: Boolean(value) }; this._updateToolbarOptions("top", options); this._updateToolbarOptions("bottom", options); break } case "animation": this._updateResizeCallbackSkipCondition(); break; case "enableBodyScroll": if (this.option("visible")) { this._toggleBodyScroll(value) } break; case "showTitle": case "title": this._renderTopToolbar(); this._renderGeometry(); triggerResizeEvent(this.$overlayContent()); break; case "titleTemplate": this._renderTopToolbarImpl(); this._renderGeometry(); triggerResizeEvent(this.$overlayContent()); break; case "bottomTemplate": this._renderBottomToolbarImpl(); this._renderGeometry(); triggerResizeEvent(this.$overlayContent()); break; case "container": super._optionChanged(args); if (this.option("resizeEnabled")) { var _this$_resizable; null === (_this$_resizable = this._resizable) || void 0 === _this$_resizable || _this$_resizable.option("area", this._positionController.$dragResizeContainer) } break; case "width": case "height": super._optionChanged(args); null === (_this$_resizable2 = this._resizable) || void 0 === _this$_resizable2 || _this$_resizable2.option(name, value); break; case "onTitleRendered": this._createTitleRenderAction(); break; case "toolbarItems": case "useDefaultToolbarButtons": case "useFlatToolbarButtons": this._renderTopToolbar(); this._renderBottomToolbar(); this._renderGeometry(); this._triggerToolbarResizeEvent(); break; case "dragEnabled": this._renderDrag(); break; case "dragAndResizeArea": this._positionController.dragAndResizeArea = value; if (this.option("resizeEnabled")) { this._resizable.option("area", this._positionController.$dragResizeContainer) } this._positionController.positionContent(); break; case "dragOutsideBoundary": this._positionController.dragOutsideBoundary = value; if (this.option("resizeEnabled")) { this._resizable.option("area", this._positionController.$dragResizeContainer) } break; case "outsideDragFactor": this._positionController.outsideDragFactor = value; break; case "resizeEnabled": this._renderResize(); this._renderGeometry(); break; case "autoResizeEnabled": this._renderGeometry(); triggerResizeEvent(this.$overlayContent()); break; case "fullScreen": this._positionController.fullScreen = value; this._toggleFullScreenClass(Boolean(value)); this._toggleSafariScrolling(); this._renderGeometry(); triggerResizeEvent(this.$overlayContent()); break; case "showCloseButton": this._renderTopToolbar(); break; case "preventScrollEvents": super._optionChanged(args); this._toggleContentScrollClass(); break; default: super._optionChanged(args) } } bottomToolbar() { return this._$bottomToolbar } topToolbar() { return this._$topToolbar } $content() { return this._$popupContent } content() { return getPublicElement(this.$content()) } $overlayContent() { return this._$content } getFocusableElements() { const $wrapper = this.$wrapper(); if (!$wrapper) { return $() } return $wrapper.find("[tabindex]").filter(((_, item) => item.getAttribute("tabindex") >= 0)) } } registerComponent("dxPopup", Popup); export default Popup;