Skip to content

Commit 1605a63

Browse files
committed
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 select2#196
1 parent 06ec20d commit 1605a63

1 file changed

Lines changed: 76 additions & 63 deletions

File tree

select2.js

Lines changed: 76 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -806,26 +806,34 @@
806806

807807
if (!this.shouldOpen()) return false;
808808

809+
window.setTimeout(this.bind(this.opening), 1);
810+
811+
return true;
812+
},
813+
814+
/**
815+
* Performs the opening of the dropdown
816+
*/
817+
// abstract
818+
opening: function() {
809819
this.clearDropdownAlignmentPreference();
810820

811821
if (this.search.val() === " ") { this.search.val(""); }
812822

813-
this.container.addClass("select2-dropdown-open").addClass("select2-container-active");
814-
if(this.dropdown[0] !== this.body.children().last()[0]) {
815-
// ensure the dropdown is the last child of body, so the z-index is always respected correctly
816-
this.dropdown.detach().appendTo(this.body);
817-
}
818-
819823
this.dropdown.addClass("select2-drop-active");
820824

821825
this.positionDropdown();
822826

823827
this.updateResults(true);
828+
829+
if(this.dropdown[0] !== this.body.children().last()[0]) {
830+
this.dropdown.detach().appendTo(this.body);
831+
}
832+
824833
this.dropdown.show();
825834
this.ensureHighlightVisible();
826835
this.focusSearch();
827-
828-
return true;
836+
this.container.addClass("select2-dropdown-open").addClass("select2-container-active");
829837
},
830838

831839
// abstract
@@ -1132,11 +1140,11 @@
11321140
"class": "select2-container",
11331141
"style": "width: " + this.getContainerWidth()
11341142
}).html([
1135-
" <a href='javascript:void(0)' class='select2-choice'><input type='text' class='select2-offscreen select2-focusser'/>",
1143+
" <a href='javascript:void(0)' class='select2-choice'>",
11361144
" <span></span><abbr class='select2-search-choice-close' style='display:none;'></abbr>",
11371145
" <div><b></b></div>" ,
11381146
"</a>",
1139-
" <div class='select2-drop' style='display:none;'>" ,
1147+
" <div class='select2-drop select2-offscreen'>" ,
11401148
" <div class='select2-search'>" ,
11411149
" <input type='text' autocomplete='off' class='select2-input'/>" ,
11421150
" </div>" ,
@@ -1145,16 +1153,23 @@
11451153
"</div>"].join(""));
11461154
},
11471155

1156+
// single
1157+
opening: function () {
1158+
this.parent.opening.apply(this, arguments);
1159+
this.dropdown.removeClass("select2-offscreen");
1160+
},
1161+
11481162
// single
11491163
close: function () {
11501164
if (!this.opened()) return;
11511165
this.parent.close.apply(this, arguments);
1166+
this.dropdown.removeAttr("style").addClass("select2-offscreen").insertAfter(this.selection).show();
11521167
},
11531168

11541169
// single
11551170
focus: function () {
11561171
this.close();
1157-
this.selection.focus();
1172+
this.search.focus();
11581173
},
11591174

11601175
// single
@@ -1165,7 +1180,7 @@
11651180
// single
11661181
cancel: function () {
11671182
this.parent.cancel.apply(this, arguments);
1168-
this.selection.focus();
1183+
this.search.focus();
11691184
},
11701185

11711186
// single
@@ -1174,84 +1189,83 @@
11741189
var selection,
11751190
container = this.container,
11761191
dropdown = this.dropdown,
1177-
containers = $([this.container.get(0), this.dropdown.get(0)]),
1178-
clickingInside = false,
1179-
selector = ".select2-choice",
1180-
focusser=container.find("input.select2-focusser");
1192+
clickingInside = false;
11811193

1182-
this.selection = selection = container.find(selector);
1194+
this.selection = selection = container.find(".select2-choice");
11831195

