Skip to content

Commit

Permalink
Prevent a disabled element from opening via keydown/keypress events
Browse files Browse the repository at this point in the history
Gist: return early from the Select2#open method if the object is
disabled.

Add helper #isEnabled and #isDisabled methods to Select2 and selector
classes.

Add test coverage for the original, expected behavior and new
preventative behavior.
  • Loading branch information
mcountis committed Jan 21, 2020
1 parent 48775d0 commit 95d7d30
Show file tree
Hide file tree
Showing 12 changed files with 359 additions and 17 deletions.
56 changes: 51 additions & 5 deletions dist/js/select2.full.js
Expand Up @@ -1556,6 +1556,27 @@ S2.define('select2/selection/base',[
throw new Error('The `update` method must be defined in child classes.');
};

/**
* Helper method to abstract the "enabled" (not "disabled") state of this
* object.
*
* @return {true} if the instance is not disabled.
* @return {false} if the instance is disabled.
*/
BaseSelection.prototype.isEnabled = function () {
return !this.isDisabled();
};

/**
* Helper method to abstract the "disabled" state of this object.
*
* @return {true} if the disabled option is true.
* @return {false} if the disabled option is false.
*/
BaseSelection.prototype.isDisabled = function () {
return this.options.get('disabled');
};

return BaseSelection;
});

