ソースを参照

Keyboard navigation in choices (tags)

Niels Kühnel 12 年 前
コミット
877c1d90c5
2 ファイル変更105 行追加16 行削除
  1. 12 1
      select2.css
  2. 93 15
      select2.js

+ 12 - 1
select2.css

@@ -497,6 +497,7 @@ disabled look for disabled choices in the results dropdown
     margin: 0;
     padding: 0;
     white-space: nowrap;
+    position: relative;
 }
 
 .select2-container-multi .select2-choices .select2-search-field input {
@@ -514,6 +515,16 @@ disabled look for disabled choices in the results dropdown
     background: transparent !important;
 }
 
+.select2-container-multi .select2-choices .select2-search-field .carret-hider {
+    position: absolute;
+    background-color: white;
+    top: 0;
+    left: 0;
+    width: 6px;
+    height: 100%;
+    display: none;
+}
+
 .select2-container-multi .select2-choices .select2-search-field input.select2-active {
     background: #fff url('select2-spinner.gif') no-repeat 100% !important;
 }
@@ -651,4 +662,4 @@ disabled look for disabled choices in the results dropdown
   .select2-search input {
       background-position: 100% -21px !important;
   }
-}
+}

+ 93 - 15
select2.js

@@ -262,6 +262,23 @@ the specific language governing permissions and limitations under the Apache Lic
         }, 0);
     }
 
+    function getCursorInfo(el) {
+        el = $(el)[0];
+        var offset = 0;
+        var length = 0;
+        if ('selectionStart' in el) {
+            offset = el.selectionStart;
+            length = el.selectionEnd - offset;
+        } else if ('selection' in document) {
+            el.focus();
+            var sel = document.selection.createRange();
+            length = document.selection.createRange().text.length;
+            sel.moveStart('character', -el.value.length);
+            offset = sel.text.length - length;
+        }
+        return { offset: offset, length: length };
+    }
+
     function killEvent(event) {
         event.preventDefault();
         event.stopPropagation();
@@ -1220,7 +1237,7 @@ the specific language governing permissions and limitations under the Apache Lic
         },
 
         // abstract
-        close: function () {
+        close: function (keepSearchText) {
             if (!this.opened()) return;
 
             var cid = this.containerId,
@@ -1238,7 +1255,10 @@ the specific language governing permissions and limitations under the Apache Lic
             this.dropdown.hide();
             this.container.removeClass("select2-dropdown-open");
             this.results.empty();
-            this.clearSearch();
+
+            if (!keepSearchText) {
+               this.clearSearch();
+            }
             this.search.removeClass("select2-active");
             this.opts.element.trigger($.Event("close"));
         },
@@ -2130,6 +2150,7 @@ the specific language governing permissions and limitations under the Apache Lic
                 "    <ul class='select2-choices'>",
                 //"<li class='select2-search-choice'><span>California</span><a href="javascript:void(0)" class="select2-search-choice-close"></a></li>" ,
                 "  <li class='select2-search-field'>" ,
+                "   <div class='carret-hider'></div>",
                 "    <input type='text' autocomplete='off' class='select2-input'>" ,
                 "  </li>" ,
                 "</ul>" ,
@@ -2184,6 +2205,27 @@ the specific language governing permissions and limitations under the Apache Lic
             return opts;
         },
 
