1
0
mirror of synced 2024-12-02 01:26:02 +03:00

More intuitive handling of the enter key

Previously, when in results the enter key would select items that
were highlighted if they were not already selected.  In the case of
a select where multiple items could be selected, pressing enter
when highlighting a selected item would also allow it to be
unselected.  While this seems intuitive for accessibility purposes,
the enter button essentially working as a toggle, it caused some
really strange behavior.

- If the enter button was held down, all previously selected items
  would be unselected.
- The enter button did not work the same across both single and
  multiple selects.

After listening to user feedback, I have decided to remove the
"enter as toggle" functionality from Select2 and have gone back to
just having the enter button select items.  This means that instead
of unselected items that are already selected and highlighted,
Select2 will just close the dropdown.  This is the same as what
Select2 would previously do for single selects, so the keyboard
functionality is now the same across both.

Because this removed the only easy way to unselect items in the
dropdown using the keyboard, we had to maintain the toggle
functionality.  We decided to implement the toggle functionality
on the CTRL + Space keybinding, which is in line with other
applications.  Now when pressing CTRL + Space at the same time in
the dropdown, the highlighted result will behave the same as if the
mouse selected it, which will toggle the current item in multiple
select mode and close the dropdown in single select mode.

This is the same keybinding that Windows Explorer [1] and GTK [2]
use for toggling the current selection, which was why it was picked.

This also fixes an issue where keyboard focus would be lost once an
item was unselected from the results.  This was due to a bug in the
CloseOnSelect module that would only automatically close the
dropdown when an item was selected, but not when an item was
unselected.  Now the dropdown will be closed automatically when an
item is unselected, which will also cause the selection (and
eventually the search) to be focused.

This fixes two issues described in
https://github.com/select2/select2/issues/3036#issuecomment-76321411.

[1]: http://superuser.com/q/78891/72528
[2]: https://developer.gnome.org/gtk3/stable/GtkIconView.html#GtkIconView-toggle-cursor-item
This commit is contained in:
Kevin Brown 2015-03-01 20:30:43 -05:00
parent c0839b4f93
commit 017c201094
9 changed files with 160 additions and 80 deletions

View File

