Browse Source

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

Igor Vaynberg 12 years ago
parent
commit
7a006a7259
2 changed files with 52 additions and 22 deletions
  1. 8 0
      select2.css
  2. 44 22
      select2.js

+ 8 - 0
select2.css

@@ -107,6 +107,14 @@ Version: @@ver@@ Timestamp: @@timestamp@@
     cursor: pointer;
     cursor: pointer;
 }
 }
 
 
+.select2-drop-mask {
+    position: absolute;
+    left: 0;
+    top: 0;
+    z-index: 9998;
+    opacity: 0;
+}
+
 .select2-drop {
 .select2-drop {
     width: 100%;
     width: 100%;
     margin-top:-1px;
     margin-top:-1px;

+ 44 - 22
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) {
     $document.bind("mousemove", function (e) {
         lastMousePosition = {x: e.pageX, y: e.pageY};
         lastMousePosition = {x: e.pageX, y: e.pageY};
     });
     });
@@ -553,7 +534,7 @@ the specific language governing permissions and limitations under the Apache Lic
 
 
         // abstract
         // abstract
         init: function (opts) {
         init: function (opts) {
-            var results, search, resultsSelector = ".select2-results";
+            var results, search, resultsSelector = ".select2-results", mask;
 
 
             // prepare options
             // prepare options
             this.opts = opts = this.prepareOpts(opts);
             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
             // cache the body so future lookups are cheap
             this.body = thunk(function() { return opts.element.closest("body"); });
             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) {
             if (opts.element.attr("class") !== undefined) {
                 this.container.addClass(opts.element.attr("class").replace(/validate\[[\S ]+] ?/, ''));
                 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
         // abstract
         opening: function() {
         opening: function() {
-            var cid = this.containerId, selector = this.containerSelector;
+            var cid = this.containerId,
+                scroll = "scroll." + cid,
+                resize = "resize."+cid,
+                mask;
 
 
             this.clearDropdownAlignmentPreference();
             this.clearDropdownAlignmentPreference();
 
 
@@ -1000,16 +993,39 @@ the specific language governing permissions and limitations under the Apache Lic
                 this.dropdown.detach().appendTo(this.body());
                 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
             // move the global id to the correct dropdown
             $("#select2-drop").removeAttr("id");
             $("#select2-drop").removeAttr("id");
             this.dropdown.attr("id", "select2-drop");
             this.dropdown.attr("id", "select2-drop");
 
 
             // show the elements
             // show the elements
+            mask.css({
+                width: document.documentElement.scrollWidth,
+                height: document.documentElement.scrollHeight});
+            mask.show();
             this.dropdown.show();
             this.dropdown.show();
             this.positionDropdown();
             this.positionDropdown();
 
 
             this.dropdown.addClass("select2-drop-active");
             this.dropdown.addClass("select2-drop-active");
             this.ensureHighlightVisible();
             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();
             this.focusSearch();
         },
         },
 
 
@@ -1017,10 +1033,16 @@ the specific language governing permissions and limitations under the Apache Lic
         close: function () {
         close: function () {
             if (!this.opened()) return;
             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();
             this.clearDropdownAlignmentPreference();
 
 
+            $("#select2-drop-mask").hide();
             this.dropdown.removeAttr("id"); // only the active dropdown has the select2-drop id
             this.dropdown.removeAttr("id"); // only the active dropdown has the select2-drop id
             this.dropdown.hide();
             this.dropdown.hide();
             this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active");
             this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active");