From a14451deb3b8368de76aad6e728b27032bf8097a Mon Sep 17 00:00:00 2001 From: Ilias Date: Sun, 2 Apr 2017 14:26:25 +0300 Subject: [PATCH] Fix #18373: properly adjust padding-right of body and fixed elements when opening or closing modal --- js/src/modal.js | 54 ++++++++++++++---- js/tests/unit/modal.js | 123 +++++++++++++++++++++++++++++++---------- 2 files changed, 138 insertions(+), 39 deletions(-) diff --git a/js/src/modal.js b/js/src/modal.js index 5e99414449..779b9a402f 100644 --- a/js/src/modal.js +++ b/js/src/modal.js @@ -67,7 +67,8 @@ const Modal = (($) => { DIALOG : '.modal-dialog', DATA_TOGGLE : '[data-toggle="modal"]', DATA_DISMISS : '[data-dismiss="modal"]', - FIXED_CONTENT : '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top' + FIXED_CONTENT : '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top', + NAVBAR_TOGGLER : '.navbar-toggler' } @@ -212,7 +213,6 @@ const Modal = (($) => { this._isShown = null this._isBodyOverflowing = null this._ignoreBackdropClick = null - this._originalBodyPadding = null this._scrollbarWidth = null } @@ -429,21 +429,53 @@ const Modal = (($) => { } _setScrollbar() { - const bodyPadding = parseInt( - $(Selector.FIXED_CONTENT).css('padding-right') || 0, - 10 - ) + if (this._isBodyOverflowing) { + // Note: DOMNode.style.paddingRight returns the actual value or '' if not set + // while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set + + // Adjust fixed content padding + $(Selector.FIXED_CONTENT).each((index, element) => { + const actualPadding = $(element)[0].style.paddingRight + const calculatedPadding = $(element).css('padding-right') + $(element).data('padding-right', actualPadding).css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`) + }) - this._originalBodyPadding = document.body.style.paddingRight || '' + // Adjust navbar-toggler margin + $(Selector.NAVBAR_TOGGLER).each((index, element) => { + const actualMargin = $(element)[0].style.marginRight + const calculatedMargin = $(element).css('margin-right') + $(element).data('margin-right', actualMargin).css('margin-right', `${parseFloat(calculatedMargin) + this._scrollbarWidth}px`) + }) - if (this._isBodyOverflowing) { - document.body.style.paddingRight = - `${bodyPadding + this._scrollbarWidth}px` + // Adjust body padding + const actualPadding = document.body.style.paddingRight + const calculatedPadding = $('body').css('padding-right') + $('body').data('padding-right', actualPadding).css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`) } } _resetScrollbar() { - document.body.style.paddingRight = this._originalBodyPadding + // Restore fixed content padding + $(Selector.FIXED_CONTENT).each((index, element) => { + const padding = $(element).data('padding-right') + if (typeof padding !== 'undefined') { + $(element).css('padding-right', padding).removeData('padding-right') + } + }) + + // Restore navbar-toggler margin + $(Selector.NAVBAR_TOGGLER).each((index, element) => { + const margin = $(element).data('margin-right') + if (typeof margin !== 'undefined') { + $(element).css('margin-right', margin).removeData('margin-right') + } + }) + + // Restore body padding + const padding = $('body').data('padding-right') + if (typeof padding !== 'undefined') { + $('body').css('padding-right', padding).removeData('padding-right') + } } _getScrollbarWidth() { // thx d.walsh diff --git a/js/tests/unit/modal.js b/js/tests/unit/modal.js index 84492cec2c..2c3e422306 100644 --- a/js/tests/unit/modal.js +++ b/js/tests/unit/modal.js @@ -9,6 +9,10 @@ $(function () { }) QUnit.module('modal', { + before: function () { + // Enable the scrollbar measurer + $('').appendTo('head') + }, beforeEach: function () { // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode $.fn.bootstrapModal = $.fn.modal.noConflict() @@ -336,81 +340,144 @@ $(function () { $toggleBtn.trigger('click') }) - QUnit.test('should restore inline body padding after closing', function (assert) { + QUnit.test('should adjust the inline body padding when opening and restore when closing', function (assert) { assert.expect(2) var done = assert.async() - var originalBodyPad = 0 var $body = $(document.body) - - $body.css('padding-right', originalBodyPad) + var originalPadding = $body.css('padding-right') $('