From 7a006a7259d5ececeab3c336de9de22d9f750d09 Mon Sep 17 00:00:00 2001 From: Igor Vaynberg Date: Thu, 31 Jan 2013 10:52:18 -0800 Subject: [PATCH] fix scroll event handling since it doesnt bubble. also add a shim behind the dropdown, this allows it to properly close even when used inside modals. sometimes modals will place their own shim that closes the modal and aborts the default mousedown event. in such cases the modal would close but the dropdown element would still float on the screen now detached and the only way to close it would be to make a selection --- select2.css | 8 +++++++ select2.js | 66 +++++++++++++++++++++++++++++++++++------------------ 2 files changed, 52 insertions(+), 22 deletions(-) diff --git a/select2.css b/select2.css index b1a9628b..a99e72a1 100644 --- a/select2.css +++ b/select2.css @@ -107,6 +107,14 @@ Version: @@ver@@ Timestamp: @@timestamp@@ cursor: pointer; } +.select2-drop-mask { + position: absolute; + left: 0; + top: 0; + z-index: 9998; + opacity: 0; +} + .select2-drop { width: 100%; margin-top:-1px; diff --git a/select2.js b/select2.js index b4f6d2cc..34f1685c 100644 --- a/select2.js +++ b/select2.js @@ -150,25 +150,6 @@ the specific language governing permissions and limitations under the Apache Lic }); } - - $(window).bind("resize", function(e) { - var dropdown=$("#select2-drop"); - if (dropdown.length>0) { - // there is an open dropdown - - // adjust dropdown positioning so it sizes with the content - dropdown.data("select2").positionDropdown(); - } - }).delegate("*", "scroll", function(e) { - var dropdown=$("#select2-drop"); - if (dropdown.length>0) { - // there is an open dropdown - - // adjust dropdown positioning so it scrolls with the content - dropdown.data("select2").positionDropdown(); - } - }); - $document.bind("mousemove", function (e) { lastMousePosition = {x: e.pageX, y: e.pageY}; }); @@ -553,7 +534,7 @@ the specific language governing permissions and limitations under the Apache Lic // abstract init: function (opts) { - var results, search, resultsSelector = ".select2-results"; + var results, search, resultsSelector = ".select2-results", mask; // prepare options this.opts = opts = this.prepareOpts(opts); @@ -576,6 +557,15 @@ the specific language governing permissions and limitations under the Apache Lic // cache the body so future lookups are cheap this.body = thunk(function() { return opts.element.closest("body"); }); + // create the dropdown mask if doesnt already exist + mask = $("#select2-drop-mask"); + if (mask.length == 0) { + mask = $(document.createElement("div")); + mask.attr("id","select2-drop-mask").attr("class","select2-drop-mask"); + mask.hide(); + mask.appendTo(this.body()); + } + if (opts.element.attr("class") !== undefined) { this.container.addClass(opts.element.attr("class").replace(/validate\[[\S ]+] ?/, '')); } @@ -986,7 +976,10 @@ the specific language governing permissions and limitations under the Apache Lic */ // abstract opening: function() { - var cid = this.containerId, selector = this.containerSelector; + var cid = this.containerId, + scroll = "scroll." + cid, + resize = "resize."+cid, + mask; this.clearDropdownAlignmentPreference(); @@ -1000,16 +993,39 @@ the specific language governing permissions and limitations under the Apache Lic this.dropdown.detach().appendTo(this.body()); } + mask = $("#select2-drop-mask"); + + // ensure the mask is always right before the dropdown + if (this.dropdown.prev()[0] !== mask[0]) { + this.dropdown.before(mask); + } + // move the global id to the correct dropdown $("#select2-drop").removeAttr("id"); this.dropdown.attr("id", "select2-drop"); // show the elements + mask.css({ + width: document.documentElement.scrollWidth, + height: document.documentElement.scrollHeight}); + mask.show(); this.dropdown.show(); this.positionDropdown(); this.dropdown.addClass("select2-drop-active"); this.ensureHighlightVisible(); + + // attach listeners to events that can change the position of the container and thus require + // the position of the dropdown to be updated as well so it does not come unglued from the container + this.container.parents().add(window).each(function () { + $(this).bind(resize+" "+scroll, function (e) { + $("#select2-drop-mask").css({ + width:document.documentElement.scrollWidth, + height:document.documentElement.scrollHeight}); + $("#select2-drop").data("select2").positionDropdown(); + }); + }); + this.focusSearch(); }, @@ -1017,10 +1033,16 @@ the specific language governing permissions and limitations under the Apache Lic close: function () { if (!this.opened()) return; - var self = this; + var cid = this.containerId, + scroll = "scroll." + cid, + resize = "resize."+cid; + + // unbind event listeners + this.container.parents().add(window).each(function () { $(this).unbind(scroll).unbind(resize); }); this.clearDropdownAlignmentPreference(); + $("#select2-drop-mask").hide(); this.dropdown.removeAttr("id"); // only the active dropdown has the select2-drop id this.dropdown.hide(); this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active");