Update Select2 plugin to version 4.0.3

This commit is contained in:
Aleksandr Palyan
2016-05-27 21:42:25 +03:00
parent 0050e298a2
commit 9b77655eb3
53 changed files with 458 additions and 139 deletions

View File

@@ -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);
});