From 482cc409ea27fc3cdf1028e9202c1ca7ada01e35 Mon Sep 17 00:00:00 2001 From: Igor Vaynberg Date: Wed, 11 Jul 2012 12:33:38 +0300 Subject: [PATCH] dropdown can now open above or below control depending on available screens pace. fixes #120. based on #197 --- select2.css | 34 ++++++++++++++++++++++++++++++++++ select2.js | 53 +++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/select2.css b/select2.css index cd2116cb..d533c69e 100755 --- a/select2.css +++ b/select2.css @@ -54,6 +54,21 @@ Version: @@ver@@ Timestamp: @@timestamp@@ text-decoration: none; } +.select2-container.select2-drop-above .select2-choice +{ + border-bottom-color: #aaa; + -webkit-border-radius:0px 0px 4px 4px; + -moz-border-radius:0px 0px 4px 4px; + border-radius:0px 0px 4px 4px; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(0.9, white)); + background-image: -webkit-linear-gradient(center bottom, #eeeeee 0%, white 90%); + background-image: -moz-linear-gradient(center bottom, #eeeeee 0%, white 90%); + background-image: -o-linear-gradient(bottom, #eeeeee 0%, white 90%); + background-image: -ms-linear-gradient(top, #eeeeee 0%,#ffffff 90%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#ffffff',GradientType=0 ); + background-image: linear-gradient(top, #eeeeee 0%,#ffffff 90%); +} + .select2-container .select2-choice span { margin-right: 26px; display: block; @@ -102,6 +117,20 @@ Version: @@ver@@ Timestamp: @@timestamp@@ border-radius: 0 0 4px 4px; } +.select2-drop.select2-drop-above { + -webkit-border-radius: 4px 4px 0px 0px; + -moz-border-radius: 4px 4px 0px 0px; + border-radius: 4px 4px 0px 0px; + margin-top:1px; + border-top: 1px solid #aaa; + border-bottom: 0; + + -webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); + -moz-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); + -o-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); + box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); +} + .select2-container .select2-choice div { -webkit-border-radius: 0 4px 4px 0; -moz-border-radius: 0 4px 4px 0; @@ -175,6 +204,11 @@ Version: @@ver@@ Timestamp: @@timestamp@@ -webkit-border-radius: 0; } +.select2-drop.select2-drop-above .select2-search input +{ + margin-top:4px; +} + .select2-search input.select2-active { background: #fff url('spinner.gif') no-repeat 100%; background: url('spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); diff --git a/select2.js b/select2.js index b86a3742..8984aee5 100755 --- a/select2.js +++ b/select2.js @@ -728,11 +728,40 @@ positionDropdown: function() { var offset = this.container.offset(), height = this.container.outerHeight(), - width = this.container.outerWidth(), - css = { - top: offset.top + height, - left: offset.left, - width: width + width = this.container.outerWidth(), + dropHeight = this.dropdown.outerHeight(), + viewportBottom = document.body.scrollTop + document.documentElement.clientHeight, + dropTop = offset.top + height, + enoughRoomBelow = dropTop + dropHeight <= viewportBottom, + enoughRoomAbove = (offset.top - dropHeight) >= document.body.scrollTop, + aboveNow = this.dropdown.hasClass("select2-drop-above"), + above, + css; + + // always prefer the current above/below alignment, unless there is not enough room + + if (aboveNow) { + above = true; + if (!enoughRoomAbove && enoughRoomBelow) above = false; + } else { + above = false; + if (!enoughRoomBelow && enoughRoomAbove) above = true; + } + + if (above) { + dropTop = offset.top - dropHeight; + this.container.addClass("select2-drop-above"); + this.dropdown.addClass("select2-drop-above"); + } + else { + this.container.removeClass("select2-drop-above"); + this.dropdown.removeClass("select2-drop-above"); + } + + css = { + top:dropTop, + left:offset.left, + width:width }; this.dropdown.css(css); @@ -749,6 +778,13 @@ return !event.isDefaultPrevented(); }, + // abstract + clearDropdownAlignmentPreference: function() { + // clear the classes used to figure out the preference of where the dropdown should be opened + this.container.removeClass("select2-drop-above"); + this.dropdown.removeClass("select2-drop-above"); + }, + /** * Opens the dropdown * @@ -760,6 +796,8 @@ if (!this.shouldOpen()) return false; + this.clearDropdownAlignmentPreference(); + if (this.search.val() === " ") { this.search.val(""); } this.container.addClass("select2-dropdown-open").addClass("select2-container-active"); @@ -784,6 +822,8 @@ close: function () { if (!this.opened()) return; + this.clearDropdownAlignmentPreference(); + this.dropdown.hide(); this.container.removeClass("select2-dropdown-open"); this.results.empty(); @@ -1575,7 +1615,8 @@ // multi open: function () { if (this.parent.open.apply(this, arguments) === false) return false; - this.clearPlaceholder(); + + this.clearPlaceholder(); this.resizeSearch(); this.focusSearch(); return true;