From e260860789db87c68ed2889895c76a22e94dbce1 Mon Sep 17 00:00:00 2001 From: Kevin Brown Date: Fri, 1 Jan 2016 17:09:43 -0500 Subject: [PATCH] Correct positioning issues for statically positioned elements There was a commit that landed in 4.0.1 that fixed positioning for non-static elements, which are commonly used for the custom `dropdownParent` option, but broke positioning for statically positioned elements, commonly used in almost every other case. That commit was https://github.com/select2/select2/commit/c9216b4b966653dd63a67e815b47899ef5325298 This fixes the positioning issues caused by that commit by properly calculating the offsets for statically positioned parents. Statically positioned parents are unique, because the offset for the dropdown must be calculated based on the closest element that is non-statically positioned. Otherwise, the offset for any statically positioned parent other than the body will be considerably higher than it should be, resulting in the dropdown being offset by a large amount. The offset parent for the body element is the html element, which is why this works for both the body element and any custom parents for the dropdown. This would not be needed if the parent wasn't customizable (as seen in Select2 3.x) because you will never need to offset the body element if it is statically positioned, because the html element almost never has an offset. This also fixes JSHint issues within the tests added in the last commit. This closes https://github.com/select2/select2/issues/3970 This closes https://github.com/select2/select2/issues/3639 --- src/js/select2/dropdown/attachBody.js | 16 +++++++++++----- tests/dropdown/positioning-tests.js | 14 ++++++++++++-- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/js/select2/dropdown/attachBody.js b/src/js/select2/dropdown/attachBody.js index 667596df..a1b62dc8 100644 --- a/src/js/select2/dropdown/attachBody.js +++ b/src/js/select2/dropdown/attachBody.js @@ -157,14 +157,20 @@ define([ top: container.bottom }; - // Fix positioning with static parents - if (this.$dropdownParent[0].style.position !== 'static') { - var parentOffset = this.$dropdownParent.offset(); + // Determine what the parent element is to use for calciulating the offset + var $offsetParent = this.$dropdownParent; - css.top -= parentOffset.top; - css.left -= parentOffset.left; + // For statically positoned elements, we need to get the element + // that is determining the offset + if ($offsetParent.css('position') === 'static') { + $offsetParent = $offsetParent.offsetParent(); } + var parentOffset = $offsetParent.offset(); + + css.top -= parentOffset.top; + css.left -= parentOffset.left; + if (!isCurrentlyAbove && !isCurrentlyBelow) { newDirection = 'below'; } diff --git a/tests/dropdown/positioning-tests.js b/tests/dropdown/positioning-tests.js index cb4d0788..98ff5f18 100644 --- a/tests/dropdown/positioning-tests.js +++ b/tests/dropdown/positioning-tests.js @@ -61,7 +61,12 @@ test('appends to the dropdown parent', function (assert) { test('dropdown is positioned with static margins', function (assert) { var $ = require('jquery'); var $select = $(''); - var $parent = $('
'); + var $parent = $('
'); + $parent.css({ + position: 'static', + marginTop: '5px', + marginLeft: '10px' + }); var $container = $(''); var container = new MockContainer(); @@ -111,7 +116,12 @@ test('dropdown is positioned with static margins', function (assert) { test('dropdown is positioned with absolute offsets', function (assert) { var $ = require('jquery'); var $select = $(''); - var $parent = $('
'); + var $parent = $('
'); + $parent.css({ + position: 'absolute', + top: '10px', + left: '5px' + }); var $container = $(''); var container = new MockContainer();