diff --git a/src/definitions/modules/modal.js b/src/definitions/modules/modal.js index bc2ae995e3..6b1d55c05c 100755 --- a/src/definitions/modules/modal.js +++ b/src/definitions/modules/modal.js @@ -94,6 +94,7 @@ id, observer, observeAttributes = false, + resizeObserver, module ; module = { @@ -246,6 +247,9 @@ if (observer) { observer.disconnect(); } + if (resizeObserver) { + resizeObserver.disconnect(); + } module.verbose('Destroying previous modal'); $module .removeData(moduleNamespace) @@ -263,6 +267,13 @@ observeChanges: function () { if ('MutationObserver' in window) { + if ('ResizeObserver' in window && settings.observeChanges) { + resizeObserver = new ResizeObserver(function (entries) { + module.refresh(); + }); + resizeObserver.observe(element); + module.debug('Setting up resize observer', resizeObserver); + } observer = new MutationObserver(function (mutations) { var collectNodes = function (parent) { var nodes = []; @@ -299,7 +310,7 @@ return !shouldRefreshInputs; }); - if (shouldRefresh && settings.observeChanges) { + if (!resizeObserver && shouldRefresh && settings.observeChanges) { module.debug('DOM tree modified, refreshing'); module.refresh(); } @@ -319,12 +330,15 @@ refresh: function () { module.remove.scrolling(); - module.cacheSizes(); - if (!module.can.useFlex()) { - module.set.modalOffset(); + if ($module.css('display') !== 'none') { + module.cacheSizes(); + if (!module.can.useFlex()) { + module.set.modalOffset(); + } + module.set.screenHeight(); + module.set.dimmerHeight(); + module.set.type(); } - module.set.screenHeight(); - module.set.type(); }, refreshModals: function () { @@ -601,7 +615,7 @@ } hadScrollbar = module.has.scrollbar(); module.showDimmer(); - module.cacheSizes(); + module.cacheSizes(true); if (hadScrollbar) { module.set.bodyMargin(); } @@ -729,7 +743,8 @@ if ($dimmable.dimmer('is animating') || !$dimmable.dimmer('is active')) { if (hadScrollbar) { if (!isBody) { - $dimmer.css('top', $dimmable.scrollTop()); + $dimmer.css('top', settings.detachable ? $dimmable.scrollTop() : 0); + module.set.dimmerHeight(); } module.save.bodyMargin(); } @@ -749,6 +764,7 @@ } module.remove.clickaway(); module.remove.screenHeight(); + module.remove.dimmerHeight(); }); } else { module.debug('Dimmer is not visible cannot hide'); @@ -881,6 +897,12 @@ $context.removeAttr('style'); } }, + dimmerStyle: function () { + if ($dimmer.attr('style') === '') { + module.verbose('Removing dimmer style attribute'); + $dimmer.removeAttr('style'); + } + }, screenHeight: function () { module.debug('Removing page height'); $context @@ -888,6 +910,15 @@ ; module.remove.bodyStyle(); }, + dimmerHeight: function () { + module.debug('Removing dimmer height'); + $dimmer.css({ + top: '', + height: '', + maxHeight: '', + }); + module.remove.dimmerStyle(); + }, keyboardShortcuts: function () { module.verbose('Removing keyboard shortcuts'); $document @@ -902,12 +933,14 @@ }, }, - cacheSizes: function () { + cacheSizes: function (getScrollingMargins) { $module.addClass(className.loading); var scrollHeight = $module.prop('scrollHeight'), modalWidth = $module.outerWidth(), - modalHeight = $module.outerHeight() + modalHeight = $module.outerHeight(), + scrollingTop = 0, + bottomMargin = 0 ; if (module.cache.pageHeight === undefined || modalHeight !== 0) { $.extend(module.cache, { @@ -921,6 +954,18 @@ }); module.cache.topOffset = -(module.cache.height / 2); } + if (getScrollingMargins) { + if (module.can.useFlex()) { + $module.addClass(className.scrolling); + scrollingTop = parseInt($module.css('top').replace(/[^\d.]/g, ''), 10) || 0; + bottomMargin = parseInt(window.getComputedStyle($module[0], '::after').height.replace(/[^\d.]/g, ''), 10) || 0; + $module.removeClass(className.scrolling); + } + $.extend(module.cache, { + scrollingTop: scrollingTop, + bottomMargin: bottomMargin, + }); + } $module.removeClass(className.loading); module.debug('Caching modal and container sizes', module.cache); }, @@ -980,7 +1025,8 @@ contextHeight = module.cache.contextHeight, verticalCenter = module.cache.contextHeight / 2, topOffset = module.cache.topOffset, - scrollHeight = module.cache.scrollHeight, + scrollingTop = module.cache.scrollingTop || 0, + scrollHeight = module.cache.scrollHeight - (module.cache.bottomMargin || 0), height = module.cache.height, paddingHeight = settings.padding, startPosition = verticalCenter + topOffset @@ -988,7 +1034,7 @@ return scrollHeight > height ? startPosition + scrollHeight + paddingHeight < contextHeight - : height + (paddingHeight * 2) < contextHeight; + : height + (paddingHeight * 2) - scrollingTop < contextHeight; }, }, has: { @@ -1140,14 +1186,15 @@ }, modalOffset: function () { if (!settings.detachable) { - var canFit = module.can.fit(); + var canFit = module.can.fit(), + scrollTop = (isBody ? $document : $context).scrollTop(); $module .css({ top: !$module.hasClass('aligned') && canFit - ? $document.scrollTop() + (module.cache.contextHeight - module.cache.height) / 2 + ? scrollTop + (module.cache.contextHeight - module.cache.height) / 2 : (!canFit || $module.hasClass('top') - ? $document.scrollTop() + settings.padding - : $document.scrollTop() + (module.cache.contextHeight - module.cache.height - settings.padding)), + ? scrollTop + settings.padding + : scrollTop + (module.cache.contextHeight - module.cache.height - settings.padding)), marginLeft: -(module.cache.width / 2), }) ; @@ -1164,13 +1211,24 @@ module.verbose('Setting modal offset for legacy mode'); }, screenHeight: function () { - if (module.can.fit()) { - $context.css('height', ''); - } else if (!$module.hasClass('bottom')) { - module.debug('Modal is taller than page content, resizing page height'); - $context - .css('height', module.cache.height + (settings.padding * 2) + 'px') - ; + if (!isBody && !settings.detachable) { + if (module.can.fit() || hadScrollbar) { + $context.css('height', ''); + } else if (!$module.hasClass('bottom')) { + module.debug('Modal is taller than page content, resizing page height'); + $context + .css('height', module.cache.height + (settings.padding * 2) + 'px') + ; + } + } + }, + dimmerHeight: function () { + if (!isBody && !settings.detachable) { + var contextHeight = $context.prop('scrollHeight'); + $dimmer.css({ + height: contextHeight, + maxHeight: contextHeight, + }); } }, active: function () { diff --git a/src/definitions/modules/modal.less b/src/definitions/modules/modal.less index 274fc6d36a..09d7dd8990 100755 --- a/src/definitions/modules/modal.less +++ b/src/definitions/modules/modal.less @@ -227,6 +227,7 @@ opacity: @closeOpacityDimmed; } } + .undetached.dimmable.dimmed > .ui.modal:not(.fullscreen) > .close:not(.inside), .ui.dimmer > .ui.modal:not(.fullscreen) > .close:not(.inside) { text-shadow: @closeShadow; } @@ -447,6 +448,11 @@ overflow: auto; overscroll-behavior: @overscrollBehavior; } + @supports selector(:has(.f)) { + .modals.dimmer:has(.scrollable) { + scrollbar-gutter: stable; + } + } .modals.dimmer .ui.scrolling.modal.fullscreen { top: 0; } @@ -455,12 +461,17 @@ top: @scrollingTop; } - /* Fix for Firefox, Edge, IE11 */ - .modals.dimmer .ui.scrolling.modal:not([class*="overlay fullscreen"])::after { + .modals.dimmer .ui.modal:not([class*="overlay fullscreen"])::after { content: "\00A0"; position: absolute; + height: 0; + } + .modals.dimmer .ui.scrolling.modal:not([class*="overlay fullscreen"])::after { height: @scrollingMargin; } + .dimmable.dimmed > .modals.dimmer { + overflow: auto; + } /* Undetached Scrolling */ .scrolling.undetached.dimmable.dimmed {