mod/bootstrap/vendor/select2/dist/js/select2.js in card-1.94.1 vs mod/bootstrap/vendor/select2/dist/js/select2.js in card-1.95.0

- old
+ new

@@ -1,13 +1,13 @@ /*! - * Select2 4.0.4 + * Select2 4.0.6-rc.1 * https://select2.github.io * * Released under the MIT license * https://github.com/select2/select2/blob/master/LICENSE.md */ -(function (factory) { +;(function (factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(['jquery'], factory); } else if (typeof module === 'object' && module.exports) { // Node/CommonJS @@ -572,14 +572,14 @@ } DecoratedClass.prototype = new ctr(); for (var m = 0; m < superMethods.length; m++) { - var superMethod = superMethods[m]; + var superMethod = superMethods[m]; - DecoratedClass.prototype[superMethod] = - SuperClass.prototype[superMethod]; + DecoratedClass.prototype[superMethod] = + SuperClass.prototype[superMethod]; } var calledMethod = function (methodName) { // Stub out the original method if it's not decorating an actual method var originalMethod = function () {}; @@ -770,10 +770,71 @@ } $element.append($nodes); }; + // Cache objects in Utils.__cache instead of $.data (see #4346) + Utils.__cache = {}; + + var id = 0; + Utils.GetUniqueElementId = function (element) { + // Get a unique element Id. If element has no id, + // creates a new unique number, stores it in the id + // attribute and returns the new id. + // If an id already exists, it simply returns it. + + var select2Id = element.getAttribute('data-select2-id'); + if (select2Id == null) { + // If element has id, use it. + if (element.id) { + select2Id = element.id; + element.setAttribute('data-select2-id', select2Id); + } else { + element.setAttribute('data-select2-id', ++id); + select2Id = id.toString(); + } + } + return select2Id; + }; + + Utils.StoreData = function (element, name, value) { + // Stores an item in the cache for a specified element. + // name is the cache key. + var id = Utils.GetUniqueElementId(element); + if (!Utils.__cache[id]) { + Utils.__cache[id] = {}; + } + + Utils.__cache[id][name] = value; + }; + + Utils.GetData = function (element, name) { + // Retrieves a value from the cache by its key (name) + // name is optional. If no name specified, return + // all cache items for the specified element. + // and for a specified element. + var id = Utils.GetUniqueElementId(element); + if (name) { + if (Utils.__cache[id]) { + return Utils.__cache[id][name] != null ? + Utils.__cache[id][name]: + $(element).data(name); // Fallback to HTML5 data attribs. + } + return $(element).data(name); // Fallback to HTML5 data attribs. + } else { + return Utils.__cache[id]; + } + }; + + Utils.RemoveData = function (element) { + // Removes all cached items for a specified element. + var id = Utils.GetUniqueElementId(element); + if (Utils.__cache[id] != null) { + delete Utils.__cache[id]; + } + }; + return Utils; }); S2.define('select2/results',[ 'jquery', @@ -905,11 +966,11 @@ .find('.select2-results__option[aria-selected]'); $options.each(function () { var $option = $(this); - var item = $.data(this, 'data'); + var item = Utils.GetData(this, 'data'); // id needs to be converted to a string when comparing var id = '' + item.id; if ((item.element != null && item.element.selected) || @@ -1010,11 +1071,11 @@ $option.append($childrenContainer); } else { this.template(data, option); } - $.data(option, 'data', data); + Utils.StoreData(option, 'data', data); return option; }; Results.prototype.bind = function (container, $container) { @@ -1096,11 +1157,11 @@ if ($highlighted.length === 0) { return; } - var data = $highlighted.data('data'); + var data = Utils.GetData($highlighted[0], 'data'); if ($highlighted.attr('aria-selected') == 'true') { self.trigger('close', {}); } else { self.trigger('select', { @@ -1115,11 +1176,12 @@ var $options = self.$results.find('[aria-selected]'); var currentIndex = $options.index($highlighted); // If we are already at te top, don't move further - if (currentIndex === 0) { + // If no options, currentIndex will be -1 + if (currentIndex <= 0) { return; } var nextIndex = currentIndex - 1; @@ -1208,11 +1270,11 @@ this.$results.on('mouseup', '.select2-results__option[aria-selected]', function (evt) { var $this = $(this); - var data = $this.data('data'); + var data = Utils.GetData(this, 'data'); if ($this.attr('aria-selected') === 'true') { if (self.options.get('multiple')) { self.trigger('unselect', { originalEvent: evt, @@ -1231,11 +1293,11 @@ }); }); this.$results.on('mouseenter', '.select2-results__option[aria-selected]', function (evt) { - var data = $(this).data('data'); + var data = Utils.GetData(this, 'data'); self.getHighlightedResults() .removeClass('select2-results__option--highlighted'); self.trigger('results:focus', { @@ -1346,12 +1408,12 @@ '</span>' ); this._tabindex = 0; - if (this.$element.data('old-tabindex') != null) { - this._tabindex = this.$element.data('old-tabindex'); + if (Utils.GetData(this.$element[0], 'old-tabindex') != null) { + this._tabindex = Utils.GetData(this.$element[0], 'old-tabindex'); } else if (this.$element.attr('tabindex') != null) { this._tabindex = this.$element.attr('tabindex'); } $selection.attr('title', this.$element.attr('title')); @@ -1407,10 +1469,13 @@ self.$selection.attr('aria-expanded', 'false'); self.$selection.removeAttr('aria-activedescendant'); self.$selection.removeAttr('aria-owns'); self.$selection.focus(); + window.setTimeout(function () { + self.$selection.focus(); + }, 0); self._detachCloseHandler(container); }); container.on('enable', function () { @@ -1455,11 +1520,11 @@ if (this == $select[0]) { return; } - var $element = $this.data('element'); + var $element = Utils.GetData(this, 'element'); $element.select2('close'); }); }); }; @@ -1516,11 +1581,14 @@ SingleSelection.__super__.bind.apply(this, arguments); var id = container.id + '-container'; - this.$selection.find('.select2-selection__rendered').attr('id', id); + this.$selection.find('.select2-selection__rendered') + .attr('id', id) + .attr('role', 'textbox') + .attr('aria-readonly', 'true'); this.$selection.attr('aria-labelledby', id); this.$selection.on('mousedown', function (evt) { // Only respond to left clicks if (evt.which !== 1) { @@ -1543,18 +1611,16 @@ container.on('focus', function (evt) { if (!container.isOpen()) { self.$selection.focus(); } }); - - container.on('selection:update', function (params) { - self.update(params.data); - }); }; SingleSelection.prototype.clear = function () { - this.$selection.find('.select2-selection__rendered').empty(); + var $rendered = this.$selection.find('.select2-selection__rendered'); + $rendered.empty(); + $rendered.removeAttr('title'); // clear tooltip on empty }; SingleSelection.prototype.display = function (data, container) { var template = this.options.get('templateSelection'); var escapeMarkup = this.options.get('escapeMarkup'); @@ -1576,11 +1642,11 @@ var $rendered = this.$selection.find('.select2-selection__rendered'); var formatted = this.display(selection, $rendered); $rendered.empty().append(formatted); - $rendered.prop('title', selection.title || selection.text); + $rendered.attr('title', selection.title || selection.text); }; return SingleSelection; }); @@ -1628,22 +1694,24 @@ } var $remove = $(this); var $selection = $remove.parent(); - var data = $selection.data('data'); + var data = Utils.GetData($selection[0], 'data'); self.trigger('unselect', { originalEvent: evt, data: data }); } ); }; MultipleSelection.prototype.clear = function () { - this.$selection.find('.select2-selection__rendered').empty(); + var $rendered = this.$selection.find('.select2-selection__rendered'); + $rendered.empty(); + $rendered.removeAttr('title'); }; MultipleSelection.prototype.display = function (data, container) { var template = this.options.get('templateSelection'); var escapeMarkup = this.options.get('escapeMarkup'); @@ -1677,13 +1745,13 @@ var $selection = this.selectionContainer(); var formatted = this.display(selection, $selection); $selection.append(formatted); - $selection.prop('title', selection.title || selection.text); + $selection.attr('title', selection.title || selection.text); - $selection.data('data', selection); + Utils.StoreData($selection[0], 'data', selection); $selections.push($selection); } var $rendered = this.$selection.find('.select2-selection__rendered'); @@ -1744,12 +1812,13 @@ return Placeholder; }); S2.define('select2/selection/allowClear',[ 'jquery', - '../keys' -], function ($, KEYS) { + '../keys', + '../utils' +], function ($, KEYS, Utils) { function AllowClear () { } AllowClear.prototype.bind = function (decorated, container, $container) { var self = this; @@ -1787,28 +1856,41 @@ return; } evt.stopPropagation(); - var data = $clear.data('data'); + var data = Utils.GetData($clear[0], 'data'); + var previousVal = this.$element.val(); + this.$element.val(this.placeholder.id); + + var unselectData = { + data: data + }; + this.trigger('clear', unselectData); + if (unselectData.prevented) { + this.$element.val(previousVal); + return; + } + for (var d = 0; d < data.length; d++) { - var unselectData = { + unselectData = { data: data[d] }; // Trigger the `unselect` event, so people can prevent it from being // cleared. this.trigger('unselect', unselectData); // If the event was prevented, don't clear it out. if (unselectData.prevented) { + this.$element.val(previousVal); return; } } - this.$element.val(this.placeholder.id).trigger('change'); + this.$element.trigger('change'); this.trigger('toggle', {}); }; AllowClear.prototype._handleKeyboardClear = function (_, evt, container) { @@ -1832,11 +1914,11 @@ var $remove = $( '<span class="select2-selection__clear">' + '&times;' + '</span>' ); - $remove.data('data', data); + Utils.StoreData($remove[0], 'data', data); this.$selection.find('.select2-selection__rendered').prepend($remove); }; return AllowClear; @@ -1853,11 +1935,11 @@ Search.prototype.render = function (decorated) { var $search = $( '<li class="select2-search select2-search--inline">' + '<input class="select2-search__field" type="search" tabindex="-1"' + - ' autocomplete="off" autocorrect="off" autocapitalize="off"' + + ' autocomplete="off" autocorrect="off" autocapitalize="none"' + ' spellcheck="false" role="textbox" aria-autocomplete="list" />' + '</li>' ); this.$searchContainer = $search; @@ -1923,11 +2005,11 @@ if (key === KEYS.BACKSPACE && self.$search.val() === '') { var $previousChoice = self.$searchContainer .prev('.select2-selection__choice'); if ($previousChoice.length > 0) { - var item = $previousChoice.data('data'); + var item = Utils.GetData($previousChoice[0], 'data'); self.searchRemoveChoice(item); evt.preventDefault(); } @@ -2017,11 +2099,17 @@ this.$selection.find('.select2-selection__rendered') .append(this.$searchContainer); this.resizeSearch(); if (searchHadFocus) { - this.$search.focus(); + var isTagInput = this.$element.find('[data-select2-tag]').length; + if (isTagInput) { + // fix IE11 bug where tag input lost focus + this.$element.focus(); + } else { + this.$search.focus(); + } } }; Search.prototype.handleSearch = function () { this.resizeSearch(); @@ -2074,14 +2162,17 @@ var self = this; var relayEvents = [ 'open', 'opening', 'close', 'closing', 'select', 'selecting', - 'unselect', 'unselecting' + 'unselect', 'unselecting', + 'clear', 'clearing' ]; - var preventableEvents = ['opening', 'closing', 'selecting', 'unselecting']; + var preventableEvents = [ + 'opening', 'closing', 'selecting', 'unselecting', 'clearing' + ]; decorated.call(this, container, $container); container.on('*', function (name, params) { // Ignore events that should not be relayed @@ -3156,11 +3247,11 @@ SelectAdapter.prototype.destroy = function () { // Remove anything added to child elements this.$element.find('*').each(function () { // Remove any custom data set by Select2 - $.removeData(this, 'data'); + Utils.RemoveData(this); }); }; SelectAdapter.prototype.query = function (params, callback) { var data = []; @@ -3229,19 +3320,19 @@ var normalizedData = this._normalizeItem(data); normalizedData.element = option; // Override the option's data with the combined data - $.data(option, 'data', normalizedData); + Utils.StoreData(option, 'data', normalizedData); return $option; }; SelectAdapter.prototype.item = function ($option) { var data = {}; - data = $.data($option[0], 'data'); + data = Utils.GetData($option[0], 'data'); if (data != null) { return data; } @@ -3275,17 +3366,17 @@ } data = this._normalizeItem(data); data.element = $option[0]; - $.data($option[0], 'data', data); + Utils.StoreData($option[0], 'data', data); return data; }; SelectAdapter.prototype._normalizeItem = function (item) { - if (!$.isPlainObject(item)) { + if (item !== Object(item)) { item = { id: item, text: item }; } @@ -3485,11 +3576,12 @@ callback(results); }, function () { // Attempt to detect if a request was aborted // Only works if the transport exposes a status property - if ($request.status && $request.status === '0') { + if ('status' in $request && + ($request.status === 0 || $request.status === '0')) { return; } self.trigger('results:message', { message: 'errorLoading' @@ -3907,11 +3999,11 @@ var $rendered = decorated.call(this); var $search = $( '<span class="select2-search select2-search--dropdown">' + '<input class="select2-search__field" type="search" tabindex="-1"' + - ' autocomplete="off" autocorrect="off" autocapitalize="off"' + + ' autocomplete="off" autocorrect="off" autocapitalize="none"' + ' spellcheck="false" role="textbox" />' + '</span>' ); this.$searchContainer = $search; @@ -3957,10 +4049,11 @@ container.on('close', function () { self.$search.attr('tabindex', -1); self.$search.val(''); + self.$search.blur(); }); container.on('focus', function () { if (!container.isOpen()) { self.$search.focus(); @@ -4222,18 +4315,18 @@ var resizeEvent = 'resize.select2.' + container.id; var orientationEvent = 'orientationchange.select2.' + container.id; var $watchers = this.$container.parents().filter(Utils.hasScroll); $watchers.each(function () { - $(this).data('select2-scroll-position', { + Utils.StoreData(this, 'select2-scroll-position', { x: $(this).scrollLeft(), y: $(this).scrollTop() }); }); $watchers.on(scrollEvent, function (ev) { - var position = $(this).data('select2-scroll-position'); + var position = Utils.GetData(this, 'select2-scroll-position'); $(this).scrollTop(position.y); }); $(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent, function (e) { @@ -4394,12 +4487,12 @@ return MinimumResultsForSearch; }); S2.define('select2/dropdown/selectOnClose',[ - -], function () { + '../utils' +], function (Utils) { function SelectOnClose () { } SelectOnClose.prototype.bind = function (decorated, container, $container) { var self = this; @@ -4426,11 +4519,11 @@ // Only select highlighted results if ($highlightedResults.length < 1) { return; } - var data = $highlightedResults.data('data'); + var data = Utils.GetData($highlightedResults[0], 'data'); // Don't re-select already selected resulte if ( (data.element != null && data.element.selected) || (data.element == null && data.selected) @@ -4914,11 +5007,11 @@ var data = {}; data[camelKey] = value; var convertedData = Utils._convertData(data); - $.extend(this.defaults, convertedData); + $.extend(true, this.defaults, convertedData); }; var defaults = new Defaults(); return defaults; @@ -4979,44 +5072,45 @@ } $e.prop('disabled', this.options.disabled); $e.prop('multiple', this.options.multiple); - if ($e.data('select2Tags')) { + if (Utils.GetData($e[0], 'select2Tags')) { if (this.options.debug && window.console && console.warn) { console.warn( 'Select2: The `data-select2-tags` attribute has been changed to ' + 'use the `data-data` and `data-tags="true"` attributes and will be ' + 'removed in future versions of Select2.' ); } - $e.data('data', $e.data('select2Tags')); - $e.data('tags', true); + Utils.StoreData($e[0], 'data', Utils.GetData($e[0], 'select2Tags')); + Utils.StoreData($e[0], 'tags', true); } - if ($e.data('ajaxUrl')) { + if (Utils.GetData($e[0], 'ajaxUrl')) { if (this.options.debug && window.console && console.warn) { console.warn( 'Select2: The `data-ajax-url` attribute has been changed to ' + '`data-ajax--url` and support for the old attribute will be removed' + ' in future versions of Select2.' ); } - $e.attr('ajax--url', $e.data('ajaxUrl')); - $e.data('ajax--url', $e.data('ajaxUrl')); + $e.attr('ajax--url', Utils.GetData($e[0], 'ajaxUrl')); + Utils.StoreData($e[0], 'ajax-Url', Utils.GetData($e[0], 'ajaxUrl')); + } var dataset = {}; // Prefer the element's `dataset` attribute if it exists // jQuery 1.x does not correctly handle data attributes with multiple dashes if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) { - dataset = $.extend(true, {}, $e[0].dataset, $e.data()); + dataset = $.extend(true, {}, $e[0].dataset, Utils.GetData($e[0])); } else { - dataset = $e.data(); + dataset = Utils.GetData($e[0]); } var data = $.extend(true, {}, dataset); data = Utils._convertData(data); @@ -5052,12 +5146,12 @@ './options', './utils', './keys' ], function ($, Options, Utils, KEYS) { var Select2 = function ($element, options) { - if ($element.data('select2') != null) { - $element.data('select2').destroy(); + if (Utils.GetData($element[0], 'select2') != null) { + Utils.GetData($element[0], 'select2').destroy(); } this.$element = $element; this.id = this._generateId($element); @@ -5069,11 +5163,11 @@ Select2.__super__.constructor.call(this); // Set up the tabindex var tabindex = $element.attr('tabindex') || 0; - $element.data('old-tabindex', tabindex); + Utils.StoreData($element[0], 'old-tabindex', tabindex); $element.attr('tabindex', '-1'); // Set up containers and adapters var DataAdapter = this.options.get('dataAdapter'); @@ -5130,10 +5224,13 @@ $element.attr('aria-hidden', 'true'); // Synchronize any monitored attributes this._syncAttributes(); + Utils.StoreData($element[0], 'select2', this); + + // Ensure backwards compatibility with $element.data('select2'). $element.data('select2', this); }; Utils.Extend(Select2, Utils.Observable); @@ -5464,11 +5561,12 @@ var actualTrigger = Select2.__super__.trigger; var preTriggerMap = { 'open': 'opening', 'close': 'closing', 'select': 'selecting', - 'unselect': 'unselecting' + 'unselect': 'unselecting', + 'clear': 'clearing' }; if (args === undefined) { args = {}; } @@ -5619,14 +5717,16 @@ this._syncA = null; this._syncS = null; this.$element.off('.select2'); - this.$element.attr('tabindex', this.$element.data('old-tabindex')); + this.$element.attr('tabindex', + Utils.GetData(this.$element[0], 'old-tabindex')); this.$element.removeClass('select2-hidden-accessible'); this.$element.attr('aria-hidden', 'false'); + Utils.RemoveData(this.$element[0]); this.$element.removeData('select2'); this.dataAdapter.destroy(); this.selection.destroy(); this.dropdown.destroy(); @@ -5650,11 +5750,11 @@ this.$container = $container; this.$container.addClass('select2-container--' + this.options.get('theme')); - $container.data('element', this.$element); + Utils.StoreData($container[0], 'element', this.$element); return $container; }; return Select2; @@ -5670,12 +5770,13 @@ S2.define('jquery.select2',[ 'jquery', 'jquery-mousewheel', './select2/core', - './select2/defaults' -], function ($, _, Select2, Defaults) { + './select2/defaults', + './select2/utils' +], function ($, _, Select2, Defaults, Utils) { if ($.fn.select2 == null) { // All methods that should return the element var thisMethods = ['open', 'close', 'destroy']; $.fn.select2 = function (options) { @@ -5692,10 +5793,10 @@ } else if (typeof options === 'string') { var ret; var args = Array.prototype.slice.call(arguments, 1); this.each(function () { - var instance = $(this).data('select2'); + var instance = Utils.GetData(this, 'select2'); if (instance == null && window.console && console.error) { console.error( 'The select2(\'' + options + '\') method was called on an ' + 'element that is not using Select2.'