Sfoglia il codice sorgente

reworked how dropdown is managed in singleselect so the search field has focus even when the dropdown is not opened and can capture te first keypress. fixes #196

Igor Vaynberg 13 anni fa
parent
commit
1605a631e5
1 ha cambiato i file con 76 aggiunte e 63 eliminazioni
  1. 76 63
      select2.js

+ 76 - 63
select2.js

@@ -806,26 +806,34 @@
 
             if (!this.shouldOpen()) return false;
 
+            window.setTimeout(this.bind(this.opening), 1);
+
+            return true;
+        },
+
+        /**
+         * Performs the opening of the dropdown
+         */
+        // abstract
+        opening: function() {
             this.clearDropdownAlignmentPreference();
 
             if (this.search.val() === " ") { this.search.val(""); }
 
-            this.container.addClass("select2-dropdown-open").addClass("select2-container-active");
-            if(this.dropdown[0] !== this.body.children().last()[0]) {
-				// ensure the dropdown is the last child of body, so the z-index is always respected correctly
-                this.dropdown.detach().appendTo(this.body);
-            }
-
             this.dropdown.addClass("select2-drop-active");
 
             this.positionDropdown();
 
             this.updateResults(true);
+
+            if(this.dropdown[0] !== this.body.children().last()[0]) {
+                this.dropdown.detach().appendTo(this.body);
+            }
+
             this.dropdown.show();
             this.ensureHighlightVisible();
             this.focusSearch();
-
-            return true;
+            this.container.addClass("select2-dropdown-open").addClass("select2-container-active");
         },
 
         // abstract
@@ -1132,11 +1140,11 @@
                 "class": "select2-container",
                 "style": "width: " + this.getContainerWidth()
             }).html([
-                "    <a href='javascript:void(0)' class='select2-choice'><input type='text' class='select2-offscreen select2-focusser'/>",
+                "    <a href='javascript:void(0)' class='select2-choice'>",
                 "   <span></span><abbr class='select2-search-choice-close' style='display:none;'></abbr>",
                 "   <div><b></b></div>" ,
                 "</a>",
-                "    <div class='select2-drop' style='display:none;'>" ,
+                "    <div class='select2-drop select2-offscreen'>" ,
                 "   <div class='select2-search'>" ,
                 "       <input type='text' autocomplete='off' class='select2-input'/>" ,
                 "   </div>" ,
@@ -1145,16 +1153,23 @@
                 "</div>"].join(""));
         },
 
+        // single
+        opening: function () {
+            this.parent.opening.apply(this, arguments);
+            this.dropdown.removeClass("select2-offscreen");
+        },
+
         // single
         close: function () {
             if (!this.opened()) return;
             this.parent.close.apply(this, arguments);
+            this.dropdown.removeAttr("style").addClass("select2-offscreen").insertAfter(this.selection).show();
         },
 
         // single
         focus: function () {
             this.close();
-            this.selection.focus();
+            this.search.focus();
         },
 
         // single
@@ -1165,7 +1180,7 @@
         // single
         cancel: function () {
             this.parent.cancel.apply(this, arguments);
-            this.selection.focus();
+            this.search.focus();
         },
 
         // single
@@ -1174,65 +1189,66 @@
             var selection,
                 container = this.container,
                 dropdown = this.dropdown,
-                containers = $([this.container.get(0), this.dropdown.get(0)]),
-                clickingInside = false,
-                selector = ".select2-choice",
-                focusser=container.find("input.select2-focusser");
+                clickingInside = false;
 
