Skip to content

Commit 877c1d9

Browse files
committed
Keyboard navigation in choices (tags)
1 parent 36f6f67 commit 877c1d9

2 files changed

Lines changed: 105 additions & 16 deletions

File tree

select2.css

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,7 @@ disabled look for disabled choices in the results dropdown
497497
margin: 0;
498498
padding: 0;
499499
white-space: nowrap;
500+
position: relative;
500501
}
501502

502503
.select2-container-multi .select2-choices .select2-search-field input {
@@ -514,6 +515,16 @@ disabled look for disabled choices in the results dropdown
514515
background: transparent !important;
515516
}
516517

518+
.select2-container-multi .select2-choices .select2-search-field .carret-hider {
519+
position: absolute;
520+
background-color: white;
521+
top: 0;
522+
left: 0;
523+
width: 6px;
524+
height: 100%;
525+
display: none;
526+
}
527+
517528
.select2-container-multi .select2-choices .select2-search-field input.select2-active {
518529
background: #fff url('select2-spinner.gif') no-repeat 100% !important;
519530
}
@@ -651,4 +662,4 @@ disabled look for disabled choices in the results dropdown
651662
.select2-search input {
652663
background-position: 100% -21px !important;
653664
}
654-
}
665+
}

select2.js

Lines changed: 93 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,23 @@ the specific language governing permissions and limitations under the Apache Lic
262262
}, 0);
263263
}
264264

265+
function getCursorInfo(el) {
266+
el = $(el)[0];
267+
var offset = 0;
268+
var length = 0;
269+
if ('selectionStart' in el) {
270+
offset = el.selectionStart;
271+
length = el.selectionEnd - offset;
272+
} else if ('selection' in document) {
273+
el.focus();
274+
var sel = document.selection.createRange();
275+
length = document.selection.createRange().text.length;
276+
sel.moveStart('character', -el.value.length);
277+
offset = sel.text.length - length;
278+
}
279+
return { offset: offset, length: length };
280+
}
281+
265282
function killEvent(event) {
266283
event.preventDefault();
267284
event.stopPropagation();
@@ -1220,7 +1237,7 @@ the specific language governing permissions and limitations under the Apache Lic
12201237
},
12211238

12221239
// abstract
1223-
close: function () {
1240+
close: function (keepSearchText) {
12241241
if (!this.opened()) return;
12251242

12261243
var cid = this.containerId,
@@ -1238,7 +1255,10 @@ the specific language governing permissions and limitations under the Apache Lic
12381255
this.dropdown.hide();
12391256
this.container.removeClass("select2-dropdown-open");
12401257
this.results.empty();
1241-
this.clearSearch();
1258+
1259+
if (!keepSearchText) {
1260+
this.clearSearch();
1261+
}
12421262
this.search.removeClass("select2-active");
12431263
this.opts.element.trigger($.Event("close"));
12441264
},
@@ -2130,6 +2150,7 @@ the specific language governing permissions and limitations under the Apache Lic
21302150
" <ul class='select2-choices'>",
21312151
//"<li class='select2-search-choice'><span>California</span><a href="javascript:void(0)" class="select2-search-choice-close"></a></li>" ,
21322152
" <li class='select2-search-field'>" ,
2153+
" <div class='carret-hider'></div>",
21332154
" <input type='text' autocomplete='off' class='select2-input'>" ,
21342155
" </li>" ,
21352156
"</ul>" ,
@@ -2184,13 +2205,47 @@ the specific language governing permissions and limitations under the Apache Lic
21842205
return opts;
21852206
},
21862207

