From bb8c3d9a62c783d6e7f416056c382d41c607d256 Mon Sep 17 00:00:00 2001 From: EugeniyKiyashko Date: Thu, 28 Dec 2023 15:58:00 +0400 Subject: [PATCH] Popup: the styles for body overflow should not be changed if showing, hiding is prevented (#26367) --- .../devextreme/js/ui/overlay/ui.overlay.js | 5 +- packages/devextreme/js/ui/popup/ui.popup.js | 4 +- .../tests/editors/overlays/scrolling.ts | 4 +- .../overlaysStyleRecalculations.tests.js | 4 +- .../DevExpress.ui.widgets/popup.tests.js | 137 ++++++++++++++++++ 5 files changed, 148 insertions(+), 6 deletions(-) diff --git a/packages/devextreme/js/ui/overlay/ui.overlay.js b/packages/devextreme/js/ui/overlay/ui.overlay.js index 3b22e13a2750..81f8b600b25b 100644 --- a/packages/devextreme/js/ui/overlay/ui.overlay.js +++ b/packages/devextreme/js/ui/overlay/ui.overlay.js @@ -486,9 +486,8 @@ const Overlay = Widget.inherit({ this._showingDeferred.reject(); } else { const show = () => { - this._toggleBodyScroll(this.option('enableBodyScroll')); - this._stopAnimation(); + this._toggleBodyScroll(this.option('enableBodyScroll')); this._toggleVisibility(true); this._$content.css('visibility', 'hidden'); this._$content.toggleClass(INVISIBLE_STATE_CLASS, false); @@ -505,6 +504,7 @@ const Overlay = Widget.inherit({ this._$content.toggleClass(INVISIBLE_STATE_CLASS, true); this._isShowingActionCanceled = true; this._moveFromContainer(); + this._toggleBodyScroll(true); this.option('visible', false); this._showingDeferred.resolve(); }; @@ -593,6 +593,7 @@ const Overlay = Widget.inherit({ const cancelHide = () => { this._isHidingActionCanceled = true; + this._toggleBodyScroll(this.option('enableBodyScroll')); this.option('visible', true); this._hidingDeferred.resolve(); }; diff --git a/packages/devextreme/js/ui/popup/ui.popup.js b/packages/devextreme/js/ui/popup/ui.popup.js index a111b9491252..ac3c111aed5f 100644 --- a/packages/devextreme/js/ui/popup/ui.popup.js +++ b/packages/devextreme/js/ui/popup/ui.popup.js @@ -964,7 +964,9 @@ const Popup = Overlay.inherit({ this._updateResizeCallbackSkipCondition(); break; case 'enableBodyScroll': - this._toggleBodyScroll(value); + if(this.option('visible')) { + this._toggleBodyScroll(value); + } break; case 'showTitle': case 'title': diff --git a/packages/devextreme/testing/testcafe/tests/editors/overlays/scrolling.ts b/packages/devextreme/testing/testcafe/tests/editors/overlays/scrolling.ts index 7d0d8d53ebfd..209a29bd2297 100644 --- a/packages/devextreme/testing/testcafe/tests/editors/overlays/scrolling.ts +++ b/packages/devextreme/testing/testcafe/tests/editors/overlays/scrolling.ts @@ -1,6 +1,6 @@ /* eslint-disable no-multi-str */ import { ClientFunction } from 'testcafe'; -import { isMaterial } from '../../../helpers/themeUtils'; +import { isMaterialBased } from '../../../helpers/themeUtils'; import url from '../../../helpers/getPageUrl'; import createWidget from '../../../helpers/createWidget'; import { @@ -17,7 +17,7 @@ const POPUP_CONTENT_CLASS = 'dx-popup-content'; fixture`Popup scrolling` .page(url(__dirname, '../../container.html')); -if (!isMaterial()) { +if (!isMaterialBased()) { [false, true].forEach((shading) => { [false, true].forEach((enableBodyScroll) => { [false, true].forEach((fullScreen) => { diff --git a/packages/devextreme/testing/tests/DevExpress.performance/overlaysStyleRecalculations.tests.js b/packages/devextreme/testing/tests/DevExpress.performance/overlaysStyleRecalculations.tests.js index b9a7547d51ac..ba690583970c 100644 --- a/packages/devextreme/testing/tests/DevExpress.performance/overlaysStyleRecalculations.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.performance/overlaysStyleRecalculations.tests.js @@ -95,7 +95,9 @@ QUnit.performanceTest('dxOverlay should not force relayout on creation', functio popup.show(); }; - assert.measureStyleRecalculation(measureFunction, shading ? 16 : 15); + const expectedRecalculationsCount = shading ? 16 : 15; + + assert.measureStyleRecalculation(measureFunction, expectedRecalculationsCount); } finally { $additionalElement.remove(); } diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets/popup.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets/popup.tests.js index 3df53be0072e..dc1d17980834 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets/popup.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets/popup.tests.js @@ -1529,6 +1529,143 @@ QUnit.module('options changed callbacks', { assert.strictEqual(this.getBodyStyle('paddingRight'), '', 'body padding right style'); }); + QUnit.test('the styles for body overflow should not be changed if showing is prevented, enableBodyScroll is true', function(assert) { + window.scrollTo(200, 200); + + assert.strictEqual(this.getBodyStyleAttr(), null, 'body style attribute'); + + const popup = this.createPopup({ + visible: false, + onShowing(e) { + e.cancel = true; + }, + enableBodyScroll: true, + }); + + assert.strictEqual(this.getBodyStyleAttr(), null, 'body style attribute'); + + popup.show(); + + assert.strictEqual(popup.option('visible'), false, 'popup is hidden'); + assert.strictEqual(this.getBodyStyleAttr(), null, 'body style attribute'); + }); + + QUnit.test('the styles for body overflow should not be changed if hiding is prevented, enableBodyScroll is true', function(assert) { + window.scrollTo(200, 200); + + assert.strictEqual(this.getBodyStyleAttr(), null, 'body style attribute'); + + const popup = this.createPopup({ + visible: true, + onHiding(e) { + e.cancel = true; + }, + enableBodyScroll: true, + }); + + assert.strictEqual(this.getBodyStyleAttr(), null, 'body style attribute'); + + popup.hide(); + + assert.strictEqual(popup.option('visible'), true, 'popup is visible'); + assert.strictEqual(this.getBodyStyleAttr(), null, 'body style attribute'); + }); + + QUnit.test('the styles for body overflow should not be changed if showing is prevented, enableBodyScroll is false', function(assert) { + window.scrollTo(200, 200); + + assert.strictEqual(this.getBodyStyleAttr(), null, 'body style attribute'); + + const popup = this.createPopup({ + visible: false, + onShowing(e) { + e.cancel = true; + }, + enableBodyScroll: false, + }); + + assert.strictEqual(this.getBodyStyleAttr(), null, 'body style attribute'); + + popup.show(); + + assert.strictEqual(popup.option('visible'), false, 'popup is hidden'); + assert.strictEqual(this.getBodyStyleAttr(), '', 'body style attribute'); + assert.strictEqual(this.getBodyStyle('overflow'), '', 'body overflow style'); + assert.strictEqual(this.getBodyStyle('paddingRight'), '', 'body padding right style'); + }); + + QUnit.test('the styles for body overflow should not be changed if hiding is prevented, enableBodyScroll is false', function(assert) { + window.scrollTo(200, 200); + + assert.strictEqual(this.getBodyStyleAttr(), null, 'body style attribute'); + + const popup = this.createPopup({ + visible: true, + onHiding(e) { + e.cancel = true; + }, + enableBodyScroll: false, + }); + + assert.strictEqual(this.getBodyStyleAttr(), this.scrollbarWidth ? `padding-right: ${this.scrollbarWidth}px; overflow: hidden;` : 'overflow: hidden;', 'body style attribute'); + assert.strictEqual(this.getBodyStyle('overflow'), 'hidden', 'body overflow style'); + assert.strictEqual(this.getBodyStyle('paddingRight'), this.scrollbarWidth ? `${this.scrollbarWidth}px` : '', 'body padding right style'); + + popup.hide(); + + assert.strictEqual(popup.option('visible'), true, 'popup is visible'); + assert.strictEqual(this.getBodyStyleAttr(), this.scrollbarWidth ? `padding-right: ${this.scrollbarWidth}px; overflow: hidden;` : 'overflow: hidden;', 'body style attribute'); + assert.strictEqual(this.getBodyStyle('overflow'), 'hidden', 'body overflow style'); + assert.strictEqual(this.getBodyStyle('paddingRight'), this.scrollbarWidth ? `${this.scrollbarWidth}px` : '', 'body padding right style'); + }); + + QUnit.test('the styles for body overflow should not be changed if enableBodyScroll is changed in runtime when popup is hidden', function(assert) { + window.scrollTo(200, 200); + + assert.strictEqual(this.getBodyStyleAttr(), null, 'body style attribute'); + + const popup = this.createPopup({ + visible: false, + enableBodyScroll: true, + }); + + assert.strictEqual(this.getBodyStyleAttr(), null, 'body style attribute'); + + popup.option('enableBodyScroll', false); + + assert.strictEqual(this.getBodyStyleAttr(), null, 'body style attribute'); + }); + + QUnit.test('the styles for body overflow should be changed if enableBodyScroll is changed in runtime when popup is visible', function(assert) { + window.scrollTo(200, 200); + + assert.strictEqual(this.getBodyStyleAttr(), null, 'body style attribute'); + + const popup = this.createPopup({ + visible: true, + enableBodyScroll: false, + }); + + assert.strictEqual(popup.option('visible'), true, 'popup is visible'); + assert.strictEqual(this.getBodyStyleAttr(), this.scrollbarWidth ? `padding-right: ${this.scrollbarWidth}px; overflow: hidden;` : 'overflow: hidden;', 'body style attribute'); + assert.strictEqual(this.getBodyStyle('overflow'), 'hidden', 'body overflow style'); + assert.strictEqual(this.getBodyStyle('paddingRight'), this.scrollbarWidth ? `${this.scrollbarWidth}px` : '', 'body padding right style'); + + popup.option('enableBodyScroll', true); + + assert.strictEqual(popup.option('visible'), true, 'popup is visible'); + assert.strictEqual(this.getBodyStyleAttr(), '', 'body style attribute'); + assert.strictEqual(this.getBodyStyle('overflow'), '', 'body overflow style'); + assert.strictEqual(this.getBodyStyle('paddingRight'), '', 'body padding right style'); + + popup.option('enableBodyScroll', false); + + assert.strictEqual(popup.option('visible'), true, 'popup is visible'); + assert.strictEqual(this.getBodyStyleAttr(), this.scrollbarWidth ? `padding-right: ${this.scrollbarWidth}px; overflow: hidden;` : 'overflow: hidden;', 'body style attribute'); + assert.strictEqual(this.getBodyStyle('overflow'), 'hidden', 'body overflow style'); + assert.strictEqual(this.getBodyStyle('paddingRight'), this.scrollbarWidth ? `${this.scrollbarWidth}px` : '', 'body padding right style'); + }); + ['overflow', 'overflowX', 'overflowY'].forEach((overflow) => { QUnit.test(`body with ${overflow} inline style should have overflow styles after showing and restore them after hidden, enableBodyScroll is false`, function(assert) { window.scrollTo(200, 200);