@ -527,6 +527,16 @@ define('select2/results',[
self.$results.removeAttr('aria-activedescendant'); self.$results.removeAttr('aria-activedescendant');
}); });
container.on('results:toggle', function () {
var $highlighted = self.getHighlightedResults();
if ($highlighted.length === 0) {
return;
}
$highlighted.trigger('mouseup');
});
container.on('results:select', function () { container.on('results:select', function () {
var $highlighted = self.getHighlightedResults(); var $highlighted = self.getHighlightedResults();
@ -537,13 +547,7 @@ define('select2/results',[
var data = $highlighted.data('data'); var data = $highlighted.data('data');
if ($highlighted.attr('aria-selected') == 'true') { if ($highlighted.attr('aria-selected') == 'true') {
if (self.options.get('multiple')) { self.trigger('close');
self.trigger('unselect', {
data: data
});
} else {
self.trigger('close');
}
} else { } else {
self.trigger('select', { self.trigger('select', {
data: data data: data
@ -3647,15 +3651,23 @@ define('select2/dropdown/closeOnSelect',[
decorated.call(this, container, $container); decorated.call(this, container, $container);
container.on('select', function (evt) { container.on('select', function (evt) {
var originalEvent = evt.originalEvent; self._selectTriggered(evt);
// Don't close if the control key is being held
if (originalEvent && originalEvent.ctrlKey) {
return;
}
self.trigger('close');
}); });
container.on('unselect', function (evt) {
self._selectTriggered(evt);
});
};
CloseOnSelect.prototype._selectTriggered = function (_, evt) {
var originalEvent = evt.originalEvent;
// Don't close if the control key is being held
if (originalEvent && originalEvent.ctrlKey) {
return;
}
this.trigger('close');
}; };
return CloseOnSelect; return CloseOnSelect;
@ -4483,6 +4495,10 @@ define('select2/core',[
if (key === KEYS.ENTER) { if (key === KEYS.ENTER) {
self.trigger('results:select'); self.trigger('results:select');
evt.preventDefault();
} else if ((key === KEYS.SPACE && evt.ctrlKey)) {
self.trigger('results:toggle');
evt.preventDefault(); evt.preventDefault();
} else if (key === KEYS.UP) { } else if (key === KEYS.UP) {
self.trigger('results:previous'); self.trigger('results:previous');

View File

@ -527,6 +527,16 @@ define('select2/results',[
self.$results.removeAttr('aria-activedescendant'); self.$results.removeAttr('aria-activedescendant');
}); });
container.on('results:toggle', function () {
var $highlighted = self.getHighlightedResults();
if ($highlighted.length === 0) {
return;
}
$highlighted.trigger('mouseup');
});
container.on('results:select', function () { container.on('results:select', function () {
var $highlighted = self.getHighlightedResults(); var $highlighted = self.getHighlightedResults();
@ -537,13 +547,7 @@ define('select2/results',[
var data = $highlighted.data('data'); var data = $highlighted.data('data');
if ($highlighted.attr('aria-selected') == 'true') { if ($highlighted.attr('aria-selected') == 'true') {
if (self.options.get('multiple')) { self.trigger('close');
self.trigger('unselect', {
data: data
});
} else {
self.trigger('close');
}
} else { } else {
self.trigger('select', { self.trigger('select', {
data: data data: data
@ -3647,15 +3651,23 @@ define('select2/dropdown/closeOnSelect',[
decorated.call(this, container, $container); decorated.call(this, container, $container);
container.on('select', function (evt) { container.on('select', function (evt) {
var originalEvent = evt.originalEvent; self._selectTriggered(evt);
// Don't close if the control key is being held
if (originalEvent && originalEvent.ctrlKey) {
return;
}
self.trigger('close');
}); });
container.on('unselect', function (evt) {
self._selectTriggered(evt);
});
};
CloseOnSelect.prototype._selectTriggered = function (_, evt) {
var originalEvent = evt.originalEvent;
// Don't close if the control key is being held
if (originalEvent && originalEvent.ctrlKey) {
return;
}
this.trigger('close');
}; };
return CloseOnSelect; return CloseOnSelect;
@ -4483,6 +4495,10 @@ define('select2/core',[
if (key === KEYS.ENTER) { if (key === KEYS.ENTER) {
self.trigger('results:select'); self.trigger('results:select');
evt.preventDefault();
} else if ((key === KEYS.SPACE && evt.ctrlKey)) {
self.trigger('results:toggle');
evt.preventDefault(); evt.preventDefault();
} else if (key === KEYS.UP) { } else if (key === KEYS.UP) {
self.trigger('results:previous'); self.trigger('results:previous');

View File

@ -966,6 +966,16 @@ define('select2/results',[
self.$results.removeAttr('aria-activedescendant'); self.$results.removeAttr('aria-activedescendant');
}); });
container.on('results:toggle', function () {
var $highlighted = self.getHighlightedResults();
if ($highlighted.length === 0) {
return;
}
$highlighted.trigger('mouseup');
});
container.on('results:select', function () { container.on('results:select', function () {
var $highlighted = self.getHighlightedResults(); var $highlighted = self.getHighlightedResults();
@ -976,13 +986,7 @@ define('select2/results',[
var data = $highlighted.data('data'); var data = $highlighted.data('data');
if ($highlighted.attr('aria-selected') == 'true') { if ($highlighted.attr('aria-selected') == 'true') {
if (self.options.get('multiple')) { self.trigger('close');
self.trigger('unselect', {
data: data
});
} else {
self.trigger('close');
}
} else { } else {
self.trigger('select', { self.trigger('select', {
data: data data: data
@ -4086,15 +4090,23 @@ define('select2/dropdown/closeOnSelect',[
decorated.call(this, container, $container); decorated.call(this, container, $container);
container.on('select', function (evt) { container.on('select', function (evt) {
var originalEvent = evt.originalEvent; self._selectTriggered(evt);
// Don't close if the control key is being held
if (originalEvent && originalEvent.ctrlKey) {
return;
}
self.trigger('close');
}); });
container.on('unselect', function (evt) {
self._selectTriggered(evt);
});
};
CloseOnSelect.prototype._selectTriggered = function (_, evt) {
var originalEvent = evt.originalEvent;
// Don't close if the control key is being held
if (originalEvent && originalEvent.ctrlKey) {
return;
}
this.trigger('close');
}; };
return CloseOnSelect; return CloseOnSelect;
@ -4922,6 +4934,10 @@ define('select2/core',[
if (key === KEYS.ENTER) { if (key === KEYS.ENTER) {
self.trigger('results:select'); self.trigger('results:select');
evt.preventDefault();
} else if ((key === KEYS.SPACE && evt.ctrlKey)) {
self.trigger('results:toggle');
evt.preventDefault(); evt.preventDefault();
} else if (key === KEYS.UP) { } else if (key === KEYS.UP) {
self.trigger('results:previous'); self.trigger('results:previous');

File diff suppressed because one or more lines are too long

46
dist/js/select2.js vendored
View File

@ -966,6 +966,16 @@ define('select2/results',[
self.$results.removeAttr('aria-activedescendant'); self.$results.removeAttr('aria-activedescendant');
}); });
container.on('results:toggle', function () {
var $highlighted = self.getHighlightedResults();
if ($highlighted.length === 0) {
return;
}
$highlighted.trigger('mouseup');
});
container.on('results:select', function () { container.on('results:select', function () {
var $highlighted = self.getHighlightedResults(); var $highlighted = self.getHighlightedResults();
@ -976,13 +986,7 @@ define('select2/results',[
var data = $highlighted.data('data'); var data = $highlighted.data('data');
if ($highlighted.attr('aria-selected') == 'true') { if ($highlighted.attr('aria-selected') == 'true') {
if (self.options.get('multiple')) { self.trigger('close');
self.trigger('unselect', {
data: data
});
} else {
self.trigger('close');
}
} else { } else {
self.trigger('select', { self.trigger('select', {
data: data data: data
@ -4086,15 +4090,23 @@ define('select2/dropdown/closeOnSelect',[
decorated.call(this, container, $container); decorated.call(this, container, $container);
container.on('select', function (evt) { container.on('select', function (evt) {
var originalEvent = evt.originalEvent; self._selectTriggered(evt);
// Don't close if the control key is being held
if (originalEvent && originalEvent.ctrlKey) {
return;
}
self.trigger('close');
}); });
container.on('unselect', function (evt) {
self._selectTriggered(evt);
});
};
CloseOnSelect.prototype._selectTriggered = function (_, evt) {
var originalEvent = evt.originalEvent;
// Don't close if the control key is being held
if (originalEvent && originalEvent.ctrlKey) {
return;
}
this.trigger('close');
}; };
return CloseOnSelect; return CloseOnSelect;
@ -4922,6 +4934,10 @@ define('select2/core',[
if (key === KEYS.ENTER) { if (key === KEYS.ENTER) {
self.trigger('results:select'); self.trigger('results:select');
evt.preventDefault();
} else if ((key === KEYS.SPACE && evt.ctrlKey)) {
self.trigger('results:toggle');
evt.preventDefault(); evt.preventDefault();
} else if (key === KEYS.UP) { } else if (key === KEYS.UP) {
self.trigger('results:previous'); self.trigger('results:previous');

File diff suppressed because one or more lines are too long

View File

@ -296,6 +296,10 @@ define([
if (key === KEYS.ENTER) { if (key === KEYS.ENTER) {
self.trigger('results:select'); self.trigger('results:select');
evt.preventDefault();
} else if ((key === KEYS.SPACE && evt.ctrlKey)) {
self.trigger('results:toggle');
evt.preventDefault(); evt.preventDefault();
} else if (key === KEYS.UP) { } else if (key === KEYS.UP) {
self.trigger('results:previous'); self.trigger('results:previous');

View File

@ -9,15 +9,23 @@ define([
decorated.call(this, container, $container); decorated.call(this, container, $container);
container.on('select', function (evt) { container.on('select', function (evt) {
var originalEvent = evt.originalEvent; self._selectTriggered(evt);
// Don't close if the control key is being held
if (originalEvent && originalEvent.ctrlKey) {
return;
}
self.trigger('close');
}); });
container.on('unselect', function (evt) {
self._selectTriggered(evt);
});
};
CloseOnSelect.prototype._selectTriggered = function (_, evt) {
var originalEvent = evt.originalEvent;
// Don't close if the control key is being held
if (originalEvent && originalEvent.ctrlKey) {
return;
}
this.trigger('close');
}; };
return CloseOnSelect; return CloseOnSelect;

View File

@ -281,6 +281,16 @@ define([
self.$results.removeAttr('aria-activedescendant'); self.$results.removeAttr('aria-activedescendant');
}); });
container.on('results:toggle', function () {
var $highlighted = self.getHighlightedResults();
if ($highlighted.length === 0) {
return;
}
$highlighted.trigger('mouseup');
});
container.on('results:select', function () { container.on('results:select', function () {
var $highlighted = self.getHighlightedResults(); var $highlighted = self.getHighlightedResults();
@ -291,13 +301,7 @@ define([
var data = $highlighted.data('data'); var data = $highlighted.data('data');
if ($highlighted.attr('aria-selected') == 'true') { if ($highlighted.attr('aria-selected') == 'true') {
if (self.options.get('multiple')) { self.trigger('close');
self.trigger('unselect', {
data: data
});
} else {
self.trigger('close');
}
} else { } else {
self.trigger('select', { self.trigger('select', {
data: data data: data