-            this.selection = selection = container.find(selector);
+            this.selection = selection = container.find(".select2-choice");
 
             this.search.bind("keydown", this.bind(function (e) {
-                switch (e.which) {
-                case KEY.UP:
-                case KEY.DOWN:
-                    this.moveHighlight((e.which === KEY.UP) ? -1 : 1);
-                    killEvent(e);
-                    return;
-                case KEY.TAB:
-                case KEY.ENTER:
-                    this.selectHighlighted();
-                    killEvent(e);
-                    return;
-                case KEY.ESC:
-                    this.cancel(e);
+                if (!this.enabled) return;
+
+                if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN || e.which === KEY.SPACE) {
+                    // prevent the page from scrolling
                     killEvent(e);
                     return;
                 }
+
+                if (this.opened()) {
+                    switch (e.which) {
+                        case KEY.UP:
+                        case KEY.DOWN:
+                            this.moveHighlight((e.which === KEY.UP) ? -1 : 1);
+                            killEvent(e);
+                            return;
+                        case KEY.TAB:
+                        case KEY.ENTER:
+                            this.selectHighlighted();
+                            killEvent(e);
+                            return;
+                        case KEY.ESC:
+                            this.cancel(e);
+                            killEvent(e);
+                            return;
+                    }
+                } else {
+                    if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) {
+                        return;
+                    }
+
+                    this.open();
+
+                    if (e.which === KEY.ENTER) {
+                        // do not propagate the event otherwise we open, and propagate enter which closes
+                        killEvent(e);
+                        return;
+                    }
+                }
             }));
 
-            containers.delegate(selector, "click", this.bind(function (e) {
+            selection.bind("click", this.bind(function (e) {
                 clickingInside = true;
 
                 if (this.opened()) {
                     this.close();
-                    selection.focus();
+                    this.search.focus();
                 } else if (this.enabled) {
                     this.open();
                 }
-                e.preventDefault();
+                killEvent(e);
 
                 clickingInside = false;
             }));
-            containers.delegate(selector, "keydown", this.bind(function (e) {
-                if (!this.enabled || e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) {
-                    return;
-                }
-                this.open();
-                if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN || e.which === KEY.SPACE) {
-                    // prevent the page from scrolling
-                    killEvent(e);
-                }
-                if (e.which === KEY.ENTER) {
-                    // do not propagate the event otherwise we open, and propagate enter which closes
-                    killEvent(e);
-                }
-            }));
-            containers.delegate(selector, "focus", function () { if (this.enabled) { containers.addClass("select2-container-active"); dropdown.addClass("select2-drop-active"); }});
-            containers.delegate(selector, "blur", this.bind(function (e) {
-                if (clickingInside) return;
-                if (e.target===focusser.get(0)) return; // ignore blurs from focusser
-                if (!this.opened()) { this.blur(); }
-            }));
+
+            dropdown.bind("click", this.bind(function() { this.search.focus(); }));
 
             selection.delegate("abbr", "click", this.bind(function (e) {
                 if (!this.enabled) return;
@@ -1240,18 +1256,16 @@
                 killEvent(e);
                 this.close();
                 this.triggerChange();
-                selection.focus();
+                this.search.focus();
             }));
 
+            selection.bind("focus", this.bind(function() { this.search.focus(); }));
+
             this.setPlaceholder();
 
-            focusser.bind("focus", function() { selection.focus(); });
-            selection.bind("focus", this.bind(function() {
-                focusser.hide();
+            this.search.bind("focus", this.bind(function() {
                 this.container.addClass("select2-container-active");
             }));
-            selection.bind("blur", function() { focusser.show(); });
-            this.opts.element.bind("open", function() { focusser.hide(); });
         },
 
         clear: function() {
@@ -1358,7 +1372,7 @@
             this.opts.element.val(this.id(data));
             this.updateSelection(data);
             this.close();
-            this.selection.focus();
+            this.search.focus();
 
             if (!equal(old, this.id(data))) { this.triggerChange(); }
         },
@@ -1623,13 +1637,12 @@
         },
 
         // multi
-        open: function () {
-            if (this.parent.open.apply(this, arguments) === false) return false;
+        opening: function () {
+            this.parent.opening.apply(this, arguments);
 
             this.clearPlaceholder();
 			this.resizeSearch();
             this.focusSearch();
-            return true;
         },
 
         // multi