Update Select2 plugin to version 4.0.3
This commit is contained in:
239
plugins/select2/select2.js
vendored
239
plugins/select2/select2.js
vendored
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* Select2 4.0.1
|
||||
* Select2 4.0.3
|
||||
* https://select2.github.io
|
||||
*
|
||||
* Released under the MIT license
|
||||
@@ -606,9 +606,23 @@ S2.define('select2/utils',[
|
||||
|
||||
Observable.prototype.trigger = function (event) {
|
||||
var slice = Array.prototype.slice;
|
||||
var params = slice.call(arguments, 1);
|
||||
|
||||
this.listeners = this.listeners || {};
|
||||
|
||||
// Params should always come in as an array
|
||||
if (params == null) {
|
||||
params = [];
|
||||
}
|
||||
|
||||
// If there are no arguments to the event, use a temporary object
|
||||
if (params.length === 0) {
|
||||
params.push({});
|
||||
}
|
||||
|
||||
// Set the `_type` of the first object to the event
|
||||
params[0]._type = event;
|
||||
|
||||
if (event in this.listeners) {
|
||||
this.invoke(this.listeners[event], slice.call(arguments, 1));
|
||||
}
|
||||
@@ -842,6 +856,25 @@ S2.define('select2/results',[
|
||||
return sorter(data);
|
||||
};
|
||||
|
||||
Results.prototype.highlightFirstItem = function () {
|
||||
var $options = this.$results
|
||||
.find('.select2-results__option[aria-selected]');
|
||||
|
||||
var $selected = $options.filter('[aria-selected=true]');
|
||||
|
||||
// Check if there are any selected options
|
||||
if ($selected.length > 0) {
|
||||
// If there are selected options, highlight the first
|
||||
$selected.first().trigger('mouseenter');
|
||||
} else {
|
||||
// If there are no selected options, highlight the first option
|
||||
// in the dropdown
|
||||
$options.first().trigger('mouseenter');
|
||||
}
|
||||
|
||||
this.ensureHighlightVisible();
|
||||
};
|
||||
|
||||
Results.prototype.setClasses = function () {
|
||||
var self = this;
|
||||
|
||||
@@ -869,17 +902,6 @@ S2.define('select2/results',[
|
||||
}
|
||||
});
|
||||
|
||||
var $selected = $options.filter('[aria-selected=true]');
|
||||
|
||||
// Check if there are any selected options
|
||||
if ($selected.length > 0) {
|
||||
// If there are selected options, highlight the first
|
||||
$selected.first().trigger('mouseenter');
|
||||
} else {
|
||||
// If there are no selected options, highlight the first option
|
||||
// in the dropdown
|
||||
$options.first().trigger('mouseenter');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -990,6 +1012,7 @@ S2.define('select2/results',[
|
||||
|
||||
if (container.isOpen()) {
|
||||
self.setClasses();
|
||||
self.highlightFirstItem();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1012,6 +1035,7 @@ S2.define('select2/results',[
|
||||
}
|
||||
|
||||
self.setClasses();
|
||||
self.highlightFirstItem();
|
||||
});
|
||||
|
||||
container.on('unselect', function () {
|
||||
@@ -1020,6 +1044,7 @@ S2.define('select2/results',[
|
||||
}
|
||||
|
||||
self.setClasses();
|
||||
self.highlightFirstItem();
|
||||
});
|
||||
|
||||
container.on('open', function () {
|
||||
@@ -1142,11 +1167,7 @@ S2.define('select2/results',[
|
||||
this.$results.on('mousewheel', function (e) {
|
||||
var top = self.$results.scrollTop();
|
||||
|
||||
var bottom = (
|
||||
self.$results.get(0).scrollHeight -
|
||||
self.$results.scrollTop() +
|
||||
e.deltaY
|
||||
);
|
||||
var bottom = self.$results.get(0).scrollHeight - top + e.deltaY;
|
||||
|
||||
var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0;
|
||||
var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height();
|
||||
@@ -1501,6 +1522,12 @@ S2.define('select2/selection/single',[
|
||||
// User exits the container
|
||||
});
|
||||
|
||||
container.on('focus', function (evt) {
|
||||
if (!container.isOpen()) {
|
||||
self.$selection.focus();
|
||||
}
|
||||
});
|
||||
|
||||
container.on('selection:update', function (params) {
|
||||
self.update(params.data);
|
||||
});
|
||||
@@ -3332,7 +3359,7 @@ S2.define('select2/data/array',[
|
||||
var $existingOption = $existing.filter(onlyItem(item));
|
||||
|
||||
var existingData = this.item($existingOption);
|
||||
var newData = $.extend(true, {}, existingData, item);
|
||||
var newData = $.extend(true, {}, item, existingData);
|
||||
|
||||
var $newOption = this.option(newData);
|
||||
|
||||
@@ -3440,13 +3467,21 @@ S2.define('select2/data/ajax',[
|
||||
|
||||
callback(results);
|
||||
}, function () {
|
||||
// TODO: Handle AJAX errors
|
||||
// Attempt to detect if a request was aborted
|
||||
// Only works if the transport exposes a status property
|
||||
if ($request.status && $request.status === '0') {
|
||||
return;
|
||||
}
|
||||
|
||||
self.trigger('results:message', {
|
||||
message: 'errorLoading'
|
||||
});
|
||||
});
|
||||
|
||||
self._request = $request;
|
||||
}
|
||||
|
||||
if (this.ajaxOptions.delay && params.term !== '') {
|
||||
if (this.ajaxOptions.delay && params.term != null) {
|
||||
if (this._queryTimeout) {
|
||||
window.clearTimeout(this._queryTimeout);
|
||||
}
|
||||
@@ -3472,6 +3507,12 @@ S2.define('select2/data/tags',[
|
||||
this.createTag = createTag;
|
||||
}
|
||||
|
||||
var insertTag = options.get('insertTag');
|
||||
|
||||
if (insertTag !== undefined) {
|
||||
this.insertTag = insertTag;
|
||||
}
|
||||
|
||||
decorated.call(this, $element, options);
|
||||
|
||||
if ($.isArray(tags)) {
|
||||
@@ -3603,6 +3644,29 @@ S2.define('select2/data/tokenizer',[
|
||||
Tokenizer.prototype.query = function (decorated, params, callback) {
|
||||
var self = this;
|
||||
|
||||
function createAndSelect (data) {
|
||||
// Normalize the data object so we can use it for checks
|
||||
var item = self._normalizeItem(data);
|
||||
|
||||
// Check if the data object already exists as a tag
|
||||
// Select it if it doesn't
|
||||
var $existingOptions = self.$element.find('option').filter(function () {
|
||||
return $(this).val() === item.id;
|
||||
});
|
||||
|
||||
// If an existing option wasn't found for it, create the option
|
||||
if (!$existingOptions.length) {
|
||||
var $option = self.option(item);
|
||||
$option.attr('data-select2-tag', true);
|
||||
|
||||
self._removeOldTags();
|
||||
self.addOptions([$option]);
|
||||
}
|
||||
|
||||
// Select the item, now that we know there is an option for it
|
||||
select(item);
|
||||
}
|
||||
|
||||
function select (data) {
|
||||
self.trigger('select', {
|
||||
data: data
|
||||
@@ -3611,7 +3675,7 @@ S2.define('select2/data/tokenizer',[
|
||||
|
||||
params.term = params.term || '';
|
||||
|
||||
var tokenData = this.tokenizer(params, this.options, select);
|
||||
var tokenData = this.tokenizer(params, this.options, createAndSelect);
|
||||
|
||||
if (tokenData.term !== params.term) {
|
||||
// Replace the search term if we have the search box
|
||||
@@ -3876,6 +3940,12 @@ S2.define('select2/dropdown/search',[
|
||||
self.$search.val('');
|
||||
});
|
||||
|
||||
container.on('focus', function () {
|
||||
if (container.isOpen()) {
|
||||
self.$search.focus();
|
||||
}
|
||||
});
|
||||
|
||||
container.on('results:all', function (params) {
|
||||
if (params.query.term == null || params.query.term === '') {
|
||||
var showSearch = self.showSearch(params);
|
||||
@@ -4171,7 +4241,6 @@ S2.define('select2/dropdown/attachBody',[
|
||||
|
||||
var newDirection = null;
|
||||
|
||||
var position = this.$container.position();
|
||||
var offset = this.$container.offset();
|
||||
|
||||
offset.bottom = offset.top + this.$container.outerHeight(false);
|
||||
@@ -4200,14 +4269,20 @@ S2.define('select2/dropdown/attachBody',[
|
||||
top: container.bottom
|
||||
};
|
||||
|
||||
// Fix positioning with static parents
|
||||
if (this.$dropdownParent[0].style.position !== 'static') {
|
||||
var parentOffset = this.$dropdownParent.offset();
|
||||
// Determine what the parent element is to use for calciulating the offset
|
||||
var $offsetParent = this.$dropdownParent;
|
||||
|
||||
css.top -= parentOffset.top;
|
||||
css.left -= parentOffset.left;
|
||||
// For statically positoned elements, we need to get the element
|
||||
// that is determining the offset
|
||||
if ($offsetParent.css('position') === 'static') {
|
||||
$offsetParent = $offsetParent.offsetParent();
|
||||
}
|
||||
|
||||
var parentOffset = $offsetParent.offset();
|
||||
|
||||
css.top -= parentOffset.top;
|
||||
css.left -= parentOffset.left;
|
||||
|
||||
if (!isCurrentlyAbove && !isCurrentlyBelow) {
|
||||
newDirection = 'below';
|
||||
}
|
||||
@@ -4220,7 +4295,7 @@ S2.define('select2/dropdown/attachBody',[
|
||||
|
||||
if (newDirection == 'above' ||
|
||||
(isCurrentlyAbove && newDirection !== 'below')) {
|
||||
css.top = container.top - dropdown.height;
|
||||
css.top = container.top - parentOffset.top - dropdown.height;
|
||||
}
|
||||
|
||||
if (newDirection != null) {
|
||||
@@ -4242,6 +4317,7 @@ S2.define('select2/dropdown/attachBody',[
|
||||
|
||||
if (this.options.get('dropdownAutoWidth')) {
|
||||
css.minWidth = css.width;
|
||||
css.position = 'relative';
|
||||
css.width = 'auto';
|
||||
}
|
||||
|
||||
@@ -4308,12 +4384,22 @@ S2.define('select2/dropdown/selectOnClose',[
|
||||
|
||||
decorated.call(this, container, $container);
|
||||
|
||||
container.on('close', function () {
|
||||
self._handleSelectOnClose();
|
||||
container.on('close', function (params) {
|
||||
self._handleSelectOnClose(params);
|
||||
});
|
||||
};
|
||||
|
||||
SelectOnClose.prototype._handleSelectOnClose = function () {
|
||||
SelectOnClose.prototype._handleSelectOnClose = function (_, params) {
|
||||
if (params && params.originalSelect2Event != null) {
|
||||
var event = params.originalSelect2Event;
|
||||
|
||||
// Don't select an item if the close event was triggered from a select or
|
||||
// unselect event
|
||||
if (event._type === 'select' || event._type === 'unselect') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var $highlightedResults = this.getHighlightedResults();
|
||||
|
||||
// Only select highlighted results
|
||||
@@ -4366,7 +4452,10 @@ S2.define('select2/dropdown/closeOnSelect',[
|
||||
return;
|
||||
}
|
||||
|
||||
this.trigger('close', {});
|
||||
this.trigger('close', {
|
||||
originalEvent: originalEvent,
|
||||
originalSelect2Event: evt
|
||||
});
|
||||
};
|
||||
|
||||
return CloseOnSelect;
|
||||
@@ -4474,7 +4563,7 @@ S2.define('select2/defaults',[
|
||||
}
|
||||
|
||||
Defaults.prototype.apply = function (options) {
|
||||
options = $.extend({}, this.defaults, options);
|
||||
options = $.extend(true, {}, this.defaults, options);
|
||||
|
||||
if (options.dataAdapter == null) {
|
||||
if (options.ajax != null) {
|
||||
@@ -5038,6 +5127,7 @@ S2.define('select2/core',[
|
||||
id = Utils.generateChars(4);
|
||||
}
|
||||
|
||||
id = id.replace(/(:|\.|\[|\]|,)/g, '');
|
||||
id = 'select2-' + id;
|
||||
|
||||
return id;
|
||||
@@ -5119,10 +5209,15 @@ S2.define('select2/core',[
|
||||
});
|
||||
});
|
||||
|
||||
this._sync = Utils.bind(this._syncAttributes, this);
|
||||
this.$element.on('focus.select2', function (evt) {
|
||||
self.trigger('focus', evt);
|
||||
});
|
||||
|
||||
this._syncA = Utils.bind(this._syncAttributes, this);
|
||||
this._syncS = Utils.bind(this._syncSubtree, this);
|
||||
|
||||
if (this.$element[0].attachEvent) {
|
||||
this.$element[0].attachEvent('onpropertychange', this._sync);
|
||||
this.$element[0].attachEvent('onpropertychange', this._syncA);
|
||||
}
|
||||
|
||||
var observer = window.MutationObserver ||
|
||||
@@ -5132,14 +5227,30 @@ S2.define('select2/core',[
|
||||
|
||||
if (observer != null) {
|
||||
this._observer = new observer(function (mutations) {
|
||||
$.each(mutations, self._sync);
|
||||
$.each(mutations, self._syncA);
|
||||
$.each(mutations, self._syncS);
|
||||
});
|
||||
this._observer.observe(this.$element[0], {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
subtree: false
|
||||
});
|
||||
} else if (this.$element[0].addEventListener) {
|
||||
this.$element[0].addEventListener('DOMAttrModified', self._sync, false);
|
||||
this.$element[0].addEventListener(
|
||||
'DOMAttrModified',
|
||||
self._syncA,
|
||||
false
|
||||
);
|
||||
this.$element[0].addEventListener(
|
||||
'DOMNodeInserted',
|
||||
self._syncS,
|
||||
false
|
||||
);
|
||||
this.$element[0].addEventListener(
|
||||
'DOMNodeRemoved',
|
||||
self._syncS,
|
||||
false
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5284,6 +5395,46 @@ S2.define('select2/core',[
|
||||
}
|
||||
};
|
||||
|
||||
Select2.prototype._syncSubtree = function (evt, mutations) {
|
||||
var changed = false;
|
||||
var self = this;
|
||||
|
||||
// Ignore any mutation events raised for elements that aren't options or
|
||||
// optgroups. This handles the case when the select element is destroyed
|
||||
if (
|
||||
evt && evt.target && (
|
||||
evt.target.nodeName !== 'OPTION' && evt.target.nodeName !== 'OPTGROUP'
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mutations) {
|
||||
// If mutation events aren't supported, then we can only assume that the
|
||||
// change affected the selections
|
||||
changed = true;
|
||||
} else if (mutations.addedNodes && mutations.addedNodes.length > 0) {
|
||||
for (var n = 0; n < mutations.addedNodes.length; n++) {
|
||||
var node = mutations.addedNodes[n];
|
||||
|
||||
if (node.selected) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
} else if (mutations.removedNodes && mutations.removedNodes.length > 0) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// Only re-pull the data if we think there is a change
|
||||
if (changed) {
|
||||
this.dataAdapter.current(function (currentData) {
|
||||
self.trigger('selection:update', {
|
||||
data: currentData
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Override the trigger method to automatically trigger pre-events when
|
||||
* there are events that can be prevented.
|
||||
@@ -5430,7 +5581,7 @@ S2.define('select2/core',[
|
||||
this.$container.remove();
|
||||
|
||||
if (this.$element[0].detachEvent) {
|
||||
this.$element[0].detachEvent('onpropertychange', this._sync);
|
||||
this.$element[0].detachEvent('onpropertychange', this._syncA);
|
||||
}
|
||||
|
||||
if (this._observer != null) {
|
||||
@@ -5438,10 +5589,15 @@ S2.define('select2/core',[
|
||||
this._observer = null;
|
||||
} else if (this.$element[0].removeEventListener) {
|
||||
this.$element[0]
|
||||
.removeEventListener('DOMAttrModified', this._sync, false);
|
||||
.removeEventListener('DOMAttrModified', this._syncA, false);
|
||||
this.$element[0]
|
||||
.removeEventListener('DOMNodeInserted', this._syncS, false);
|
||||
this.$element[0]
|
||||
.removeEventListener('DOMNodeRemoved', this._syncS, false);
|
||||
}
|
||||
|
||||
this._sync = null;
|
||||
this._syncA = null;
|
||||
this._syncS = null;
|
||||
|
||||
this.$element.off('.select2');
|
||||
this.$element.attr('tabindex', this.$element.data('old-tabindex'));
|
||||
@@ -5514,6 +5670,7 @@ S2.define('jquery.select2',[
|
||||
return this;
|
||||
} else if (typeof options === 'string') {
|
||||
var ret;
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
|
||||
this.each(function () {
|
||||
var instance = $(this).data('select2');
|
||||
@@ -5525,8 +5682,6 @@ S2.define('jquery.select2',[
|
||||
);
|
||||
}
|
||||
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
|
||||
ret = instance[options].apply(instance, args);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user