11841196
this.search.bind("keydown", this.bind(function (e) {
1185-
switch (e.which) {
1186-
case KEY.UP:
1187-
case KEY.DOWN:
1188-
this.moveHighlight((e.which === KEY.UP) ? -1 : 1);
1189-
killEvent(e);
1190-
return;
1191-
case KEY.TAB:
1192-
case KEY.ENTER:
1193-
this.selectHighlighted();
1194-
killEvent(e);
1195-
return;
1196-
case KEY.ESC:
1197-
this.cancel(e);
1197+
if (!this.enabled) return;
1198+
1199+
if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN || e.which === KEY.SPACE) {
1200+
// prevent the page from scrolling
11981201
killEvent(e);
11991202
return;
12001203
}
1204+
1205+
if (this.opened()) {
1206+
switch (e.which) {
1207+
case KEY.UP:
1208+
case KEY.DOWN:
1209+
this.moveHighlight((e.which === KEY.UP) ? -1 : 1);
1210+
killEvent(e);
1211+
return;
1212+
case KEY.TAB:
1213+
case KEY.ENTER:
1214+
this.selectHighlighted();
1215+
killEvent(e);
1216+
return;
1217+
case KEY.ESC:
1218+
this.cancel(e);
1219+
killEvent(e);
1220+
return;
1221+
}
1222+
} else {
1223+
if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) {
1224+
return;
1225+
}
1226+
1227+
this.open();
1228+
1229+
if (e.which === KEY.ENTER) {
1230+
// do not propagate the event otherwise we open, and propagate enter which closes
1231+
killEvent(e);
1232+
return;
1233+
}
1234+
}
12011235
}));
12021236

1203-
containers.delegate(selector, "click", this.bind(function (e) {
1237+
selection.bind("click", this.bind(function (e) {
12041238
clickingInside = true;
12051239

12061240
if (this.opened()) {
12071241
this.close();
1208-
selection.focus();
1242+
this.search.focus();
12091243
} else if (this.enabled) {
12101244
this.open();
12111245
}
1212-
e.preventDefault();
1246+
killEvent(e);
12131247

12141248
clickingInside = false;
12151249
}));
1216-
containers.delegate(selector, "keydown", this.bind(function (e) {
1217-
if (!this.enabled || e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) {
1218-
return;
1219-
}
1220-
this.open();
1221-
if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN || e.which === KEY.SPACE) {
1222-
// prevent the page from scrolling
1223-
killEvent(e);
1224-
}
1225-
if (e.which === KEY.ENTER) {
1226-
// do not propagate the event otherwise we open, and propagate enter which closes
1227-
killEvent(e);
1228-
}
1229-
}));
1230-
containers.delegate(selector, "focus", function () { if (this.enabled) { containers.addClass("select2-container-active"); dropdown.addClass("select2-drop-active"); }});
1231-
containers.delegate(selector, "blur", this.bind(function (e) {
1232-
if (clickingInside) return;
1233-
if (e.target===focusser.get(0)) return; // ignore blurs from focusser
1234-
if (!this.opened()) { this.blur(); }
1235-
}));
1250+
1251+
dropdown.bind("click", this.bind(function() { this.search.focus(); }));
12361252

12371253
selection.delegate("abbr", "click", this.bind(function (e) {
12381254
if (!this.enabled) return;
12391255
this.clear();
12401256
killEvent(e);
12411257
this.close();
12421258
this.triggerChange();
1243-
selection.focus();
1259+
this.search.focus();
12441260
}));
12451261

1262+
selection.bind("focus", this.bind(function() { this.search.focus(); }));
1263+
12461264
this.setPlaceholder();
12471265

1248-
focusser.bind("focus", function() { selection.focus(); });
1249-
selection.bind("focus", this.bind(function() {
1250-
focusser.hide();
1266+
this.search.bind("focus", this.bind(function() {
12511267
this.container.addClass("select2-container-active");
12521268
}));
1253-
selection.bind("blur", function() { focusser.show(); });
1254-
this.opts.element.bind("open", function() { focusser.hide(); });
12551269
},
12561270

12571271
clear: function() {
@@ -1358,7 +1372,7 @@
13581372
this.opts.element.val(this.id(data));
13591373
this.updateSelection(data);
13601374
this.close();
1361-
this.selection.focus();
1375+
this.search.focus();
13621376

13631377
if (!equal(old, this.id(data))) { this.triggerChange(); }
13641378
},
@@ -1623,13 +1637,12 @@
16231637
},
16241638

16251639
// multi
1626-
open: function () {
1627-
if (this.parent.open.apply(this, arguments) === false) return false;
1640+
opening: function () {
1641+
this.parent.opening.apply(this, arguments);
16281642

16291643
this.clearPlaceholder();
16301644
this.resizeSearch();
16311645
this.focusSearch();
1632-
return true;
16331646
},
16341647

16351648
// multi

0 commit comments

Comments
 (0)