diff options
Diffstat (limited to 'ishtar_common/static/select2/js/select2.full.js')
| -rw-r--r-- | ishtar_common/static/select2/js/select2.full.js | 956 |
1 files changed, 670 insertions, 286 deletions
diff --git a/ishtar_common/static/select2/js/select2.full.js b/ishtar_common/static/select2/js/select2.full.js index e750834ef..358572a65 100644 --- a/ishtar_common/static/select2/js/select2.full.js +++ b/ishtar_common/static/select2/js/select2.full.js @@ -1,27 +1,41 @@ /*! - * Select2 4.0.3 + * Select2 4.0.13 * 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 exports === 'object') { + } else if (typeof module === 'object' && module.exports) { // Node/CommonJS - factory(require('jquery')); + module.exports = function (root, jQuery) { + if (jQuery === undefined) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if (typeof window !== 'undefined') { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + factory(jQuery); + return jQuery; + }; } else { // Browser globals factory(jQuery); } -}(function (jQuery) { +} (function (jQuery) { // This is needed so we can catch the AMD loader configuration and use it // The inner file should be wrapped (by `banner.start.js`) in a function that // returns the AMD loader references. - var S2 = -(function () { + var S2 =(function () { // Restore the Select2 AMD loader so it can be used // Needed mostly in the language files, where the loader is not inserted if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) { @@ -30,13 +44,11 @@ var S2;(function () { if (!S2 || !S2.requirejs) { if (!S2) { S2 = {}; } else { require = S2; } /** - * @license almond 0.3.1 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved. - * Available via the MIT or new BSD license. - * see: http://github.com/jrburke/almond for details + * @license almond 0.3.3 Copyright jQuery Foundation and other contributors. + * Released under MIT license, http://github.com/requirejs/almond/LICENSE */ //Going sloppy to avoid 'use strict' string cost, but strict practices should //be followed. -/*jslint sloppy: true */ /*global setTimeout: false */ var requirejs, require, define; @@ -64,60 +76,58 @@ var requirejs, require, define; */ function normalize(name, baseName) { var nameParts, nameSegment, mapValue, foundMap, lastIndex, - foundI, foundStarMap, starI, i, j, part, + foundI, foundStarMap, starI, i, j, part, normalizedBaseParts, baseParts = baseName && baseName.split("/"), map = config.map, starMap = (map && map['*']) || {}; //Adjust any relative paths. - if (name && name.charAt(0) === ".") { - //If have a base name, try to normalize against it, - //otherwise, assume it is a top-level require that will - //be relative to baseUrl in the end. - if (baseName) { - name = name.split('/'); - lastIndex = name.length - 1; - - // Node .js allowance: - if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) { - name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ''); - } + if (name) { + name = name.split('/'); + lastIndex = name.length - 1; + + // If wanting node ID compatibility, strip .js from end + // of IDs. Have to do this here, and not in nameToUrl + // because node allows either .js or non .js to map + // to same file. + if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) { + name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ''); + } - //Lop off the last part of baseParts, so that . matches the - //"directory" and not name of the baseName's module. For instance, - //baseName of "one/two/three", maps to "one/two/three.js", but we - //want the directory, "one/two" for this normalization. - name = baseParts.slice(0, baseParts.length - 1).concat(name); - - //start trimDots - for (i = 0; i < name.length; i += 1) { - part = name[i]; - if (part === ".") { - name.splice(i, 1); - i -= 1; - } else if (part === "..") { - if (i === 1 && (name[2] === '..' || name[0] === '..')) { - //End of the line. Keep at least one non-dot - //path segment at the front so it can be mapped - //correctly to disk. Otherwise, there is likely - //no path mapping for a path starting with '..'. - //This can still fail, but catches the most reasonable - //uses of .. - break; - } else if (i > 0) { - name.splice(i - 1, 2); - i -= 2; - } + // Starts with a '.' so need the baseName + if (name[0].charAt(0) === '.' && baseParts) { + //Convert baseName to array, and lop off the last part, + //so that . matches that 'directory' and not name of the baseName's + //module. For instance, baseName of 'one/two/three', maps to + //'one/two/three.js', but we want the directory, 'one/two' for + //this normalization. + normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); + name = normalizedBaseParts.concat(name); + } + + //start trimDots + for (i = 0; i < name.length; i++) { + part = name[i]; + if (part === '.') { + name.splice(i, 1); + i -= 1; + } else if (part === '..') { + // If at the start, or previous value is still .., + // keep them so that when converted to a path it may + // still work when converted to a path, even though + // as an ID it is less than ideal. In larger point + // releases, may be better to just kick out an error. + if (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') { + continue; + } else if (i > 0) { + name.splice(i - 1, 2); + i -= 2; } } - //end trimDots - - name = name.join("/"); - } else if (name.indexOf('./') === 0) { - // No baseName, so this is ID is resolved relative - // to baseUrl, pull off the leading dot. - name = name.substring(2); } + //end trimDots + + name = name.join('/'); } //Apply map config if available. @@ -230,32 +240,39 @@ var requirejs, require, define; return [prefix, name]; } + //Creates a parts array for a relName where first part is plugin ID, + //second part is resource ID. Assumes relName has already been normalized. + function makeRelParts(relName) { + return relName ? splitPrefix(relName) : []; + } + /** * Makes a name map, normalizing the name, and using a plugin * for normalization if necessary. Grabs a ref to plugin * too, as an optimization. */ - makeMap = function (name, relName) { + makeMap = function (name, relParts) { var plugin, parts = splitPrefix(name), - prefix = parts[0]; + prefix = parts[0], + relResourceName = relParts[1]; name = parts[1]; if (prefix) { - prefix = normalize(prefix, relName); + prefix = normalize(prefix, relResourceName); plugin = callDep(prefix); } //Normalize according if (prefix) { if (plugin && plugin.normalize) { - name = plugin.normalize(name, makeNormalize(relName)); + name = plugin.normalize(name, makeNormalize(relResourceName)); } else { - name = normalize(name, relName); + name = normalize(name, relResourceName); } } else { - name = normalize(name, relName); + name = normalize(name, relResourceName); parts = splitPrefix(name); prefix = parts[0]; name = parts[1]; @@ -302,13 +319,14 @@ var requirejs, require, define; }; main = function (name, deps, callback, relName) { - var cjsModule, depName, ret, map, i, + var cjsModule, depName, ret, map, i, relParts, args = [], callbackType = typeof callback, usingExports; //Use name if no relName relName = relName || name; + relParts = makeRelParts(relName); //Call the callback to define the module, if necessary. if (callbackType === 'undefined' || callbackType === 'function') { @@ -317,7 +335,7 @@ var requirejs, require, define; //Default to [require, exports, module] if no deps deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps; for (i = 0; i < deps.length; i += 1) { - map = makeMap(deps[i], relName); + map = makeMap(deps[i], relParts); depName = map.f; //Fast path CommonJS standard dependencies. @@ -373,7 +391,7 @@ var requirejs, require, define; //deps arg is the module name, and second arg (if passed) //is just the relName. //Normalize module name, if it contains . or .. - return callDep(makeMap(deps, callback).f); + return callDep(makeMap(deps, makeRelParts(callback)).f); } else if (!deps.splice) { //deps is a config object, not an array. config = deps; @@ -556,10 +574,10 @@ S2.define('select2/utils',[ 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) { @@ -754,6 +772,70 @@ S2.define('select2/utils',[ $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]) { + if (Utils.__cache[id][name] != null) { + return Utils.__cache[id][name]; + } + return $(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]; + } + + element.removeAttribute('data-select2-id'); + }; + return Utils; }); @@ -773,7 +855,7 @@ S2.define('select2/results',[ Results.prototype.render = function () { var $results = $( - '<ul class="select2-results__options" role="tree"></ul>' + '<ul class="select2-results__options" role="listbox"></ul>' ); if (this.options.get('multiple')) { @@ -796,7 +878,7 @@ S2.define('select2/results',[ this.hideLoading(); var $message = $( - '<li role="treeitem" aria-live="assertive"' + + '<li role="alert" aria-live="assertive"' + ' class="select2-results__option"></li>' ); @@ -889,7 +971,7 @@ S2.define('select2/results',[ $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; @@ -930,11 +1012,16 @@ S2.define('select2/results',[ option.className = 'select2-results__option'; var attrs = { - 'role': 'treeitem', + 'role': 'option', 'aria-selected': 'false' }; - if (data.disabled) { + var matches = window.Element.prototype.matches || + window.Element.prototype.msMatchesSelector || + window.Element.prototype.webkitMatchesSelector; + + if ((data.element != null && matches.call(data.element, ':disabled')) || + (data.element == null && data.disabled)) { delete attrs['aria-selected']; attrs['aria-disabled'] = 'true'; } @@ -994,7 +1081,7 @@ S2.define('select2/results',[ this.template(data, option); } - $.data(option, 'data', data); + Utils.StoreData(option, 'data', data); return option; }; @@ -1035,7 +1122,10 @@ S2.define('select2/results',[ } self.setClasses(); - self.highlightFirstItem(); + + if (self.options.get('scrollAfterSelect')) { + self.highlightFirstItem(); + } }); container.on('unselect', function () { @@ -1044,7 +1134,10 @@ S2.define('select2/results',[ } self.setClasses(); - self.highlightFirstItem(); + + if (self.options.get('scrollAfterSelect')) { + self.highlightFirstItem(); + } }); container.on('open', function () { @@ -1080,7 +1173,7 @@ S2.define('select2/results',[ return; } - var data = $highlighted.data('data'); + var data = Utils.GetData($highlighted[0], 'data'); if ($highlighted.attr('aria-selected') == 'true') { self.trigger('close', {}); @@ -1098,8 +1191,9 @@ S2.define('select2/results',[ var currentIndex = $options.index($highlighted); - // If we are already at te top, don't move further - if (currentIndex === 0) { + // If we are already at the top, don't move further + // If no options, currentIndex will be -1 + if (currentIndex <= 0) { return; } @@ -1192,7 +1286,7 @@ S2.define('select2/results',[ 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')) { @@ -1215,7 +1309,7 @@ S2.define('select2/results',[ 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'); @@ -1330,14 +1424,15 @@ S2.define('select2/selection/base',[ 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')); $selection.attr('tabindex', this._tabindex); + $selection.attr('aria-disabled', 'false'); this.$selection = $selection; @@ -1347,7 +1442,6 @@ S2.define('select2/selection/base',[ BaseSelection.prototype.bind = function (container, $container) { var self = this; - var id = container.id + '-container'; var resultsId = container.id + '-results'; this.container = container; @@ -1390,17 +1484,19 @@ S2.define('select2/selection/base',[ self.$selection.removeAttr('aria-activedescendant'); self.$selection.removeAttr('aria-owns'); - self.$selection.focus(); + self.$selection.trigger('focus'); self._detachCloseHandler(container); }); container.on('enable', function () { self.$selection.attr('tabindex', self._tabindex); + self.$selection.attr('aria-disabled', 'false'); }); container.on('disable', function () { self.$selection.attr('tabindex', '-1'); + self.$selection.attr('aria-disabled', 'true'); }); }; @@ -1423,7 +1519,6 @@ S2.define('select2/selection/base',[ }; BaseSelection.prototype._attachCloseHandler = function (container) { - var self = this; $(document.body).on('mousedown.select2.' + container.id, function (e) { var $target = $(e.target); @@ -1433,13 +1528,11 @@ S2.define('select2/selection/base',[ var $all = $('.select2.select2-container--open'); $all.each(function () { - var $this = $(this); - if (this == $select[0]) { return; } - var $element = $this.data('element'); + var $element = Utils.GetData(this, 'element'); $element.select2('close'); }); @@ -1463,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; }); @@ -1500,7 +1614,10 @@ S2.define('select2/selection/single',[ 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) { @@ -1524,17 +1641,15 @@ S2.define('select2/selection/single',[ container.on('focus', function (evt) { if (!container.isOpen()) { - self.$selection.focus(); + self.$selection.trigger('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) { @@ -1560,7 +1675,14 @@ S2.define('select2/selection/single',[ var formatted = this.display(selection, $rendered); $rendered.empty().append(formatted); - $rendered.prop('title', selection.title || selection.text); + + var title = selection.title || selection.text; + + if (title) { + $rendered.attr('title', title); + } else { + $rendered.removeAttr('title'); + } }; return SingleSelection; @@ -1605,14 +1727,14 @@ 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; } var $remove = $(this); var $selection = $remove.parent(); - var data = $selection.data('data'); + var data = Utils.GetData($selection[0], 'data'); self.trigger('unselect', { originalEvent: evt, @@ -1623,7 +1745,9 @@ S2.define('select2/selection/multiple',[ }; 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) { @@ -1661,9 +1785,14 @@ S2.define('select2/selection/multiple',[ var formatted = this.display(selection, $selection); $selection.append(formatted); - $selection.prop('title', selection.title || selection.text); - $selection.data('data', selection); + var title = selection.title || selection.text; + + if (title) { + $selection.attr('title', title); + } + + Utils.StoreData($selection[0], 'data', selection); $selections.push($selection); } @@ -1728,8 +1857,9 @@ S2.define('select2/selection/placeholder',[ S2.define('select2/selection/allowClear',[ 'jquery', - '../keys' -], function ($, KEYS) { + '../keys', + '../utils' +], function ($, KEYS, Utils) { function AllowClear () { } AllowClear.prototype.bind = function (decorated, container, $container) { @@ -1758,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; } @@ -1771,10 +1901,22 @@ S2.define('select2/selection/allowClear',[ 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] }; @@ -1784,11 +1926,12 @@ S2.define('select2/selection/allowClear',[ // 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('input').trigger('change'); this.trigger('toggle', {}); }; @@ -1811,12 +1954,14 @@ S2.define('select2/selection/allowClear',[ return; } + var removeAll = this.options.get('translations').get('removeAllItems'); + var $remove = $( - '<span class="select2-selection__clear">' + + '<span class="select2-selection__clear" title="' + removeAll() +'">' + '×' + '</span>' ); - $remove.data('data', data); + Utils.StoreData($remove[0], 'data', data); this.$selection.find('.select2-selection__rendered').prepend($remove); }; @@ -1837,8 +1982,8 @@ S2.define('select2/selection/search',[ var $search = $( '<li class="select2-search select2-search--inline">' + '<input class="select2-search__field" type="search" tabindex="-1"' + - ' autocomplete="off" autocorrect="off" autocapitalize="off"' + - ' spellcheck="false" role="textbox" aria-autocomplete="list" />' + + ' autocomplete="off" autocorrect="off" autocapitalize="none"' + + ' spellcheck="false" role="searchbox" aria-autocomplete="list" />' + '</li>' ); @@ -1855,14 +2000,18 @@ S2.define('select2/selection/search',[ Search.prototype.bind = function (decorated, container, $container) { var self = this; + var resultsId = container.id + '-results'; + decorated.call(this, container, $container); container.on('open', function () { + self.$search.attr('aria-controls', resultsId); self.$search.trigger('focus'); }); container.on('close', function () { self.$search.val(''); + self.$search.removeAttr('aria-controls'); self.$search.removeAttr('aria-activedescendant'); self.$search.trigger('focus'); }); @@ -1882,7 +2031,11 @@ S2.define('select2/selection/search',[ }); container.on('results:focus', function (params) { - self.$search.attr('aria-activedescendant', params.id); + if (params.data._resultId) { + self.$search.attr('aria-activedescendant', params.data._resultId); + } else { + self.$search.removeAttr('aria-activedescendant'); + } }); this.$selection.on('focusin', '.select2-search--inline', function (evt) { @@ -1907,7 +2060,7 @@ S2.define('select2/selection/search',[ .prev('.select2-selection__choice'); if ($previousChoice.length > 0) { - var item = $previousChoice.data('data'); + var item = Utils.GetData($previousChoice[0], 'data'); self.searchRemoveChoice(item); @@ -1916,6 +2069,12 @@ S2.define('select2/selection/search',[ } }); + this.$selection.on('click', '.select2-search--inline', function (evt) { + if (self.$search.val()) { + evt.stopPropagation(); + } + }); + // Try to detect the IE version should the `documentMode` property that // is stored on the document. This is only implemented in IE and is // slightly cleaner than doing a user agent check. @@ -2001,7 +2160,7 @@ S2.define('select2/selection/search',[ this.resizeSearch(); if (searchHadFocus) { - this.$search.focus(); + this.$search.trigger('focus'); } }; @@ -2034,7 +2193,7 @@ S2.define('select2/selection/search',[ var width = ''; if (this.$search.attr('placeholder') !== '') { - width = this.$selection.find('.select2-selection__rendered').innerWidth(); + width = this.$selection.find('.select2-selection__rendered').width(); } else { var minimumWidth = this.$search.val().length + 1; @@ -2058,10 +2217,13 @@ S2.define('select2/selection/eventRelay',[ '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); @@ -2394,6 +2556,7 @@ S2.define('select2/diacritics',[ '\u019F': 'O', '\uA74A': 'O', '\uA74C': 'O', + '\u0152': 'OE', '\u01A2': 'OI', '\uA74E': 'OO', '\u0222': 'OU', @@ -2803,6 +2966,7 @@ S2.define('select2/diacritics',[ '\uA74B': 'o', '\uA74D': 'o', '\u0275': 'o', + '\u0153': 'oe', '\u01A3': 'oi', '\u0223': 'ou', '\uA74F': 'oo', @@ -2971,8 +3135,9 @@ S2.define('select2/diacritics',[ '\u03CD': '\u03C5', '\u03CB': '\u03C5', '\u03B0': '\u03C5', - '\u03C9': '\u03C9', - '\u03C2': '\u03C3' + '\u03CE': '\u03C9', + '\u03C2': '\u03C3', + '\u2019': '\'' }; return diacritics; @@ -3057,7 +3222,7 @@ S2.define('select2/data/select',[ if ($(data.element).is('option')) { data.element.selected = true; - this.$element.trigger('change'); + this.$element.trigger('input').trigger('change'); return; } @@ -3078,13 +3243,13 @@ S2.define('select2/data/select',[ } self.$element.val(val); - self.$element.trigger('change'); + self.$element.trigger('input').trigger('change'); }); } else { var val = data.id; this.$element.val(val); - this.$element.trigger('change'); + this.$element.trigger('input').trigger('change'); } }; @@ -3100,7 +3265,7 @@ S2.define('select2/data/select',[ if ($(data.element).is('option')) { data.element.selected = false; - this.$element.trigger('change'); + this.$element.trigger('input').trigger('change'); return; } @@ -3118,7 +3283,7 @@ S2.define('select2/data/select',[ self.$element.val(val); - self.$element.trigger('change'); + self.$element.trigger('input').trigger('change'); }); }; @@ -3140,7 +3305,7 @@ S2.define('select2/data/select',[ // Remove anything added to child elements this.$element.find('*').each(function () { // Remove any custom data set by Select2 - $.removeData(this, 'data'); + Utils.RemoveData(this); }); }; @@ -3191,7 +3356,7 @@ S2.define('select2/data/select',[ } } - if (data.id) { + if (data.id !== undefined) { option.value = data.id; } @@ -3213,7 +3378,7 @@ S2.define('select2/data/select',[ normalizedData.element = option; // Override the option's data with the combined data - $.data(option, 'data', normalizedData); + Utils.StoreData(option, 'data', normalizedData); return $option; }; @@ -3221,7 +3386,7 @@ S2.define('select2/data/select',[ SelectAdapter.prototype.item = function ($option) { var data = {}; - data = $.data($option[0], 'data'); + data = Utils.GetData($option[0], 'data'); if (data != null) { return data; @@ -3259,13 +3424,13 @@ S2.define('select2/data/select',[ 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 @@ -3311,15 +3476,19 @@ S2.define('select2/data/array',[ 'jquery' ], function (SelectAdapter, Utils, $) { function ArrayAdapter ($element, options) { - var data = options.get('data') || []; + this._dataToConvert = options.get('data') || []; ArrayAdapter.__super__.constructor.call(this, $element, options); - - this.addOptions(this.convertToOptions(data)); } Utils.Extend(ArrayAdapter, SelectAdapter); + ArrayAdapter.prototype.bind = function (container, $container) { + ArrayAdapter.__super__.bind.call(this, container, $container); + + this.addOptions(this.convertToOptions(this._dataToConvert)); + }; + ArrayAdapter.prototype.select = function (data) { var $option = this.$element.find('option').filter(function (i, elm) { return elm.value == data.id.toString(); @@ -3469,7 +3638,8 @@ S2.define('select2/data/ajax',[ }, 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; } @@ -3550,7 +3720,10 @@ S2.define('select2/data/tags',[ }, true) ); - var checkText = option.text === params.term; + var optionText = (option.text || '').toUpperCase(); + var paramsTerm = (params.term || '').toUpperCase(); + + var checkText = optionText === paramsTerm; if (checkText || checkChildren) { if (child) { @@ -3605,8 +3778,6 @@ S2.define('select2/data/tags',[ }; Tags.prototype._removeOldTags = function (_) { - var tag = this._lastTag; - var $options = this.$element.find('option[data-select2-tag]'); $options.each(function () { @@ -3681,7 +3852,7 @@ S2.define('select2/data/tokenizer',[ // Replace the search term if we have the search box if (this.$search.length) { this.$search.val(tokenData.term); - this.$search.focus(); + this.$search.trigger('focus'); } params.term = tokenData.term; @@ -3810,10 +3981,30 @@ S2.define('select2/data/maximumSelectionLength',[ decorated.call(this, $e, options); } + MaximumSelectionLength.prototype.bind = + function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('select', function () { + self._checkIfMaximumSelected(); + }); + }; + MaximumSelectionLength.prototype.query = function (decorated, params, callback) { var self = this; + this._checkIfMaximumSelected(function () { + decorated.call(self, params, callback); + }); + }; + + MaximumSelectionLength.prototype._checkIfMaximumSelected = + function (_, successCallback) { + var self = this; + this.current(function (currentData) { var count = currentData != null ? currentData.length : 0; if (self.maximumSelectionLength > 0 && @@ -3826,7 +4017,10 @@ S2.define('select2/data/maximumSelectionLength',[ }); return; } - decorated.call(self, params, callback); + + if (successCallback) { + successCallback(); + } }); }; @@ -3865,7 +4059,7 @@ S2.define('select2/dropdown',[ }; Dropdown.prototype.position = function ($dropdown, $container) { - // Should be implmented in subclasses + // Should be implemented in subclasses }; Dropdown.prototype.destroy = function () { @@ -3888,8 +4082,8 @@ S2.define('select2/dropdown/search',[ var $search = $( '<span class="select2-search select2-search--dropdown">' + '<input class="select2-search__field" type="search" tabindex="-1"' + - ' autocomplete="off" autocorrect="off" autocapitalize="off"' + - ' spellcheck="false" role="textbox" />' + + ' autocomplete="off" autocorrect="off" autocapitalize="none"' + + ' spellcheck="false" role="searchbox" aria-autocomplete="list" />' + '</span>' ); @@ -3904,6 +4098,8 @@ S2.define('select2/dropdown/search',[ Search.prototype.bind = function (decorated, container, $container) { var self = this; + var resultsId = container.id + '-results'; + decorated.call(this, container, $container); this.$search.on('keydown', function (evt) { @@ -3926,23 +4122,27 @@ S2.define('select2/dropdown/search',[ container.on('open', function () { self.$search.attr('tabindex', 0); + self.$search.attr('aria-controls', resultsId); - self.$search.focus(); + self.$search.trigger('focus'); window.setTimeout(function () { - self.$search.focus(); + self.$search.trigger('focus'); }, 0); }); container.on('close', function () { self.$search.attr('tabindex', -1); + self.$search.removeAttr('aria-controls'); + self.$search.removeAttr('aria-activedescendant'); self.$search.val(''); + self.$search.trigger('blur'); }); container.on('focus', function () { - if (container.isOpen()) { - self.$search.focus(); + if (!container.isOpen()) { + self.$search.trigger('focus'); } }); @@ -3957,6 +4157,14 @@ S2.define('select2/dropdown/search',[ } } }); + + container.on('results:focus', function (params) { + if (params.data._resultId) { + self.$search.attr('aria-activedescendant', params.data._resultId); + } else { + self.$search.removeAttr('aria-activedescendant'); + } + }); }; Search.prototype.handleSearch = function (evt) { @@ -4041,6 +4249,7 @@ S2.define('select2/dropdown/infiniteScroll',[ if (this.showLoadingMore(data)) { this.$results.append(this.$loadingMore); + this.loadMoreIfNeeded(); } }; @@ -4059,25 +4268,27 @@ S2.define('select2/dropdown/infiniteScroll',[ self.loading = true; }); - this.$results.on('scroll', function () { - var isLoadMoreVisible = $.contains( - document.documentElement, - self.$loadingMore[0] - ); + this.$results.on('scroll', this.loadMoreIfNeeded.bind(this)); + }; - if (self.loading || !isLoadMoreVisible) { - return; - } + InfiniteScroll.prototype.loadMoreIfNeeded = function () { + var isLoadMoreVisible = $.contains( + document.documentElement, + this.$loadingMore[0] + ); - var currentOffset = self.$results.offset().top + - self.$results.outerHeight(false); - var loadingMoreOffset = self.$loadingMore.offset().top + - self.$loadingMore.outerHeight(false); + if (this.loading || !isLoadMoreVisible) { + return; + } - if (currentOffset + 50 >= loadingMoreOffset) { - self.loadMore(); - } - }); + var currentOffset = this.$results.offset().top + + this.$results.outerHeight(false); + var loadingMoreOffset = this.$loadingMore.offset().top + + this.$loadingMore.outerHeight(false); + + if (currentOffset + 50 >= loadingMoreOffset) { + this.loadMore(); + } }; InfiniteScroll.prototype.loadMore = function () { @@ -4098,7 +4309,7 @@ S2.define('select2/dropdown/infiniteScroll',[ var $option = $( '<li ' + 'class="select2-results__option select2-results__option--load-more"' + - 'role="treeitem" aria-disabled="true"></li>' + 'role="option" aria-disabled="true"></li>' ); var message = this.options.get('translations').get('loadingMore'); @@ -4116,7 +4327,7 @@ S2.define('select2/dropdown/attachBody',[ '../utils' ], function ($, Utils) { function AttachBody (decorated, $element, options) { - this.$dropdownParent = options.get('dropdownParent') || $(document.body); + this.$dropdownParent = $(options.get('dropdownParent') || document.body); decorated.call(this, $element, options); } @@ -4124,27 +4335,14 @@ S2.define('select2/dropdown/attachBody',[ AttachBody.prototype.bind = function (decorated, container, $container) { var self = this; - var setupResultsEvents = false; - decorated.call(this, container, $container); container.on('open', function () { self._showDropdown(); self._attachPositioningHandler(container); - if (!setupResultsEvents) { - setupResultsEvents = true; - - container.on('results:all', function () { - self._positionDropdown(); - self._resizeDropdown(); - }); - - container.on('results:append', function () { - self._positionDropdown(); - self._resizeDropdown(); - }); - } + // Must bind after the results handlers to ensure correct sizing + self._bindContainerResultHandlers(container); }); container.on('close', function () { @@ -4193,6 +4391,44 @@ S2.define('select2/dropdown/attachBody',[ this.$dropdownContainer.detach(); }; + AttachBody.prototype._bindContainerResultHandlers = + function (decorated, container) { + + // These should only be bound once + if (this._containerResultsHandlersBound) { + return; + } + + var self = this; + + container.on('results:all', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('results:append', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('results:message', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('select', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('unselect', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + this._containerResultsHandlersBound = true; + }; + AttachBody.prototype._attachPositioningHandler = function (decorated, container) { var self = this; @@ -4203,14 +4439,14 @@ S2.define('select2/dropdown/attachBody',[ 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); }); @@ -4269,16 +4505,26 @@ S2.define('select2/dropdown/attachBody',[ top: container.bottom }; - // Determine what the parent element is to use for calciulating the offset + // Determine what the parent element is to use for calculating the offset var $offsetParent = this.$dropdownParent; - // For statically positoned elements, we need to get the element + // For statically positioned elements, we need to get the element // that is determining the offset if ($offsetParent.css('position') === 'static') { $offsetParent = $offsetParent.offsetParent(); } - var parentOffset = $offsetParent.offset(); + var parentOffset = { + top: 0, + left: 0 + }; + + if ( + $.contains(document.body, $offsetParent[0]) || + $offsetParent[0].isConnected + ) { + parentOffset = $offsetParent.offset(); + } css.top -= parentOffset.top; css.left -= parentOffset.left; @@ -4375,8 +4621,8 @@ S2.define('select2/dropdown/minimumResultsForSearch',[ }); S2.define('select2/dropdown/selectOnClose',[ - -], function () { + '../utils' +], function (Utils) { function SelectOnClose () { } SelectOnClose.prototype.bind = function (decorated, container, $container) { @@ -4407,7 +4653,7 @@ S2.define('select2/dropdown/selectOnClose',[ return; } - var data = $highlightedResults.data('data'); + var data = Utils.GetData($highlightedResults[0], 'data'); // Don't re-select already selected resulte if ( @@ -4448,7 +4694,7 @@ S2.define('select2/dropdown/closeOnSelect',[ var originalEvent = evt.originalEvent; // Don't close if the control key is being held - if (originalEvent && originalEvent.ctrlKey) { + if (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey)) { return; } @@ -4502,6 +4748,9 @@ S2.define('select2/i18n/en',[],function () { }, searching: function () { return 'Searching…'; + }, + removeAllItems: function () { + return 'Remove all items'; } }; }); @@ -4740,66 +4989,29 @@ S2.define('select2/defaults',[ ); } - if (typeof options.language === 'string') { - // Check if the language is specified with a region - if (options.language.indexOf('-') > 0) { - // Extract the region information if it is included - var languageParts = options.language.split('-'); - var baseLanguage = languageParts[0]; - - options.language = [options.language, baseLanguage]; - } else { - options.language = [options.language]; - } - } + // If the defaults were not previously applied from an element, it is + // possible for the language option to have not been resolved + options.language = this._resolveLanguage(options.language); - if ($.isArray(options.language)) { - var languages = new Translation(); - options.language.push('en'); + // Always fall back to English since it will always be complete + options.language.push('en'); - var languageNames = options.language; - - for (var l = 0; l < languageNames.length; l++) { - var name = languageNames[l]; - var language = {}; - - try { - // Try to load it with the original name - language = Translation.loadPath(name); - } catch (e) { - try { - // If we couldn't load it, check if it wasn't the full path - name = this.defaults.amdLanguageBase + name; - language = Translation.loadPath(name); - } catch (ex) { - // The translation could not be loaded at all. Sometimes this is - // because of a configuration problem, other times this can be - // because of how Select2 helps load all possible translation files. - if (options.debug && window.console && console.warn) { - console.warn( - 'Select2: The language file for "' + name + '" could not be ' + - 'automatically loaded. A fallback will be used instead.' - ); - } + var uniqueLanguages = []; - continue; - } - } + for (var l = 0; l < options.language.length; l++) { + var language = options.language[l]; - languages.extend(language); + if (uniqueLanguages.indexOf(language) === -1) { + uniqueLanguages.push(language); } + } - options.translations = languages; - } else { - var baseTranslation = Translation.loadPath( - this.defaults.amdLanguageBase + 'en' - ); - var customTranslation = new Translation(options.language); - - customTranslation.extend(baseTranslation); + options.language = uniqueLanguages; - options.translations = customTranslation; - } + options.translations = this._processTranslations( + options.language, + options.debug + ); return options; }; @@ -4866,13 +5078,14 @@ S2.define('select2/defaults',[ debug: false, dropdownAutoWidth: false, escapeMarkup: Utils.escapeMarkup, - language: EnglishTranslation, + language: {}, matcher: matcher, minimumInputLength: 0, maximumInputLength: 0, maximumSelectionLength: 0, minimumResultsForSearch: 0, selectOnClose: false, + scrollAfterSelect: false, sorter: function (data) { return data; }, @@ -4887,6 +5100,103 @@ S2.define('select2/defaults',[ }; }; + Defaults.prototype.applyFromElement = function (options, $element) { + var optionLanguage = options.language; + var defaultLanguage = this.defaults.language; + var elementLanguage = $element.prop('lang'); + var parentLanguage = $element.closest('[lang]').prop('lang'); + + var languages = Array.prototype.concat.call( + this._resolveLanguage(elementLanguage), + this._resolveLanguage(optionLanguage), + this._resolveLanguage(defaultLanguage), + this._resolveLanguage(parentLanguage) + ); + + options.language = languages; + + return options; + }; + + Defaults.prototype._resolveLanguage = function (language) { + if (!language) { + return []; + } + + if ($.isEmptyObject(language)) { + return []; + } + + if ($.isPlainObject(language)) { + return [language]; + } + + var languages; + + if (!$.isArray(language)) { + languages = [language]; + } else { + languages = language; + } + + var resolvedLanguages = []; + + for (var l = 0; l < languages.length; l++) { + resolvedLanguages.push(languages[l]); + + if (typeof languages[l] === 'string' && languages[l].indexOf('-') > 0) { + // Extract the region information if it is included + var languageParts = languages[l].split('-'); + var baseLanguage = languageParts[0]; + + resolvedLanguages.push(baseLanguage); + } + } + + return resolvedLanguages; + }; + + Defaults.prototype._processTranslations = function (languages, debug) { + var translations = new Translation(); + + for (var l = 0; l < languages.length; l++) { + var languageData = new Translation(); + + var language = languages[l]; + + if (typeof language === 'string') { + try { + // Try to load it with the original name + languageData = Translation.loadPath(language); + } catch (e) { + try { + // If we couldn't load it, check if it wasn't the full path + language = this.defaults.amdLanguageBase + language; + languageData = Translation.loadPath(language); + } catch (ex) { + // The translation could not be loaded at all. Sometimes this is + // because of a configuration problem, other times this can be + // because of how Select2 helps load all possible translation files + if (debug && window.console && console.warn) { + console.warn( + 'Select2: The language file for "' + language + '" could ' + + 'not be automatically loaded. A fallback will be used instead.' + ); + } + } + } + } else if ($.isPlainObject(language)) { + languageData = new Translation(language); + } else { + languageData = language; + } + + translations.extend(languageData); + } + + return translations; + }; + Defaults.prototype.set = function (key, value) { var camelKey = $.camelCase(key); @@ -4895,7 +5205,7 @@ S2.define('select2/defaults',[ var convertedData = Utils._convertData(data); - $.extend(this.defaults, convertedData); + $.extend(true, this.defaults, convertedData); }; var defaults = new Defaults(); @@ -4916,6 +5226,10 @@ S2.define('select2/options',[ this.fromElement($element); } + if ($element != null) { + this.options = Defaults.applyFromElement(this.options, $element); + } + this.options = Defaults.apply(this.options); if ($element && $element.is('input')) { @@ -4939,14 +5253,6 @@ S2.define('select2/options',[ this.options.disabled = $e.prop('disabled'); } - if (this.options.language == null) { - if ($e.prop('lang')) { - this.options.language = $e.prop('lang').toLowerCase(); - } else if ($e.closest('[lang]').prop('lang')) { - this.options.language = $e.closest('[lang]').prop('lang'); - } - } - if (this.options.dir == null) { if ($e.prop('dir')) { this.options.dir = $e.prop('dir'); @@ -4960,7 +5266,7 @@ S2.define('select2/options',[ $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 ' + @@ -4969,11 +5275,11 @@ S2.define('select2/options',[ ); } - $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 ' + @@ -4982,21 +5288,45 @@ S2.define('select2/options',[ ); } - $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 = {}; + function upperCaseLetter(_, letter) { + return letter.toUpperCase(); + } + + // Pre-load all of the attributes which are prefixed with `data-` + for (var attr = 0; attr < $e[0].attributes.length; attr++) { + var attributeName = $e[0].attributes[attr].name; + var prefix = 'data-'; + + if (attributeName.substr(0, prefix.length) == prefix) { + // Get the contents of the attribute after `data-` + var dataName = attributeName.substring(prefix.length); + + // Get the data contents from the consistent source + // This is more than likely the jQuery data helper + var dataValue = Utils.GetData($e[0], dataName); + + // camelCase the attribute name to match the spec + var camelDataName = dataName.replace(/-([a-z])/g, upperCaseLetter); + + // Store the data attribute contents into the dataset since + dataset[camelDataName] = dataValue; + } + } + // 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()); - } else { - dataset = $e.data(); + dataset = $.extend(true, {}, $e[0].dataset, dataset); } - var data = $.extend(true, {}, dataset); + // Prefer our internal data cache if it exists + var data = $.extend(true, {}, Utils.GetData($e[0]), dataset); data = Utils._convertData(data); @@ -5033,8 +5363,8 @@ S2.define('select2/core',[ './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; @@ -5050,7 +5380,7 @@ S2.define('select2/core',[ // 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 @@ -5111,6 +5441,9 @@ S2.define('select2/core',[ // Synchronize any monitored attributes this._syncAttributes(); + Utils.StoreData($element[0], 'select2', this); + + // Ensure backwards compatibility with $element.data('select2'). $element.data('select2', this); }; @@ -5187,6 +5520,12 @@ S2.define('select2/core',[ return null; } + if (method == 'computedstyle') { + var computedStyle = window.getComputedStyle($element[0]); + + return computedStyle.width; + } + return method; }; @@ -5227,8 +5566,8 @@ S2.define('select2/core',[ if (observer != null) { this._observer = new observer(function (mutations) { - $.each(mutations, self._syncA); - $.each(mutations, self._syncS); + self._syncA(); + self._syncS(null, mutations); }); this._observer.observe(this.$element[0], { attributes: true, @@ -5350,7 +5689,7 @@ S2.define('select2/core',[ if (self.isOpen()) { if (key === KEYS.ESC || key === KEYS.TAB || (key === KEYS.UP && evt.altKey)) { - self.close(); + self.close(evt); evt.preventDefault(); } else if (key === KEYS.ENTER) { @@ -5384,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(); } @@ -5395,7 +5734,7 @@ S2.define('select2/core',[ } }; - Select2.prototype._syncSubtree = function (evt, mutations) { + Select2.prototype._isChangeMutation = function (evt, mutations) { var changed = false; var self = this; @@ -5423,7 +5762,22 @@ S2.define('select2/core',[ } } else if (mutations.removedNodes && mutations.removedNodes.length > 0) { changed = true; + } else if ($.isArray(mutations)) { + $.each(mutations, function(evt, mutation) { + if (self._isChangeMutation(evt, mutation)) { + // We've found a change mutation. + // Let's escape from the loop and continue + changed = true; + return false; + } + }); } + return changed; + }; + + Select2.prototype._syncSubtree = function (evt, mutations) { + var changed = this._isChangeMutation(evt, mutations); + var self = this; // Only re-pull the data if we think there is a change if (changed) { @@ -5445,7 +5799,8 @@ S2.define('select2/core',[ 'open': 'opening', 'close': 'closing', 'select': 'selecting', - 'unselect': 'unselecting' + 'unselect': 'unselecting', + 'clear': 'clearing' }; if (args === undefined) { @@ -5473,7 +5828,7 @@ S2.define('select2/core',[ }; Select2.prototype.toggleDropdown = function () { - if (this.options.get('disabled')) { + if (this.isDisabled()) { return; } @@ -5489,15 +5844,40 @@ S2.define('select2/core',[ return; } + if (this.isDisabled()) { + return; + } + this.trigger('query', {}); }; - Select2.prototype.close = function () { + Select2.prototype.close = function (evt) { if (!this.isOpen()) { return; } - this.trigger('close', {}); + this.trigger('close', { originalEvent : evt }); + }; + + /** + * 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 () { @@ -5574,7 +5954,7 @@ S2.define('select2/core',[ }); } - this.$element.val(newVal).trigger('change'); + this.$element.val(newVal).trigger('input').trigger('change'); }; Select2.prototype.destroy = function () { @@ -5600,10 +5980,12 @@ S2.define('select2/core',[ 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(); @@ -5631,7 +6013,7 @@ S2.define('select2/core',[ this.$container.addClass('select2-container--' + this.options.get('theme')); - $container.data('element', this.$element); + Utils.StoreData($container[0], 'element', this.$element); return $container; }; @@ -5841,8 +6223,9 @@ S2.define('select2/compat/initSelection',[ }); S2.define('select2/compat/inputData',[ - 'jquery' -], function ($) { + 'jquery', + '../utils' +], function ($, Utils) { function InputData (decorated, $element, options) { this._currentData = []; this._valueSeparator = options.get('valueSeparator') || ','; @@ -5906,13 +6289,13 @@ S2.define('select2/compat/inputData',[ }); this.$element.val(data.id); - this.$element.trigger('change'); + this.$element.trigger('input').trigger('change'); } else { var value = this.$element.val(); value += this._valueSeparator + data.id; this.$element.val(value); - this.$element.trigger('change'); + this.$element.trigger('input').trigger('change'); } }; @@ -5935,7 +6318,7 @@ S2.define('select2/compat/inputData',[ } self.$element.val(values.join(self._valueSeparator)); - self.$element.trigger('change'); + self.$element.trigger('input').trigger('change'); }); }; @@ -5959,7 +6342,7 @@ S2.define('select2/compat/inputData',[ InputData.prototype.addOptions = function (_, $options) { var options = $.map($options, function ($option) { - return $.data($option[0], 'data'); + return Utils.GetData($option[0], 'data'); }); this._currentData.push.apply(this._currentData, options); @@ -6362,8 +6745,9 @@ S2.define('jquery.select2',[ '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']; @@ -6384,7 +6768,7 @@ S2.define('jquery.select2',[ 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( |