Expand Down Expand Up @@ -1706,7 +1727,7 @@ S2.define('select2/selection/multiple',[
'.select2-selection__choice__remove',
function (evt) {
// Ignore the event if it is disabled
if (self.options.get('disabled')) {
if (self.isDisabled()) {
return;
}

Expand Down Expand Up @@ -1867,7 +1888,7 @@ S2.define('select2/selection/allowClear',[

AllowClear.prototype._handleClear = function (_, evt) {
// Ignore the event if it is disabled
if (this.options.get('disabled')) {
if (this.isDisabled()) {
return;
}

Expand Down Expand Up @@ -1933,7 +1954,7 @@ S2.define('select2/selection/allowClear',[
return;
}

var removeAll = this.options.get('translations').get('removeAllItems');
var removeAll = this.options.get('translations').get('removeAllItems');

var $remove = $(
'<span class="select2-selection__clear" title="' + removeAll() +'">' +
Expand Down Expand Up @@ -5702,7 +5723,7 @@ S2.define('select2/core',[
Select2.prototype._syncAttributes = function () {
this.options.set('disabled', this.$element.prop('disabled'));

if (this.options.get('disabled')) {
if (this.isDisabled()) {
if (this.isOpen()) {
this.close();
}
Expand Down Expand Up @@ -5792,7 +5813,7 @@ S2.define('select2/core',[
};

Select2.prototype.toggleDropdown = function () {
if (this.options.get('disabled')) {
if (this.isDisabled()) {
return;
}

Expand All @@ -5808,6 +5829,10 @@ S2.define('select2/core',[
return;
}

if (this.isDisabled()) {
return;
}

this.trigger('query', {});
};

Expand All @@ -5819,6 +5844,27 @@ S2.define('select2/core',[
this.trigger('close', {});
};

/**
* Helper method to abstract the "enabled" (not "disabled") state of this
* object.
*
* @return {true} if the instance is not disabled.
* @return {false} if the instance is disabled.
*/
Select2.prototype.isEnabled = function () {
return !this.isDisabled();
};

/**
* Helper method to abstract the "disabled" state of this object.
*
* @return {true} if the disabled option is true.
* @return {false} if the disabled option is false.
*/
Select2.prototype.isDisabled = function () {
return this.options.get('disabled');
};

Select2.prototype.isOpen = function () {
return this.$container.hasClass('select2-container--open');
};
Expand Down
2 changes: 1 addition & 1 deletion dist/js/select2.full.min.js

Large diffs are not rendered by default.

56 changes: 51 additions & 5 deletions dist/js/select2.js
Expand Up @@ -1556,6 +1556,27 @@ S2.define('select2/selection/base',[
throw new Error('The `update` method must be defined in child classes.');
};

/**
* Helper method to abstract the "enabled" (not "disabled") state of this
* object.
*
* @return {true} if the instance is not disabled.
* @return {false} if the instance is disabled.
*/
BaseSelection.prototype.isEnabled = function () {
return !this.isDisabled();
};

/**
* Helper method to abstract the "disabled" state of this object.
*
* @return {true} if the disabled option is true.
* @return {false} if the disabled option is false.
*/
BaseSelection.prototype.isDisabled = function () {
return this.options.get('disabled');
};

return BaseSelection;
});

Expand Down Expand Up @@ -1706,7 +1727,7 @@ S2.define('select2/selection/multiple',[
'.select2-selection__choice__remove',
function (evt) {
// Ignore the event if it is disabled
if (self.options.get('disabled')) {
if (self.isDisabled()) {
return;
}

Expand Down Expand Up @@ -1867,7 +1888,7 @@ S2.define('select2/selection/allowClear',[

AllowClear.prototype._handleClear = function (_, evt) {
// Ignore the event if it is disabled
if (this.options.get('disabled')) {
if (this.isDisabled()) {
return;
}

Expand Down Expand Up @@ -1933,7 +1954,7 @@ S2.define('select2/selection/allowClear',[
return;
}

var removeAll = this.options.get('translations').get('removeAllItems');
var removeAll = this.options.get('translations').get('removeAllItems');

var $remove = $(
'<span class="select2-selection__clear" title="' + removeAll() +'">' +
Expand Down Expand Up @@ -5702,7 +5723,7 @@ S2.define('select2/core',[
Select2.prototype._syncAttributes = function () {
this.options.set('disabled', this.$element.prop('disabled'));

if (this.options.get('disabled')) {
if (this.isDisabled()) {
if (this.isOpen()) {
this.close();
}
Expand Down Expand Up @@ -5792,7 +5813,7 @@ S2.define('select2/core',[
};

Select2.prototype.toggleDropdown = function () {
if (this.options.get('disabled')) {
if (this.isDisabled()) {
return;
}

Expand All @@ -5808,6 +5829,10 @@ S2.define('select2/core',[
return;
}

if (this.isDisabled()) {
return;
}

this.trigger('query', {});
};

Expand All @@ -5819,6 +5844,27 @@ S2.define('select2/core',[
this.trigger('close', {});
};

/**
* Helper method to abstract the "enabled" (not "disabled") state of this
* object.
*
* @return {true} if the instance is not disabled.
* @return {false} if the instance is disabled.
*/
Select2.prototype.isEnabled = function () {
return !this.isDisabled();
};

/**
* Helper method to abstract the "disabled" state of this object.
*
* @return {true} if the disabled option is true.
* @return {false} if the disabled option is false.
*/
Select2.prototype.isDisabled = function () {
return this.options.get('disabled');
};

Select2.prototype.isOpen = function () {
return this.$container.hasClass('select2-container--open');
};
Expand Down
2 changes: 1 addition & 1 deletion dist/js/select2.min.js

Large diffs are not rendered by default.

29 changes: 27 additions & 2 deletions src/js/select2/core.js
Expand Up @@ -365,7 +365,7 @@ define([
Select2.prototype._syncAttributes = function () {
this.options.set('disabled', this.$element.prop('disabled'));

if (this.options.get('disabled')) {
if (this.isDisabled()) {
if (this.isOpen()) {
this.close();
}
Expand Down Expand Up @@ -455,7 +455,7 @@ define([
};

Select2.prototype.toggleDropdown = function () {
if (this.options.get('disabled')) {
if (this.isDisabled()) {
return;
}

Expand All @@ -471,6 +471,10 @@ define([
return;
}

if (this.isDisabled()) {
return;
}

this.trigger('query', {});
};

Expand All @@ -482,6 +486,27 @@ define([
this.trigger('close', {});
};

/**
* Helper method to abstract the "enabled" (not "disabled") state of this
* object.
*
* @return {true} if the instance is not disabled.
* @return {false} if the instance is disabled.
*/
Select2.prototype.isEnabled = function () {
return !this.isDisabled();
};

/**
* Helper method to abstract the "disabled" state of this object.
*
* @return {true} if the disabled option is true.
* @return {false} if the disabled option is false.
*/
Select2.prototype.isDisabled = function () {
return this.options.get('disabled');
};

Select2.prototype.isOpen = function () {
return this.$container.hasClass('select2-container--open');
};
Expand Down
4 changes: 2 additions & 2 deletions src/js/select2/selection/allowClear.js
Expand Up @@ -31,7 +31,7 @@ define([

AllowClear.prototype._handleClear = function (_, evt) {
// Ignore the event if it is disabled
if (this.options.get('disabled')) {
if (this.isDisabled()) {
return;
}

Expand Down Expand Up @@ -97,7 +97,7 @@ define([
return;
}

var removeAll = this.options.get('translations').get('removeAllItems');
var removeAll = this.options.get('translations').get('removeAllItems');

var $remove = $(
'<span class="select2-selection__clear" title="' + removeAll() +'">' +
Expand Down
21 changes: 21 additions & 0 deletions src/js/select2/selection/base.js
Expand Up @@ -153,5 +153,26 @@ define([
throw new Error('The `update` method must be defined in child classes.');
};

/**
* Helper method to abstract the "enabled" (not "disabled") state of this
* object.
*
* @return {true} if the instance is not disabled.
* @return {false} if the instance is disabled.
*/
BaseSelection.prototype.isEnabled = function () {
return !this.isDisabled();
};

/**
* Helper method to abstract the "disabled" state of this object.
*
* @return {true} if the disabled option is true.
* @return {false} if the disabled option is false.
*/
BaseSelection.prototype.isDisabled = function () {
return this.options.get('disabled');
};

return BaseSelection;
});
2 changes: 1 addition & 1 deletion src/js/select2/selection/multiple.js
Expand Up @@ -37,7 +37,7 @@ define([
'.select2-selection__choice__remove',
function (evt) {
// Ignore the event if it is disabled
if (self.options.get('disabled')) {
if (self.isDisabled()) {
return;
}

Expand Down

0 comments on commit 95d7d30

Please sign in to comment.