1
0
mirror of synced 2024-11-22 21:16:10 +03:00

Allow the dropdown to point up

Up until now, the container could only have a dropdown that was
displayed below the container. While this worked well, there are
some cases where the dropdown should be displayed above the
container. Most notably, this is when the conatainer is displayed
towards the bottom of the page, and displaying the dropdown would
cause the page to be extended. Because we close the dropdown
when the page is scrolled, the user would not be able to access any
options that were displayed outside of the viewpoint.

Because of the order that events are fired, we attach the handlers
for repositioning the dropdown after results are displayed when the
container is opened for the first time.  This allows it to be
registered after the results container registers their events, so
the dropdown is repositioned after the results have been displayed.

The logic for determining the direction that the dropdown will be
shown in is very similar to the positioning code used in
Select2 3.x. Unlike previous versions of Select2, a class is used
to indicate the direction of the dropdown, even if it is displaying
below the container.

The themes provided with Select2 have been updated to correctly
render the dropdown in both directions.
This commit is contained in:
Kevin Brown 2014-12-05 20:06:20 -05:00
parent fda973c34f
commit ce38cd5b9c
14 changed files with 463 additions and 42 deletions

54
dist/css/select2.css vendored
View File

@ -66,10 +66,17 @@
cursor: pointer; }
.select2-container--open .select2-dropdown {
left: 0; }
.select2-container--open .select2-dropdown--above {
border-bottom: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0; }
.select2-container--open .select2-dropdown--below {
border-top: none;
border-top-left-radius: 0;
border-top-right-radius: 0;
left: 0; }
border-top-right-radius: 0; }
.select2-search--dropdown {
display: block;
@ -143,7 +150,10 @@
margin-right: 2px; }
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
color: #333; }
.select2-container--default.select2-container--open .select2-selection--single, .select2-container--default.select2-container--open .select2-selection--multiple {
.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
border-top-left-radius: 0;
border-top-right-radius: 0; }
.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0; }
.select2-container--default .select2-search--dropdown .select2-search__field {
@ -218,7 +228,23 @@
top: 50%;
width: 0; }
.select2-container--classic.select2-container--open .select2-selection--single {
border: 1px solid #5897fb;
border: 1px solid #5897fb; }
.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow {
background: transparent;
border: none; }
.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b {
border-color: transparent transparent #888 transparent;
border-width: 0 4px 5px 4px; }
.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single {
border-top: none;
border-top-left-radius: 0;
border-top-right-radius: 0;
background-image: -webkit-linear-gradient(top, #ffffff 0%, #eee 50%);
background-image: -o-linear-gradient(top, #ffffff 0%, #eee 50%);
background-image: linear-gradient(to bottom, #ffffff 0%, #eee 50%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eee', GradientType=0); }
.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single {
border-bottom: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
@ -227,12 +253,6 @@
background-image: linear-gradient(to bottom, #eee 50%, #ffffff 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eee', endColorstr='#ffffff', GradientType=0); }
.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow {
background: transparent;
border: none; }
.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b {
border-color: transparent transparent #888 transparent;
border-width: 0 4px 5px 4px; }
.select2-container--classic .select2-selection--multiple {
background-color: white;
border: 1px solid #aaa;
@ -263,7 +283,12 @@
.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover {
color: #555; }
.select2-container--classic.select2-container--open .select2-selection--multiple {
border: 1px solid #5897fb;
border: 1px solid #5897fb; }
.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple {
border-top: none;
border-top-left-radius: 0;
border-top-right-radius: 0; }
.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple {
border-bottom: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0; }
@ -274,6 +299,10 @@
outline: 0; }
.select2-container--classic .select2-dropdown {
background-color: white;
border: 1px solid transparent; }
.select2-container--classic .select2-dropdown--above {
border-bottom: none; }
.select2-container--classic .select2-dropdown--below {
border-top: none; }
.select2-container--classic .select2-results > .select2-results__options {
max-height: 200px;
@ -290,5 +319,4 @@
display: block;
padding: 6px; }
.select2-container--classic.select2-container--open .select2-dropdown {
border: 1px solid #5897fb;
border-top: none; }
border-color: #5897fb; }

File diff suppressed because one or more lines are too long

View File

@ -2857,10 +2857,24 @@ define('select2/dropdown/attachBody',[
AttachBody.prototype.bind = function (decorated, container, $container) {
var self = this;
var setupResultsEvents = false;
decorated.call(this, container, $container);
container.on('open', function () {
self._showDropdown();
if (!setupResultsEvents) {
setupResultsEvents = true;
container.on('results:all', function () {
self._positionDropdown();
});
container.on('results:append', function () {
self._positionDropdown();
});
}
});
container.on('close', function () {
@ -2904,9 +2918,64 @@ define('select2/dropdown/attachBody',[
};
AttachBody.prototype._positionDropdown = function () {
var css = this.$container.offset();
var $window = $(window);
css.top += this.$container.outerHeight(true);
var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');
var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');
var newDirection = null;
var position = this.$container.position();
var offset = this.$container.offset();
offset.bottom = offset.top + this.$container.outerHeight(false);
var container = {
height: this.$container.outerHeight(false)
};
container.top = offset.top;
container.bottom = offset.top + container.height;
var dropdown = {
height: this.$dropdown.outerHeight(false)
};
var viewport = {
top: $window.scrollTop(),
bottom: $window.scrollTop() + $window.height()
};
var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);
var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);
var css = {
left: offset.left,
top: container.bottom
};
if (!isCurrentlyAbove && !isCurrentlyBelow) {
newDirection = 'below';
}
if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {
newDirection = 'above';
} else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {
newDirection = 'below';
}
if (newDirection == 'above' || isCurrentlyAbove) {
css.top = container.top - dropdown.height;
}
if (newDirection != null) {
this.$dropdown
.removeClass('select2-dropdown--below select2-dropdown--above')
.addClass('select2-dropdown--' + newDirection);
this.$container
.removeClass('select2-container--below select2-container--above')
.addClass('select2-container--' + newDirection);
}
this.$dropdownContainer.css(css);
};

View File

@ -2857,10 +2857,24 @@ define('select2/dropdown/attachBody',[
AttachBody.prototype.bind = function (decorated, container, $container) {
var self = this;
var setupResultsEvents = false;
decorated.call(this, container, $container);
container.on('open', function () {
self._showDropdown();
if (!setupResultsEvents) {
setupResultsEvents = true;
container.on('results:all', function () {
self._positionDropdown();
});
container.on('results:append', function () {
self._positionDropdown();
});
}
});
container.on('close', function () {
@ -2904,9 +2918,64 @@ define('select2/dropdown/attachBody',[
};
AttachBody.prototype._positionDropdown = function () {
var css = this.$container.offset();
var $window = $(window);
css.top += this.$container.outerHeight(true);
var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');
var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');
var newDirection = null;
var position = this.$container.position();
var offset = this.$container.offset();
offset.bottom = offset.top + this.$container.outerHeight(false);
var container = {
height: this.$container.outerHeight(false)
};
container.top = offset.top;
container.bottom = offset.top + container.height;
var dropdown = {
height: this.$dropdown.outerHeight(false)
};
var viewport = {
top: $window.scrollTop(),
bottom: $window.scrollTop() + $window.height()
};
var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);
var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);
var css = {
left: offset.left,
top: container.bottom
};
if (!isCurrentlyAbove && !isCurrentlyBelow) {
newDirection = 'below';
}
if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {
newDirection = 'above';
} else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {
newDirection = 'below';
}
if (newDirection == 'above' || isCurrentlyAbove) {
css.top = container.top - dropdown.height;
}
if (newDirection != null) {
this.$dropdown
.removeClass('select2-dropdown--below select2-dropdown--above')
.addClass('select2-dropdown--' + newDirection);
this.$container
.removeClass('select2-container--below select2-container--above')
.addClass('select2-container--' + newDirection);
}
this.$dropdownContainer.css(css);
};

View File

@ -12392,10 +12392,24 @@ define('select2/dropdown/attachBody',[
AttachBody.prototype.bind = function (decorated, container, $container) {
var self = this;
var setupResultsEvents = false;
decorated.call(this, container, $container);
container.on('open', function () {
self._showDropdown();
if (!setupResultsEvents) {
setupResultsEvents = true;
container.on('results:all', function () {
self._positionDropdown();
});
container.on('results:append', function () {
self._positionDropdown();
});
}
});
container.on('close', function () {
@ -12439,9 +12453,64 @@ define('select2/dropdown/attachBody',[
};
AttachBody.prototype._positionDropdown = function () {
var css = this.$container.offset();
var $window = $(window);
css.top += this.$container.outerHeight(true);
var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');
var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');
var newDirection = null;
var position = this.$container.position();
var offset = this.$container.offset();
offset.bottom = offset.top + this.$container.outerHeight(false);
var container = {
height: this.$container.outerHeight(false)
};
container.top = offset.top;
container.bottom = offset.top + container.height;
var dropdown = {
height: this.$dropdown.outerHeight(false)
};
var viewport = {
top: $window.scrollTop(),
bottom: $window.scrollTop() + $window.height()
};
var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);
var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);
var css = {
left: offset.left,
top: container.bottom
};
if (!isCurrentlyAbove && !isCurrentlyBelow) {
newDirection = 'below';
}
if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {
newDirection = 'above';
} else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {
newDirection = 'below';
}
if (newDirection == 'above' || isCurrentlyAbove) {
css.top = container.top - dropdown.height;
}
if (newDirection != null) {
this.$dropdown
.removeClass('select2-dropdown--below select2-dropdown--above')
.addClass('select2-dropdown--' + newDirection);
this.$container
.removeClass('select2-container--below select2-container--above')
.addClass('select2-container--' + newDirection);
}
this.$dropdownContainer.css(css);
};

File diff suppressed because one or more lines are too long

73
dist/js/select2.js vendored
View File

@ -3285,10 +3285,24 @@ define('select2/dropdown/attachBody',[
AttachBody.prototype.bind = function (decorated, container, $container) {
var self = this;
var setupResultsEvents = false;
decorated.call(this, container, $container);
container.on('open', function () {
self._showDropdown();
if (!setupResultsEvents) {
setupResultsEvents = true;
container.on('results:all', function () {
self._positionDropdown();
});
container.on('results:append', function () {
self._positionDropdown();
});
}
});
container.on('close', function () {
@ -3332,9 +3346,64 @@ define('select2/dropdown/attachBody',[
};
AttachBody.prototype._positionDropdown = function () {
var css = this.$container.offset();
var $window = $(window);
css.top += this.$container.outerHeight(true);
var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');
var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');
var newDirection = null;
var position = this.$container.position();
var offset = this.$container.offset();
offset.bottom = offset.top + this.$container.outerHeight(false);
var container = {
height: this.$container.outerHeight(false)
};
container.top = offset.top;
container.bottom = offset.top + container.height;
var dropdown = {
height: this.$dropdown.outerHeight(false)
};
var viewport = {
top: $window.scrollTop(),
bottom: $window.scrollTop() + $window.height()
};
var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);
var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);
var css = {
left: offset.left,
top: container.bottom
};
if (!isCurrentlyAbove && !isCurrentlyBelow) {
newDirection = 'below';
}
if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {
newDirection = 'above';
} else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {
newDirection = 'below';
}
if (newDirection == 'above' || isCurrentlyAbove) {
css.top = container.top - dropdown.height;
}
if (newDirection != null) {
this.$dropdown
.removeClass('select2-dropdown--below select2-dropdown--above')
.addClass('select2-dropdown--' + newDirection);
this.$container
.removeClass('select2-container--below select2-container--above')
.addClass('select2-container--' + newDirection);
}
this.$dropdownContainer.css(css);
};

File diff suppressed because one or more lines are too long

View File

@ -8,10 +8,24 @@ define([
AttachBody.prototype.bind = function (decorated, container, $container) {
var self = this;
var setupResultsEvents = false;
decorated.call(this, container, $container);
container.on('open', function () {
self._showDropdown();
if (!setupResultsEvents) {
setupResultsEvents = true;
container.on('results:all', function () {
self._positionDropdown();
});
container.on('results:append', function () {
self._positionDropdown();
});
}
});
container.on('close', function () {
@ -55,9 +69,64 @@ define([
};
AttachBody.prototype._positionDropdown = function () {
var css = this.$container.offset();
var $window = $(window);
css.top += this.$container.outerHeight(true);
var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');
var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');
var newDirection = null;
var position = this.$container.position();
var offset = this.$container.offset();
offset.bottom = offset.top + this.$container.outerHeight(false);
var container = {
height: this.$container.outerHeight(false)
};
container.top = offset.top;
container.bottom = offset.top + container.height;
var dropdown = {
height: this.$dropdown.outerHeight(false)
};
var viewport = {
top: $window.scrollTop(),
bottom: $window.scrollTop() + $window.height()
};
var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);
var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);
var css = {
left: offset.left,
top: container.bottom
};
if (!isCurrentlyAbove && !isCurrentlyBelow) {
newDirection = 'below';
}
if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {
newDirection = 'above';
} else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {
newDirection = 'below';
}
if (newDirection == 'above' || isCurrentlyAbove) {
css.top = container.top - dropdown.height;
}
if (newDirection != null) {
this.$dropdown
.removeClass('select2-dropdown--below select2-dropdown--above')
.addClass('select2-dropdown--' + newDirection);
this.$container
.removeClass('select2-container--below select2-container--above')
.addClass('select2-container--' + newDirection);
}
this.$dropdownContainer.css(css);
};

View File

@ -38,11 +38,19 @@
}
.select2-container--open .select2-dropdown {
left: 0;
}
.select2-container--open .select2-dropdown--above {
border-bottom: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.select2-container--open .select2-dropdown--below {
border-top: none;
border-top-left-radius: 0;
border-top-right-radius: 0;
left: 0;
}
.select2-search--dropdown {

View File

@ -51,9 +51,21 @@
&.select2-container--open {
.select2-selection--multiple {
border: 1px solid $focus-border-color;
}
&.select2-container--above {
.select2-selection--multiple {
border-top: none;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
}
&.select2-container--below {
.select2-selection--multiple {
border-bottom: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
}
}

View File

@ -70,12 +70,6 @@
.select2-selection--single {
border: 1px solid $focus-border-color;
border-bottom: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
@include gradient-vertical($selection-opened-bg-top-color, $selection-opened-bg-bottom-color, 50%, 100%);
.select2-selection__arrow {
background: transparent;
@ -87,4 +81,24 @@
}
}
}
&.select2-container--above {
.select2-selection--single {
border-top: none;
border-top-left-radius: 0;
border-top-right-radius: 0;
@include gradient-vertical($selection-opened-bg-bottom-color, $selection-opened-bg-top-color, 0%, 50%);
}
}
&.select2-container--below {
.select2-selection--single {
border-bottom: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
@include gradient-vertical($selection-opened-bg-top-color, $selection-opened-bg-bottom-color, 50%, 100%);
}
}
}

View File

@ -20,6 +20,14 @@
.select2-dropdown {
background-color: $dropdown-bg-color;
border: 1px solid transparent;
}
.select2-dropdown--above {
border-bottom: none;
}
.select2-dropdown--below {
border-top: none;
}
@ -50,7 +58,6 @@
}
&.select2-container--open .select2-dropdown {
border: 1px solid $focus-border-color;
border-top: none;
border-color: $focus-border-color;
}
}

View File

@ -2,7 +2,14 @@
@import "single";
@import "multiple";
&.select2-container--open {
&.select2-container--open.select2-container--above {
.select2-selection--single, .select2-selection--multiple {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
}
&.select2-container--open.select2-container--below {
.select2-selection--single, .select2-selection--multiple {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;