diff --git a/select2.css b/select2.css index caaac939..a81ad5fa 100644 --- a/select2.css +++ b/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; } -} +} \ No newline at end of file diff --git a/select2.js b/select2.js index 04af1cfa..554c3ed3 100644 --- a/select2.js +++ b/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 " " , @@ -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)); \ No newline at end of file