+        selectChoice: function (choice) {
+
+            this.carretHider.css("display", "none");
+
+            var selected = this.container.find(".select2-search-choice-focus");
+            if (selected.length && choice && choice[0] == selected[0]) {
+
+            } else {
+                if (selected.length) {
+                    this.opts.element.trigger("choice-deselected", selected);
+                }
+                selected.removeClass("select2-search-choice-focus");
+                if (choice && choice.length) {
+                    this.close(true);
+                    choice.addClass("select2-search-choice-focus");
+                    this.opts.element.trigger("choice-selected", choice);
+                    this.carretHider.css("display", "block");
+                }
+            }
+        },
+
         // multi
         initContainer: function () {
 
@@ -2191,6 +2233,19 @@ the specific language governing permissions and limitations under the Apache Lic
 
             this.searchContainer = this.container.find(".select2-search-field");
             this.selection = selection = this.container.find(selector);
+            this.carretHider = $(".carret-hider", this.container);
+
+            var _this = this;
+            this.selection.on("mousedown", ".select2-search-choice", function (e) {
+                //killEvent(e);                
+                _this.search[0].focus();
+                _this.selectChoice($(this));
+            })
+            //.sortable({
+            //    items: " > li",
+            //    tolerance: "pointer",
+            //    revert: 100                
+            //});
 
             // rewrite labels from original element to focusser
             this.search.attr("id", "s2id_autogen"+nextUid());
@@ -2209,24 +2264,46 @@ the specific language governing permissions and limitations under the Apache Lic
             this.search.bind("keydown", this.bind(function (e) {
                 if (!this.enabled) return;
 
-                if (e.which === KEY.BACKSPACE && this.search.val() === "") {
-                    this.close();
+                var selected = selection.find(".select2-search-choice-focus");
+                var prev = selected.prev(".select2-search-choice:not(.select2-locked)");
+                var next = selected.next(".select2-search-choice:not(.select2-locked)");
+                var pos = getCursorInfo(this.search);
 
-                    var choices,
-                        selected = selection.find(".select2-search-choice-focus");
-                    if (selected.length > 0) {
+                if (selected.length &&
+                    (e.which == KEY.LEFT || e.which == KEY.RIGHT || e.which == KEY.BACKSPACE || e.which == KEY.DELETE || e.which == KEY.ENTER)) {
+                    var selectedChoice = selected;
+                    if (e.which == KEY.LEFT && prev.length) {
+                        selectedChoice = prev;
+                    }
+                    else if (e.which == KEY.RIGHT) {
+                        selectedChoice = next.length ? next : null;
+                    }
+                    else if (e.which === KEY.BACKSPACE) {
                         this.unselect(selected.first());
                         this.search.width(10);
-                        killEvent(e);
-                        return;
+                        selectedChoice = prev.length ? prev : next;
+                    } else if (e.which == KEY.DELETE) {
+                        this.unselect(selected.first());
+                        this.search.width(10);
+                        selectedChoice = next.length ? next : null;
+                    } else if (e.which == KEY.ENTER) {
+                        selectedChoice = null;
                     }
 
-                    choices = selection.find(".select2-search-choice:not(.select2-locked)");
-                    if (choices.length > 0) {
-                        choices.last().addClass("select2-search-choice-focus");
+                    this.selectChoice(selectedChoice);
+                    killEvent(e);
+                    if (!selectedChoice || !selectedChoice.length) {
+                        this.open();
                     }
+                    return;
+                } else if ((e.which === KEY.BACKSPACE
+                    || e.which == KEY.LEFT) && (pos.offset == 0 && !pos.length)) {
+
+                    this.selectChoice(selection.find(".select2-search-choice:not(.select2-locked)").last());
+                    killEvent(e);
+                    return;
                 } else {
-                    selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
+                    this.selectChoice(null);
                 }
 
                 if (this.opened()) {
@@ -2280,7 +2357,7 @@ the specific language governing permissions and limitations under the Apache Lic
             this.search.bind("blur", this.bind(function(e) {
                 this.container.removeClass("select2-container-active");
                 this.search.removeClass("select2-focused");
-                this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
+                this.selectChoice(null);
                 if (!this.opened()) this.clearSearch();
                 e.stopImmediatePropagation();
             }));
@@ -2291,6 +2368,7 @@ the specific language governing permissions and limitations under the Apache Lic
                     // clicked inside a select2 search choice, do not open
                     return;
                 }
+                this.selectChoice(null);
                 this.clearPlaceholder();
                 this.open();
                 this.focusSearch();
@@ -2898,4 +2976,4 @@ the specific language governing permissions and limitations under the Apache Lic
         }
     };
 
-}(jQuery));
+}(jQuery));