2208+
selectChoice: function (choice) {
2209+
2210+
this.carretHider.css("display", "none");
2211+
2212+
var selected = this.container.find(".select2-search-choice-focus");
2213+
if (selected.length && choice && choice[0] == selected[0]) {
2214+
2215+
} else {
2216+
if (selected.length) {
2217+
this.opts.element.trigger("choice-deselected", selected);
2218+
}
2219+
selected.removeClass("select2-search-choice-focus");
2220+
if (choice && choice.length) {
2221+
this.close(true);
2222+
choice.addClass("select2-search-choice-focus");
2223+
this.opts.element.trigger("choice-selected", choice);
2224+
this.carretHider.css("display", "block");
2225+
}
2226+
}
2227+
},
2228+
21872229
// multi
21882230
initContainer: function () {
21892231

21902232
var selector = ".select2-choices", selection;
21912233

21922234
this.searchContainer = this.container.find(".select2-search-field");
21932235
this.selection = selection = this.container.find(selector);
2236+
this.carretHider = $(".carret-hider", this.container);
2237+
2238+
var _this = this;
2239+
this.selection.on("mousedown", ".select2-search-choice", function (e) {
2240+
//killEvent(e);
2241+
_this.search[0].focus();
2242+
_this.selectChoice($(this));
2243+
})
2244+
//.sortable({
2245+
// items: " > li",
2246+
// tolerance: "pointer",
2247+
// revert: 100
2248+
//});
21942249

21952250
// rewrite labels from original element to focusser
21962251
this.search.attr("id", "s2id_autogen"+nextUid());
@@ -2209,24 +2264,46 @@ the specific language governing permissions and limitations under the Apache Lic
22092264
this.search.bind("keydown", this.bind(function (e) {
22102265
if (!this.enabled) return;
22112266

2212-
if (e.which === KEY.BACKSPACE && this.search.val() === "") {
2213-
this.close();
2267+
var selected = selection.find(".select2-search-choice-focus");
2268+
var prev = selected.prev(".select2-search-choice:not(.select2-locked)");
2269+
var next = selected.next(".select2-search-choice:not(.select2-locked)");
2270+
var pos = getCursorInfo(this.search);
22142271

2215-
var choices,
2216-
selected = selection.find(".select2-search-choice-focus");
2217-
if (selected.length > 0) {
2272+
if (selected.length &&
2273+
(e.which == KEY.LEFT || e.which == KEY.RIGHT || e.which == KEY.BACKSPACE || e.which == KEY.DELETE || e.which == KEY.ENTER)) {
2274+
var selectedChoice = selected;
2275+
if (e.which == KEY.LEFT && prev.length) {
2276+
selectedChoice = prev;
2277+
}
2278+
else if (e.which == KEY.RIGHT) {
2279+
selectedChoice = next.length ? next : null;
2280+
}
2281+
else if (e.which === KEY.BACKSPACE) {
22182282
this.unselect(selected.first());
22192283
this.search.width(10);
2220-
killEvent(e);
2221-
return;
2284+
selectedChoice = prev.length ? prev : next;
2285+
} else if (e.which == KEY.DELETE) {
2286+
this.unselect(selected.first());
2287+
this.search.width(10);
2288+
selectedChoice = next.length ? next : null;
2289+
} else if (e.which == KEY.ENTER) {
2290+
selectedChoice = null;
22222291
}
22232292

2224-
choices = selection.find(".select2-search-choice:not(.select2-locked)");
2225-
if (choices.length > 0) {
2226-
choices.last().addClass("select2-search-choice-focus");
2293+
this.selectChoice(selectedChoice);
2294+
killEvent(e);
2295+
if (!selectedChoice || !selectedChoice.length) {
2296+
this.open();
22272297
}
2298+
return;
2299+
} else if ((e.which === KEY.BACKSPACE
2300+
|| e.which == KEY.LEFT) && (pos.offset == 0 && !pos.length)) {
2301+
2302+
this.selectChoice(selection.find(".select2-search-choice:not(.select2-locked)").last());
2303+
killEvent(e);
2304+
return;
22282305
} else {
2229-
selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
2306+
this.selectChoice(null);
22302307
}
22312308

22322309
if (this.opened()) {
@@ -2280,7 +2357,7 @@ the specific language governing permissions and limitations under the Apache Lic
22802357
this.search.bind("blur", this.bind(function(e) {
22812358
this.container.removeClass("select2-container-active");
22822359
this.search.removeClass("select2-focused");
2283-
this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
2360+
this.selectChoice(null);
22842361
if (!this.opened()) this.clearSearch();
22852362
e.stopImmediatePropagation();
22862363
}));
@@ -2291,6 +2368,7 @@ the specific language governing permissions and limitations under the Apache Lic
22912368
// clicked inside a select2 search choice, do not open
22922369
return;
22932370
}
2371+
this.selectChoice(null);
22942372
this.clearPlaceholder();
22952373
this.open();
22962374
this.focusSearch();
@@ -2898,4 +2976,4 @@ the specific language governing permissions and limitations under the Apache Lic
28982976
}
28992977
};
29002978

2901-
}(jQuery));
2979+
}(jQuery));

0 commit comments

Comments
 (0)