Skip to content

Commit e16c505

Browse files
committed
Move to a central key handler
This allows for any control to emit key events, and for the Select2 instance to handle them. So now the search box will allow for results to be scrolled and selected, bringing back the old expected functionality. This also stops triggering new queries when the arrow keys are pressed. The container will also be automatically focused when the dropdown is closed, which is consistent with the old Select2. The results will no longer be queried on initialization, but instead will be queried when the dropdown is opened. This is more consistent with the previous version of Select2. The search box will now be cleared when the dropdown is closed.
1 parent 3b575ad commit e16c505

10 files changed

Lines changed: 513 additions & 338 deletions

File tree

dist/js/select2.amd.full.js

Lines changed: 110 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ window.$ = window.$ || {};(function() { if ($ && $.fn && $.fn.select2 && $.fn.se
107107
};
108108

109109
Observable.prototype.on = function (event, callback) {
110+
this.listeners = this.listeners || {};
111+
110112
if (event in this.listeners) {
111113
this.listeners[event].push(callback);
112114
} else {
@@ -117,6 +119,8 @@ window.$ = window.$ || {};(function() { if ($ && $.fn && $.fn.select2 && $.fn.se
117119
Observable.prototype.trigger = function (event) {
118120
var slice = Array.prototype.slice;
119121

122+
this.listeners = this.listeners || {};
123+
120124
if (event in this.listeners) {
121125
this.invoke(this.listeners[event], slice.call(arguments, 1));
122126
}
@@ -569,51 +573,10 @@ define('select2/selection/base',[
569573
return BaseSelection;
570574
});
571575

572-
define('select2/keys',[
573-
574-
], function () {
575-
var KEYS = {
576-
BACKSPACE: 8,
577-
TAB: 9,
578-
ENTER: 13,
579-
SHIFT: 16,
580-
CTRL: 17,
581-
ALT: 18,
582-
ESC: 27,
583-
SPACE: 32,
584-
PAGE_UP: 33,
585-
PAGE_DOWN: 34,
586-
END: 35,
587-
HOME: 36,
588-
LEFT: 37,
589-
UP: 38,
590-
RIGHT: 39,
591-
DOWN: 40,
592-
DELETE: 46,
593-
594-
isArrow: function (k) {
595-
k = k.which ? k.which : k;
596-
597-
switch (k) {
598-
case KEY.LEFT:
599-
case KEY.RIGHT:
600-
case KEY.UP:
601-
case KEY.DOWN:
602-
return true;
603-
}
604-
605-
return false;
606-
}
607-
};
608-
609-
return KEYS;
610-
});
611-
612576
define('select2/selection/single',[
613577
'./base',
614-
'../utils',
615-
'../keys'
616-
], function (BaseSelection, Utils, KEYS) {
578+
'../utils'
579+
], function (BaseSelection, Utils) {
617580
function SingleSelection () {
618581
SingleSelection.__super__.constructor.apply(this, arguments);
619582
}
@@ -667,6 +630,8 @@ define('select2/selection/single',[
667630
// When the dropdown is closed, aria-expanded="false"
668631
self.$selection.attr('aria-expanded', 'false');
669632
self.$selection.removeAttr('aria-activedescendant');
633+
634+
self.$selection.focus();
670635
});
671636

672637
this.$selection.on('focus', function (evt) {
@@ -678,29 +643,7 @@ define('select2/selection/single',[
678643
});
679644

680645
this.$selection.on('keydown', function (evt) {
681-
var key = evt.which;
682-
683-
if (container.isOpen()) {
684-
if (key == KEYS.ENTER) {
685-
self.trigger('results:select');
686-
687-
evt.preventDefault();
688-
} else if (key == KEYS.UP) {
689-
self.trigger('results:previous');
690-
691-
evt.preventDefault();
692-
} else if (key == KEYS.DOWN) {
693-
self.trigger('results:next');
694-
695-
evt.preventDefault();
696-
}
697-
} else {
698-
if (key == KEYS.ENTER || key == KEYS.SPACE) {
699-
self.trigger('open');
700-
701-
evt.preventDefault();
702-
}
703-
}
646+
self.trigger('keypress', evt);
704647
});
705648

706649
container.on('results:focus', function (params) {
@@ -1375,8 +1318,8 @@ define('select2/dropdown',[
13751318
});
13761319

13771320
define('select2/dropdown/search',[
1378-
1379-
], function () {
1321+
'../utils'
1322+
], function (Utils) {
13801323
function Search () { }
13811324

13821325
Search.prototype.render = function (decorated) {
@@ -1401,8 +1344,14 @@ define('select2/dropdown/search',[
14011344

14021345
decorated.call(this, container, $container);
14031346

1404-
this.$search.on('keyup', function () {
1405-
container.trigger('query', {
1347+
this.$search.on('keyup', function (evt) {
1348+
self.trigger('keypress', evt);
1349+
1350+
if (evt.isDefaultPrevented()) {
1351+
return;
1352+
}
1353+
1354+
self.trigger('query', {
14061355
term: $(this).val()
14071356
});
14081357
});
@@ -1413,6 +1362,8 @@ define('select2/dropdown/search',[
14131362

14141363
container.on('close', function () {
14151364
self.$search.attr('tabindex', -1);
1365+
1366+
self.$search.val('');
14161367
});
14171368

14181369
container.on('results:all', function (params) {
@@ -1428,7 +1379,7 @@ define('select2/dropdown/search',[
14281379
});
14291380
};
14301381

1431-
Search.prototype.showSearch = function (params) {
1382+
Search.prototype.showSearch = function (_, params) {
14321383
return true;
14331384
};
14341385

@@ -1642,11 +1593,52 @@ define('select2/options',[
16421593
return Options;
16431594
});
16441595

1596+
define('select2/keys',[
1597+
1598+
], function () {
1599+
var KEYS = {
1600+
BACKSPACE: 8,
1601+
TAB: 9,
1602+
ENTER: 13,
1603+
SHIFT: 16,
1604+
CTRL: 17,
1605+
ALT: 18,
1606+
ESC: 27,
1607+
SPACE: 32,
1608+
PAGE_UP: 33,
1609+
PAGE_DOWN: 34,
1610+
END: 35,
1611+
HOME: 36,
1612+
LEFT: 37,
1613+
UP: 38,
1614+
RIGHT: 39,
1615+
DOWN: 40,
1616+
DELETE: 46,
1617+
1618+
isArrow: function (k) {
1619+
k = k.which ? k.which : k;
1620+
1621+
switch (k) {
1622+
case KEY.LEFT:
1623+
case KEY.RIGHT:
1624+
case KEY.UP:
1625+
case KEY.DOWN:
1626+
return true;
1627+
}
1628+
1629+
return false;
1630+
}
1631+
};
1632+
1633+
return KEYS;
1634+
});
1635+
16451636
define('select2/core',[
16461637
'jquery',
16471638
'./options',
1648-
'./utils'
1649-
], function ($, Options, Utils) {
1639+
'./utils',
1640+
'./keys'
1641+
], function ($, Options, Utils, KEYS) {
16501642
var Select2 = function ($element, options) {
16511643
this.$element = $element;
16521644

@@ -1700,6 +1692,7 @@ define('select2/core',[
17001692

17011693
// Register any internal event handlers
17021694
this._registerSelectionEvents();
1695+
this._registerDropdownEvents();
17031696
this._registerResultsEvents();
17041697
this._registerEvents();
17051698

@@ -1711,8 +1704,6 @@ define('select2/core',[
17111704
});
17121705
});
17131706

1714-
this.trigger('query', {});
1715-
17161707
// Hide the original select
17171708

17181709
$element.hide();
@@ -1809,6 +1800,22 @@ define('select2/core',[
18091800

18101801
self.close();
18111802
});
1803+
1804+
this.selection.on('keypress', function (e) {
1805+
self.trigger('keypress', e);
1806+
});
1807+
};
1808+
1809+
Select2.prototype._registerDropdownEvents = function () {
1810+
var self = this;
1811+
1812+
this.dropdown.on('query', function (params) {
1813+
self.trigger('query', params);
1814+
});
1815+
1816+
this.dropdown.on('keypress', function (e) {
1817+
self.trigger('keypress', e);
1818+
});
18121819
};
18131820

18141821
Select2.prototype._registerResultsEvents = function () {
@@ -1850,6 +1857,32 @@ define('select2/core',[
18501857
});
18511858
});
18521859
});
1860+
1861+
this.on('keypress', function (evt) {
1862+
var key = evt.which;
1863+
1864+
if (self.isOpen()) {
1865+
if (key == KEYS.ENTER) {
1866+
self.trigger('results:select');
1867+
1868+
evt.preventDefault();
1869+
} else if (key == KEYS.UP) {
1870+
self.trigger('results:previous');
1871+
1872+
evt.preventDefault();
1873+
} else if (key == KEYS.DOWN) {
1874+
self.trigger('results:next');
1875+
1876+
evt.preventDefault();
1877+
}
1878+
} else {
1879+
if (key == KEYS.ENTER || key == KEYS.SPACE) {
1880+
self.trigger('open');
1881+
1882+
evt.preventDefault();
1883+
}
1884+
}
1885+
});
18531886
};
18541887

18551888
Select2.prototype.toggleDropdown = function () {
@@ -1865,6 +1898,8 @@ define('select2/core',[
18651898
return;
18661899
}
18671900

1901+
this.trigger('query', {});
1902+
18681903
this.trigger('open');
18691904
};
18701905

0 commit comments

Comments
 (0)